Skypeto: Skype chat to n-yoshi n-yoshi
Twitter: Follow laresjp on Twitter laresjp
feed: RSS 2.0 RSS or Atom Atom

実家への帰省と噴火通知ボット

| go BLOG Top |

2010-04-21(水) 22:47(UTC +0900) p

今週末、金曜日から日曜日にかけて実家へ帰省しておりました。
そのタイミングに合わせて(と云うつもりはなかったけど、結果的にそうなってしまった())、以前からなんとか頑張っておりました
気象庁発表のデータを引用して Twitter で最新の火山噴火状況を呟くボット @vol_jp
も完成しましたのでお知らせ。

…↑と云うエントリを先週末には上げるつもりだったのですが、 blog の再開に手間取りまして、チョイと遅れてのご紹介です orz
結果的には、その後に色々と手直しもしているので、このタイミングで正解かも?()

最終的に決めた仕様/ロジックは、次のような感じ。

  1. どうにかこうにかして、ターゲット URL の中身を取得
    具体的には「気象庁 | 噴火に関する火山観測報」を狙う
  2. 取得したリストを解析し、【爆発的噴火】した火山名と新着チェックに使える符号を抽出
  3. 抽出した符号から新着のインシデントであるかどうかを判断し、新着アリなら呟き処理へ、ナシなら終了処理へ、分岐
  4. 抽出した符号を使って組み立てられる詳細 URL を巡って、その中身を取得
  5. 詳細から取得した中身を解析し、(特に桜島対応として)年間の爆発回数や一報目、二報目の別を抽出
  6. 以上の処理で得られた諸々の情報を組み立て、それを Twitter 宛に API で呟く
  7. cron で巡回させる周期の間に複数回報が入ることがあるので、その回数分繰り返せるようにループ処理化
  8. 終了処理として、最新インシデントをログに書き出し、次回の新着チェックに使う判断子とする
  9. cron で回す周期は10min毎、発動は「毎9分」とする
  10. 詳細の URL が長いので短縮 URL にする
  11. opt: 英語で呟く別の bot も?

用いた言語は PHP で、理由は「何となく」です。
抽出(スクレイピング?)については、正規表現でサクッと、かつ、上手いこと応用できる記事を見つけたのでそちらを見ながら組み立て。
プログラムやら弄るのは久しぶりだし、 PHP 触るのも初めてだしッてコトで、ファイルの読み書きヒトツにも苦労したり…
あと、ループ処理に手こずりまして、公開後に何度も暴走させて連投被害を振りまいてしまったり orz

しかし、それ以外ではかなり楽させてもらいました。
特に、 bot として Twitter に接続する為の認証手順 OAuth や、詳細 URL を短縮させる bit.ly (j.mp) API の利用など、サンプルを頂いて取り込むだけで使えるようになるのは、素晴らしいですね!
実は、この辺が面倒そうだったのでなかなか bot を作ろうという気になれなかったんですけど、なるほど、整備済みの高速道をヒョイと利用するッてのはこんな感じなのか。

そんな感じで、参考にさせてもらったところのリストと、実際のコードを掲示しておきます。
ツッコミ所があれば、ビシビシお願いしますね。

<?php
// 日本時間に設定
date_default_timezone_set('JST');

// OAuth
// twitteroauth.phpを読み込む。パスはあなたが置いた適切な場所に変更してください
require_once("パス");

// Consumer keyの値
$consumer_key = "キー";
// Consumer secretの値
$consumer_secret = "秘密";
// Access Tokenの値
$access_token = "トークン";
// Access Token Secretの値
$access_token_secret = "秘密トークン";

// OAuthオブジェクト生成
$to = new TwitterOAuth($consumer_key,$consumer_secret,$access_token,$access_token_secret);

