プログラミングの話題は「yuyarinのtopcoder記」で!
僕を追いかけたい方は Twitter へ!
2008年01月17日
PHPでTwitterのBotを作ってみる
Twitterで自分のタイムラインに表示されたメッセージにキーワードを見つけたら、何か反応を投稿するボットを作ってみる。
仕様
- /homeと/repliesからメッセージを1ページ取得する。
- メッセージにキーワードがあれば対応するメッセージを投稿する。
- repliesを優先してレスする。
実装
PEAR::HTTP_Clientを使う。コードは結構な量になってるので、要所だけ書く。
class TwitterBotとして実装。
require_once "HTTP/Client.php";
タイムラインの取得
Twitterはベーシック認証のみを正式サポートしているのでPEAR::HTTP_Clientでベーシック認証を行う。
$basic = array('Authorization'=>'Basic '.base64_encode($this->username.':'.$this->password));
$client = new HTTP_Client(null, $basic);
$client->get("http://twitter.com/".$page);
$response = $client->currentResponse();
$body = mb_convert_encoding($response['body'], "UTF-8","JIS,UTF-8,SJIS,EUC-JP");
$this->usernameにはユーザ名(メアドではない)、$this->passwordにはパスワードをセット。$pageには"home"や"replies"を渡す。
$responseには取得結果が格納されていて、'code'、'headers'、'body'のキーを持っている。'body'を取得して、UTF-8にコンバートする。
スクレイピング
取得したHTMLから目的の情報だけを取り出す。取り出したい情報は
- ステータス番号 ($status_number)
- ユーザ名 ($username)
- メッセージ ($word)
- @先 ($at)
の4つ。
うまいやり方が分からなかったので、strpos()とsubstr()で目的の情報が含まれる部分を愚直に取り出した後、preg_match()で正規表現マッチングして情報を抜き出す。これをwhileループで回す*1。
$st = $ed = 0;
while(true)
{
$st = strpos($body, '<tr class="hentry"', $ed);
if($st===false) break;
$ed = strpos($body, '<td class="thumb vcard author">', $st) or error_message("strpos error.");
$line = substr($body, $st, $ed-$st);
preg_match('/<tr class="hentry" id="status_(\d+)">/', $line, $matches);
$status_number = $matches[1];
$st = strpos($body, '<strong>', $ed) or error_message("strpos error.");
$ed = strpos($body, '</strong>', $st) or error_message("strpos error.");
$line = substr($body, $st, $ed-$st);
preg_match('/<a href="http:\/\/twitter.com\/.+" title=".+">(.+)<\/a>/', $line, $matches);
$username = $matches[1];
$st = strpos($body, '<span class="entry-title entry-content">', $ed) or error_message("strpos error.");
$ed = strpos($body, '<span class="meta entry-meta">', $st) or error_message("strpos error.");
$line = substr($body, $st, $ed-$st);
$line = str_replace("\n", "", $line);
preg_match('/content">(.+)<\/span>/', $line, $matches);
$word = trim($matches[1]);
if(preg_match('/@<a href="\/(.+)">(.+)<\/a>/', $word, $matches))
{
$at = $matches[1];
}
else
{
$at = "";
}
$twitter_list[] = array("status_number"=>$status_number, "username"=>$username, "word"=>$word, "at"=>$at);
}
return array_reverse($twitter_list);
これでreturnされた配列には、昔の発言から順にメッセージが格納されている。foreach($twitter_list as $data)とでもして、$data["word"]などを参照すればよい。
これらのデータを用いてキーワードを判定したりは大丈夫だと思うので、割愛する。
メッセージを投稿
投稿するメッセージが決まったら、Twitterにポストする。
$basic = array('Authorization'=>'Basic '.base64_encode($this->username.':'.$this->password));
$client = new HTTP_Client(null, $basic);
$client->post("http://twitter.com/status/update", array("status"=>$reply_message));
これだけでOK。
他に必要な実装
チェックしたステータス番号の保存
ステータス番号はユーザに依らず、新しいメッセージほど大きくなっている。前回最後にチェックしたステータス番号以下なら処理をスキップすればよい。
定期更新
ブラウザからアクセスして使うことを想定しているので、定期的にリロードしたい。60秒に1回リロードしたければHTMLのヘッダに以下を記述する。
<meta http-equiv="Refresh" content="60">
クリック: 2回
- 18 http://twitter.com/Yuyarin
- 13 http://reader.livedoor.com/reader/
- 9 http://www.google.co.jp/search?sourceid=navclient&hl=ja&ie=UTF-8&rls=GGLG,GGLG:2006-10,GGLG:ja&q=gdi++rectf
- 8 http://www.google.co.jp/search?hl=ja&client=firefox-a&rls=com.ubuntu:ja:official&q=compiz+ubuntu+インストール&btnG=検索&lr=lang_ja
- 6 http://achikor.blog111.fc2.com/blog-entry-58.html
- 6 http://d.hatena.ne.jp/sotarok/20080121/1200889073
- 6 http://www.google.co.jp/search?sourceid=navclient&aq=t&hl=ja&ie=UTF-8&rlz=1T4GZEZ_jaJP241JP242&q=IE+キャッシュ+保存場所 vista
- 5 http://www.google.co.jp/search?hl=ja&client=firefox-a&rls=org.mozilla:ja:official&hs=Huh&q=Vista+Firefox+キャッシュ flv&btnG=検索&lr=lang_ja
- 5 http://www.google.com/search?hl=ja&lr=lang_ja&ie=UTF-8&oe=UTF-8&q=VC+GDI&num=50
- 4 http://generation1986.g.hatena.ne.jp/keyword/メンバー一覧


