PHPで天気予報を求める(その2)

(1/1)
PHP で天気予報を求める」では、livedoor の WeatherHacks を用いて天気予報を表示している。ところが、この API では今日を含めて 3 日間の天気予報しか表示しない。一方、livedoor 天気情報 では、RSS 形式で 1週間分の各地の予報を配信している。
そこで今回は、この RSS を取得し、任意の都市の週間天気予報を表示するプログラムを作ってみることにする。

サンプル・プログラムの実行例

PHPで天気予報を求める(その2)

「livedoor天気情報」の天気予報情報

livedoor 天気情報は、RSS 2.0 形式で天気予報情報を配信している。
各地点の RSS の URL は「全国の地点定義表(RSS)」に示されている URL である。

サンプル・プログラム

解説:表示列数など

0027: //天気予報の表示列数
0028: define('COLUMNS', 7);

天気予報は最大 7 日分を取得できるが、横表示の日数を COLUMNS に設定している。
7 なら 1行で、ここを 4 にすると 4 日分と 3 日分の 2行表示となる。

解説:天気予報情報の取り出し

0211: /**
0212:  * livedoor天気情報RSSの description から最高・最低気温を取り出す
0213:  * @param string $descripttion  livedoor天気情報RSSの description
0214:  * @return array($max, $min) / FALSE=失敗
0215: */
0216: function getTemperature($description) {
0217:     $pat1 = '/最高気温は([0-9 \.\-]+)℃/u';
0218:     $pat2 = '/最低気温は([0-9 \.\-]+)℃/u';
0219:     $temp1 = '-';
0220:     $temp2 = '-';
0221: 
0222:     //最高気温
0223:     if (preg_match($pat1$description$arr) > 0) {
0224:         if (isset($arr[1])) $temp1 = $arr[1];
0225:     }
0226: 
0227:     //最低気温
0228:     if (preg_match($pat2$description$arr) > 0) {
0229:         if (isset($arr[1])) $temp2 = $arr[1];
0230:     }
0231: 
0232:     return array($temp1$temp2);
0233: }
0234: 
0235: /**
0236:  * 週間天気予報情報を取得する
0237:  * @param string $rss   livedoor天気情報RSSを示すURL
0238:  * @param array  $items 週間天気予報情報を格納する配列
0239:  * @return int 配列に格納した情報件数/0=失敗
0240: */
0241: function getWeeklyWeather($rss, &$items) {
0242:     //PHP4用; DOM XML利用
0243:     if (isphp5over() == FALSE) {
0244:         $dom = @read_xml($rss);
0245:         $cnt = 0;
0246:         if ($dom != FALSE) {
0247:             //DOMから必要な情報を配列へ
0248:             $node = $dom->get_elements_by_tagname('rss');
0249:             $node = $node[0]->get_elements_by_tagname('item');
0250:             foreach ($node as $node1) {
0251:                 $node2 = $node1->get_elements_by_tagname('title');
0252:                 $title = (string)$node2[0]->get_content();
0253:                 if (getMonthDay($title) != FALSE) {
0254:                     list($items[$cnt]['city'], $items[$cnt]['month'],
0255:                         $items[$cnt]['day'], $items[$cnt]['week'])
0256:                         = getMonthDay($title);
0257:                     $node2 = $node1->get_elements_by_tagname('image');
0258:                     $node3 = $node2[0]->get_elements_by_tagname('title');
0259:                     $items[$cnt]['weather'] = (string)$node3[0]->get_content();
0260:                     $node3 = $node2[0]->get_elements_by_tagname('url');
0261:                     $items[$cnt]['image'] = (string)$node3[0]->get_content();
0262:                     $node2 = $node1->get_elements_by_tagname('description');
0263:                     $description = (string)$node2[0]->get_content();
0264:                     if (getTemperature($description) != FALSE) {
0265:                         list($items[$cnt]['temp_max'], $items[$cnt]['temp_min']) = getTemperature($description);
0266:                     } else {
0267:                         $items[$cnt]['temp_max'] = '-';
0268:                         $items[$cnt]['temp_min'] = '-';
0269:                     }
0270:                     $cnt++;
0271:                 }
0272:             }
0273:         }
0274:     //PHP5用; SimpleXML利用
0275:     } else {
0276:         $node_rss = simplexml_load_file($rss);
0277:         //レスポンス・チェック
0278:         if (isset($node_rss->channel) == FALSE)  return FALSE;
0279:         //必要な情報を配列へ
0280:         $cnt = 0;
0281:         foreach ($node_rss->channel->item as $item) {
0282:             $title = (string)$item->title;
0283:             if (getMonthDay($title) != FALSE) {
0284:                 list($items[$cnt]['city'], $items[$cnt]['month'],
0285:                     $items[$cnt]['day'], $items[$cnt]['week'])
0286:                         = getMonthDay($title);
0287:                 $items[$cnt]['weather'] = (string)$item->image->title;
0288:                 $items[$cnt]['image']   = (string)$item->image->url;
0289:                 $description = (string)$item->description;
0290:                 if (getTemperature($description) != FALSE) {
0291:                     list($items[$cnt]['temp_max'], $items[$cnt]['temp_min']) = getTemperature($description);
0292:                 } else {
0293:                     $items[$cnt]['temp_max'] = '-';
0294:                     $items[$cnt]['temp_min'] = '-';
0295:                 }
0296:                 $cnt++;
0297:             }
0298:         }
0299:     }
0300:     return $cnt;
0301: }

