やっどー

Discuss Web, Social, Linux Technologies

気象庁Webページをスクレイピング

研究に利用しようと思って,アメダス情報をゲットしたかったんですね、phpで♪


天気情報をWebサービス(rss,api)で提供しているのは,
1)Yahoo!天気
2)goo
3)google
4)livedoor weather hacks
5)ひとくち予報 in Feed
とかがあるらしい.
今回はアメダスデータが欲しかったので,5)はなし.


RSSでゲットしよう♪
RSSを提供している,4)のLivedoorを使ってみたよb

http://weather.livedoor.com/amedas/point/50456.html

のデータが欲しいとーb

このRSSをゲットしようと思ったら、、

サイトのテーブルは1時間ごとに更新されるのに、RSSは6時間一度しか更新されない。
このRSSでゲットできるデータは,0・6・12・18時のいずれかでした!

6時間ごとという,大したデータが取れないので,(実地で検証www)

【実装方法】
php: simplexml(),linux:cron
simplexml()はxmlファイルを配列ぶち込んでくれる関数.
欠点があって,要素にアクセスするときパスを指定しないといけないことだね.


◆サイトのHTMLファイルからゲットしよう♪(simplexml()を使って♪)
第二の方法だよねb
HTMLファイルからゲットするんなら,もっと色々なデータを提供している気象庁http://www.jma.go.jp/jma/index.html)のサイトからゲットしようと♪

<おぉ♪簡単じゃね?前作ったプログラムでいいんじゃね?simplexml()で>

が!失敗!!
htmlはxmlじゃないんですねー!!
http://www.atmarkit.co.jp/fxml/askxmlexpert/022xhtml/22xhtml.html
使えない文字とか,色々htmlでは使われていたり。。
俗に言う,XHTMLはhtmlファイルをxmlみたいにちゃんと整形式にしたものだってb

ほうほう♪そういうことだったのか!HTMLとXMLの違いを実地で体験ww


◆HTMLファイルのスクレイピング
第三の方法だよねb
色んな方法があるみたいだけど,今回はscrape_func.phpっていうライブラリを使いました.

スクレイピングは,Webサイトから必要な情報を切り取ることだって.
やってることは,簡単にはマッチした部分を取ってくるって感じ♪


実装したもの(↓)は,ムダにループ回ってるよww
最新の一件のアメダスデータのみDBに格納してるんだけど,ループは24時間分www

そして,Linuxのcronでスケジューリング♪♪

データも1時間ごとのリアルタイムデータが取れるようになったし,満足満足♪♪

【実行結果】




【実装したもの】
/* スクレーピング関数群のインクルード */
include( "scrape_func.php" );

/* getURL()関数を使用して、ページの生データを取得する。 */
$_rawData = getURL( "http://www.jma.go.jp/jp/amedas_h/today-50456.html?groupCode=35&areaCode;=000" );

/* 生データをUTF-8に変換する。 */
//$_rawData = mb_convert_encoding($_rawData, "UTF-8", "auto");

/* 解析しやすいよう、生データを整理する。 */
$_rawData = cleanString( $_rawData );

//echo $_rawData;
/* 次は若干ややこしい。 必要な項目の開始部分と終了部分は、事前に
   HTMLから確認してある。 こういったものを利用して必要なデータを取得
   する。 */

$_rawData = getBlock( ""," ", $_rawData,false );

/* これで箇条書きに必要な特定データが入手できた。
   ここでは項目を配列化した後、繰り返しで処理を行っている。 */
$_rawData = explode( "", $_rawData );    //1時間毎に分割



//現在の時刻
$date=date( "Y-m-d H:", time() )."00:00";
//echo $date;
//cronする時刻のみのデータをとってくれば良い。

//取得するデータの時刻を求める。
$what=date( "H", time() );
//echo "what:".$what;
//if($which==1)echo "OK!";        //01 =>1
$which=(int)$what;
if($which==0)$which=24;



$conn = pg_connect("データベースの接続");
if (!$conn) {
  echo "An error occured.\n";
  fwrite($handle,"connection error!\n");
  exit;
}
pg_set_client_encoding("sjis");


//echo "
";
$now=0;            //時刻ではない
/* 繰り返しを行いながら、個々の項目を解析する。 */
foreach( $_rawData as $_rawBlock ) {
   //初期化
   //$time=null;
   $temp=null;
   $rainfall=null;
   $wind_direction=null;
   $wind_velocity=null;
   $sunlight=null;
   $moisture=null;
   $pressure=null;
  
   //now=0:$which=1        //ひとつずれてる
   if($now==($which)){
     $_rawBlock = explode( "", $_rawBlock );//8つのデータを配列に格納...余計に1つ要素が出る..
     $str="";
     $null_count=0;
     $num_element=count($_rawBlock)-1;
     //echo "count:".count($_rawBlock);
     for($j=0;$j<$num_element;$j++){
        $_rawBlock[$j]=strip_tags($_rawBlock[$j]);    //余計なタグを除去
        $_rawBlock[$j] = trim( $_rawBlock[$j] );    //空白を除去
    //echo "j:".$j."->".$_rawBlock[$j].",";
    if(!strcmp($_rawBlock[$j]," ")){        //" "=空白
       $_rawBlock[$j]=0;        //" "のとき、0を代入
       $null_count++;
    }
    if($j==0){
       //時間
       $str.="'".$date."',";
       //$time=$_rawBlock[$j];
       //if($time==24)$time=0;    //24時 => 0時
       //$str.=$time.",";
    }else if($j==1){
       //気温(℃)
       $temp=$_rawBlock[$j];
       $str.=$temp.",";
    }else if($j==2){
       //降水量(mm)
       $rainfall=$_rawBlock[$j];
       $str.=$rainfall.",";
    }else if($j==3){
       //風の向き(16方位)
       $wind_direction=$_rawBlock[$j];
       $str.="'".$wind_direction."',";
    }else if($j==4){
       //風の強さ(m/s)
       $wind_velocity=$_rawBlock[$j];
       $str.=$wind_velocity.",";
    }else if($j==5){
       //日照時間(hour)
       $sunlight=$_rawBlock[$j];
       $str.=$sunlight.",";
    }else if($j==6){
       //湿度(%)...少数表記
       $moisture=(double)$_rawBlock[$j];
       $moisture/=100;
       $str.=$moisture.",";
    }else if($j==7){
       //気圧(hPa)
       $pressure=$_rawBlock[$j];
       $str.=$pressure;
    }
     }
     if($null_count==$num_element-1){
         //echo "null!!";
     }
     //echo "=>".$str;
     //echo "
";
    
     //DBへの登録...あるデータは無視
     $sql="insert into weather(time,temp,rainfall,wind_direction,wind_velocity,sunlight,moisture,air_pressure) VALUES (".$str.");";
     //echo "sql:".$sql."
";
     $result_flag = pg_query($sql);
     if (!$result_flag) {
     //fwrite($handle,"insert error!\n");
     die('INSERT fault'.pg_last_error());
     }
     pg_close($conn);        //DB.close();
   }
   $now++;
}
?>

【参考】
http://d.hatena.ne.jp/steel-plate/20080417/1208445174