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">
*1:もっと良いやり方、ライブラリ等があれば教えてください。