/*
// TwitterへPOSTする。パラメーターは配列に格納する
// in_reply_to_status_idを指定するのならば array("status"=>"@hogehoge reply","in_reply_to_status_id"=>"0000000000"); とする。
$req = $to->OAuthRequest("https://twitter.com/statuses/update.xml","POST",array("status"=>"Test OAuth update."));
 TwitterへPOSTする以外にも、TLの取得、呟きの削除などAPIをOAuth認証で行うことが出来ます。
   例えば、TLを取得するのなら
	  $req = $to->OAuthRequest("http://twitter.com/statuses/friends_timeline.xml","GET",array("count"=>"50"));
	  $req_array = simplexml_load_string($req);
	  foreach($req_array as $tweets){~}
   呟きをお気に入りに追加するのなら
	  $req = $to->OAuthRequest("https://twitter.com/favorites/create/00000000.xml","POST",array());
   ...といった感じです。詳しくはTwitterのAPI仕様書を。
*/

// bit.ly で短縮する function
//要PHP5.2.xかjson_decode関数
function short_url($sLongURL,$sApiLogin,$sApiKey){
	//see http://code.google.com/p/bitly-api/wiki/ApiDocumentation
	$sApiVersion = "2.0.1";
	$sUrl		= rawurlencode($sLongURL);
	$sFormat	 = "json";

	$sRequestURL = "http://api.j.mp/shorten?version={$sApiVersion}&longUrl={$sUrl}&login={$sApiLogin}&apiKey={$sApiKey}";
//	fPrint_r($sRequestURL);
	$jResult	 = file_get_contents($sRequestURL);
	$aResult	 = json_decode($jResult,TRUE);

	if($aResult['statusCode']=="OK"){
		$aItem = array_pop($aResult['results']);
		return $aItem['shortUrl'];
	}
	else{
		return $aResult['errorMessage'];
	}
}

/* 使い方
//短くしたいURL
  $sLongUrl = "http://maps.google.co.jp/maps?oe=UTF-8&q=%E6%97%A5%E6%9C%AC&um=1&ie=UTF-8&sa=N&hl=ja&tab=wl";
//bit.lyのログイン名
  $sLogin = "hoge";
//bit.lyのAPIキー
  $sApiKey = "R_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";

echo short_url($sLongUrl,$sLogin,$sApiKey );
 */

// 最終インシデントの読み込みとオフセット時刻への設定, rflp ReadFlagLogPointer
$rflp = fopen("最終状態保持のファイル", "r");
$ostm = fgets($rflp);
fclose($rflp);

// ターゲットURL, pfx PreFiX, TwitterFeeD
$pfx ="www.seisvol.kishou.go.jp/tokyo/STOCK/volinfo";
$url = "http://$pfx/gensho.html";
$tfd = "ボットの RSS";

// ターゲットの中身を吸い出す, ccs cContentSource, ksc KiShouChou
$ch = curl_init();
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_URL, $url);
$ksc = curl_exec($ch);
curl_close($ch);