入力処理については、「PHP で天気予報を求める」とほぼ同じである。

WebAPI の代わりに、RSS から情報を取り出すユーザー関数 getWeeklyWeather を用意した。
RSS 2.0 の仕様にしたがって、情報を配列変数に格納している。

解説:出力処理

0473: // メインプログラム ==========================================================
0474: //ForecastMap(全国地点定義表)の解釈
0475: if ($id == 0) {
0476:     $n = parseForecastMap($ForecastTable);
0477:     if ($n == 0)    $errmsg = 'ForecastMapが見つかりません.';
0478: }
0479: 
0480: //検索処理
0481: if ($city != '' && isset($ForecastTable[$pref][$city])) {
0482:     $url = getWeeklyWeatherURL($ForecastTable[$pref][$city]);
0483:     getWeeklyWeather($url$items);
0484: else if ($id != 0) {
0485:     $url = getWeeklyWeatherURL($id);
0486:     getWeeklyWeather($url$items);
0487: }
0488: 
0489: $HtmlBody1 = makeCommonBody($items$ForecastTable$pref$city$url$errmsg);
0490: $HtmlBody2 = (count($items) == 0) ? '' : makeWeeklyWeather($items, 1, 7);
0491: 
0492: //表示処理
0493: if ($id == 0) {
0494:     echo $HtmlHeader;
0495:     echo $HtmlBody1;
0496:     echo $HtmlBody2;
0497:     echo $HtmlFooter;
0498: else  {
0499:     echo mb_convert_encoding($HtmlBody2$outencINTERNAL_ENCODING);
0500: }

今回は、画面に出力するコンテンツを $HtmlHeader, $HtmlBody1, $HtmlBody2, $HtmlFooter の 4 つに分割し、必要に応じて表示するようにした。週間予報の table が含まれているのは $HtmlBody2 である。

なぜ、このようなロジックにしたかというと、コマンドラインで

WeeklyWeather.php?id=63


のように ID を指定することで、ある地点の天気予報 table のみを表示させたかったからである。つまり、このスクリプトをホームページやブログの一部として組み込むことで、今日から 1週間分の天気予報を表示するガジェットになる。

また、親となるホームページやブログの文字コードセットにあわせ、charset 変数で出力文字コードを変更できるようにした。たとえば

WeeklyWeather.php?id=6&charset=SJIS


とすると、東京の週間天気予報をシフト JIS で出力することができる。

活用例

《全国の天気》今日・明日の天気と全国概況一覧 & 週間予報」(みんなの知識 ちょっと便利帳)では、このサンプル・プログラムを活用し、都市名を検索しやすいページを提供している。
また、サイドバーにコンパクトな形で天気予報を掲示している。
ありがとうございます。

参考サイト

(この項おわり)
header