『 引用βのTwitterボットを作りました 』
2009 年 3 月 2 日橋本商会さんのスーパーボット対戦の記事が素敵な感じだったので、僕もボットを作ってみたくなりました。
といっても、マルコフ連鎖とか高度な事はできないので(大学でやってたはずなんだけどなあ・・・)
引用βへの最新投稿を表示するTwitterボットを作ってみたのです。
その名も
ってまんまやーん。
怒られないかな、ドキドキ。
引用βって大好きなんですけど、つい見逃しちゃうことが多いのです。
そこで、TwitterFox ( FireFox の拡張機能で、Twitter の新着ポストをペコッと知らせてくれる優れもの)で知らせてくれると便利じゃんと思って作りました。
普通の RSS リーダーでも十分なんですが、ちょっと思うところがありまして Twitter ボットにしてみました。
実装は php で、heteml の cron で1時間に1回引用βの RSS をチェックしに行きます。
で、前回チェックしたときよりも最新の記事があれば Twitter に投稿します。
そんな動きなのですが、なぜか数回に1回、php の XML パーサがうまく動かなくて
RSSの一番上のアイテムをスルーしてしまう様子。
そのせいでたまに過去の引用を投稿しちゃうんだけれども、
そこは愛嬌って事で御願いします(o’c_,`人)・:*:・
以下ソースコード。
いらないって?まあそういわずに。
上記バグの原因を誰か教えてくれるといいなあ、なんつって。
Twitter に投稿するクラス(Twitter.php)
<?php
//テストコード
//$twitter = new Twitter("USER_NAME", "PASSWORD");
//$twitter->post("Hello Twitter !");
/* Twitterに投稿するクラス */
class Twitter {
//-----------------------------------------
// CONSTANT
//-----------------------------------------
const API = "http://twitter.com/statuses/update.xml?";
//-----------------------------------------
// VARIABLES
//-----------------------------------------
private $username;
private $password;
//-----------------------------------------
// Constructor
// @param $username Twitterのユーザーネーム
// @param $password Twitterのパスワード
//-----------------------------------------
public function Twitter($username, $password) {
$this->username = $username;
$this->password = $password;
}
//-----------------------------------------
// 投稿する
// @param $message 投稿するメッセージ
//-----------------------------------------
public function post($message) {
$params = "status=".rawurlencode($message);
$result = file_get_contents(Twitter::API.$params, false,
stream_context_create(array(
"http" => array(
"method" => "POST",
"header" => "Authorization: Basic ". base64_encode($this->username.":".$this->password)
)
))
);
}
}
?>
引用βのRSSを取ってくるクラス(RssReader.php)
<?php
//テストコード
//$reader = new RssReader();
//$reader->load("http://feeds.feedburner.com/inyo/everyone", 5);
/* 引用βのRSSを取ってくるクラス */
class RssReader {
//-----------------------------------------
// CONSTANT
//-----------------------------------------
//-----------------------------------------
// VARIABLES
//-----------------------------------------
private $url;
private $xml;
private $max_post;
public $entries;
//-----------------------------------------
// Constructor
//-----------------------------------------
public function RssReader() {
}
//-----------------------------------------
// load feed
// @param $url RSSの場所
// @param $max_post 1回のチェックで拾ってくる最新のポスト数
//-----------------------------------------
public function load($url, $max_post=5) {
$this->url = $url;
$this->max_post = $max_post;
if ($this->xml = simplexml_load_file($this->url)) {
//取ってきたRSSを解析する
$this->parseAsRSS();
} else {
return array();
}
}
//-----------------------------------------
// RSSを解析する
//-----------------------------------------
private function parseAsRSS() {
//前回取ってきたRSSの最新記事が保存されているので読み込む
if ($fp = fopen("log.dat", "r")) {
$last = fgets($fp, 32000);
fclose($fp);
}
//エントリをザーッと取ってくる
$items = $this->xml->channel->item;
//パーマリンクのURLを2重投稿防止用のチェックに使う
$recent = (string) $items[0]->link;
$c = 0;
$this->entries = array();
foreach ($items as $item) {
//------------------------------------
// 今回解析する最大記事数を超えていないかチェック
//------------------------------------
if (++$c > $this->max_post) break;
//パーマリンクを取得する
$permalink = (string) $item->link;
//------------------------------------
// 2重投稿ではないかチェック
//------------------------------------
if (strcmp($last, $permalink) == 0) break;
//<p>タグおよびURL部分を除いて、120文字にトリムしたエントリ内容を取得する
preg_match("/(</p><p>)([^\/]+)(< \/p>)/", (string) $item->description, $tmp);
$text = mb_strimwidth(chop($tmp[2]), 0, 120, "...", "UTF-8");
//------------------------------------
// 配列に入れておく(この中のを後で投稿する)
//------------------------------------
array_push($this->entries,
array(
"text" => $text,
"permalink" => $permalink
)
);
}
//今回取得したRSSの中で、最新記事のパーマリンクを次回読み込み時用に保存しておく
if ($fp = fopen("log.dat", "w")) {
flock($fp, LOCK_EX);
fputs($fp, $recent);
flock($fp, LOCK_UN);
fclose($fp);
}
}
}
?>
上2つのクラスを使って、取得→投稿の一連の動作をしてくれるスクリプト
<?php
//-----------------------------------------
// クラスの読み込み
//-----------------------------------------
require_once("Twitter.php");
require_once("RssReader.php");
//-----------------------------------------
// それぞれのクラスのインスタンスを生成する
//-----------------------------------------
$twitter = new Twitter("inyo_beta", "********");
$reader = new RssReader();
//-----------------------------------------
// まず更新分のRSSを取得する
//-----------------------------------------
$reader->load("http://feeds.feedburner.com/inyo/everyone", 5);
//-----------------------------------------
// 更新分のRSSをTwitterに投稿する
//-----------------------------------------
if (count($reader->entries) > 0) {
//逆順にしないと、最近記事が下になる
$entries = array_reverse($reader->entries);
foreach ($entries as $entry) {
echo $entry["text"]." ".$entry["permalink"]."<br />\n";
$twitter->post($entry["text"]." ".$entry["permalink"]);
sleep(2);
}
}
//ログを吐く
echo count($entries)." entries were posted.";
?>