// ターゲットの中身を吸い出す, ccs cContentSource, twt Twitter
$chtfd = curl_init();
curl_setopt($chtfd, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($chtfd, CURLOPT_CONNECTTIMEOUT, 13); // 活性確認のため、13秒待つ
curl_setopt($chtfd, CURLOPT_URL, $tfd);
$twt = curl_exec($chtfd);
curl_close($chtfd);

// エンコード変換
$ksc = mb_convert_encoding($ksc, 'UTF-8', 'SJIS');

// 情報を検索
// href='VG20100408092527.html'> 噴火に関する火山観測報(桜島爆発)(2010年04月08日09時25分発表) <
preg_match_all('/VG([0-9]{14})\.html.*火山観測報\((.*)爆発\)/', $ksc, $erpinfo, PREG_SET_ORDER);
preg_match_all('/<description>vol_jp.*VG([0-9]{14}).*<\/description>/', $twt, $twtinfo, PREG_SET_ORDER);

// Twitter の活性を確認し、動いてないようなら最終インシデントと同値にしておく
// Twitter への転記漏れを確認し、漏れがあればオフセット時刻を再設定, elst EruptLaST, tlst TwitterLaST
$elst = $erpinfo[0][1];
$tlst = $twtinfo[0][1];
if($tlst == NULL) {
	$tlst = $ostm;
}
if($elst != $tlst) {
	$ostm = $tlst;
}

// オフセット時刻までの data を取得し整形して表示, li Loopi, dtl DeTaiL
for($i = 0; $erpinfo[$i][1] > $ostm; $i++);
if($i != 0) {
	for($li = $i-1; $li>=0 ;$li--) {
		$dtltm = $erpinfo[$li][1];
		$dtlvl = $erpinfo[$li][2];
		$dtlurl = "http://$pfx/VG$dtltm.html";
			$sLogin = "ユーザ名";
			$sApiKey = "キー";
			$shrturl = short_url($dtlurl,$sLogin,$sApiKey );
		// 詳細を展開し、ポストに含める info を抽出し Twitter へポスト, erpltr LeTteR, erpcnt CouNT, erpdt DaTe
		$chdtl = curl_init();
		curl_setopt($chdtl, CURLOPT_RETURNTRANSFER, 1);
		curl_setopt($chdtl, CURLOPT_URL, $dtlurl);
		$kscdtl = curl_exec($chdtl);
		curl_close($chdtl);
		$kscdtl = mb_convert_encoding($kscdtl, 'UTF-8', 'SJIS');

		// 日  時:2010年04月08日09時19分(080019UTC)第2報
		// 今年396回目
		if(preg_match('/第([0-9]+)報/', $kscdtl, $erpltrinfo)) {
			$erpltr = " 第 $erpltrinfo[1] 報";
		} else {
			$erpltr = "";
		}
		
		if(preg_match('/今年([0-9]+)回目/', $kscdtl, $erpcntinfo)) {
			$erpcnt = " (今年 $erpcntinfo[1] 回目)";
		} else {
			$erpcnt = "";
		}
		preg_match('/(....年..月..日..時..分)/', $kscdtl, $erpdtinfo);
		$erpdt = $erpdtinfo[1];
		
		// 結果を呟いてみる
		$dtl = "$dtlvl 爆発 $erpdt$erpcnt$erpltr $shrturl";
// 		echo("$dtl<br />");
		$req = $to->OAuthRequest("https://twitter.com/statuses/update.xml","POST",array("status"=>"$dtl"));
		echo $req;
		sleep(3);
	}
}

// 最新インシデントの日時情報を取得し、フラグに書き込み, eflg ErupFLaG, wflp WriteFlagLogPointer
$eflg = $erpinfo[0][1];
$wflp = fopen("最終状態保持のファイル","w");
fputs($wflp, $eflg);
fclose($wflp);

?>

なんか冗長な処理があるとか、セキュリティ的にダメなやり方してるとか、そういう目利きはまだまだなので是非ツッコミを。

関連するかも知れない?


, Permalink, 関連つぶやき
cat: Tips(ティップス), Twitter(ツイッター), 電脳系
tag: , , ,
1 Trackbacks

トラックバック

噴火通知ボット @vol_jp 暴走の顛末 先ずは、フォロー頂いている皆様、お騒がせしまして申し訳ありませんでした… 以前ご紹介しました「日本の火山噴火状況通知ボット」 @vol_jp ですが、昨日、久しぶりに暴走させてしま…
2010-07-03(土) 10:17 (UTC +0900)

この記事のトラックバック URL


Twitter

Powered by Topsy

オススメ(殿堂)

ThinkPad Bluetooth ワイヤレス・トラックポイント・キーボード
ThinkPad Bluetooth ワイヤレス・トラックポイント・キーボード
ThinkPad
トラックポイント付きの無線キーボード

オススメ(amazon)

Twitter

オススメ(ニコ動)

オススメ(link)


検索

このblogをググる



タグクラウド


最近のエントリ

カレンダー

2017年9月
« 8月    
 12
3456789
10111213141516
17181920212223
24252627282930

分類別

保管庫


購読

marker

Firefox meter

CC LICENSE


since 2001-09-25

Powered by WordPress