[PHP] デーモンとして動かせるTwitter botの作り方 | A Day In The Boy's Life

A Day In The Boy's Life

とあるエンジニアのとある1日のつぶやき。

OAuthを使ってPHPからTwitterへ投稿する 」にて、OAuth経由でTwitterへの投稿の仕方が把握できたので、Twitter用のbotを作ってみることに。

今回は、さらに以前に書いた「PHPのプログラムをデーモンとして動かしてくれるPEAR::System_Daemon 」を使うことで、cronを利用することなしにbotを常時動かせるようにしてみます。


OAuthの認証はPEARパッケージのHTTP_OAuth を、そしてPHPのプログラムをデーモンとして動かすために同じくPEARパッケージのSystem_Daemon を使って構築します。

それぞれの使い方は、上記エントリを参照してみてください。



日付を定期的に投稿するTwitter bot


今回作るbotは、とてもシンプルに1分ごとに現在の日時をTwitter上に投稿するというものです。

OAuth認証時に必要なコンシューマーキーやアクセストークンの取得方法等については、「OAuthを使ってPHPからTwitterへ投稿する 」に書いています。


<?php

require_once 'System/Daemon.php';
require_once 'HTTP/OAuth/Consumer.php';

$app_name = "tweet_daemon";

// デーモンの起動オプション
$options = array("appName"        => $app_name,
                 "authorEmail"    => "foo@example.com",
                 "appDir"         => dirname(__FILE__),
                 "appRunAsUID"    => 500,
                 "appRunAsGID"    => 500,
                 "logLocation"    => dirname(__FILE__) . "/" . $app_name . ".log",
                 "appPidLocation" => dirname(__FILE__) . "/" . $app_name . "/" . $app_name . ".pid");

System_Daemon::setOptions($options);

// デーモンの起動
System_Daemon::start();

// コンシューマーキー
$consumer_key    = 'Your Consumer Key';
$consumer_secret = 'Your Consumer Secret';

// アクセストークン
$access_token        = 'Your Access Token';
$access_token_secret = 'Your Access Token Secret';

// デーモンが生きてるかチェックしながらループ
while (!System_Daemon::isDying()) {

    try {
        $http_request = new HTTP_Request2();
        $http_request->setConfig('ssl_verify_peer', false);

        $consumer = new HTTP_OAuth_Consumer($consumer_key, $consumer_secret);
        $consumer_request = new HTTP_OAuth_Consumer_Request;

        $consumer_request->accept($http_request);
        $consumer->accept($consumer_request);

// リクエストトークンの発行を依頼
         $consumer->getRequestToken('https://twitter.com/oauth/request_token');

// リクエストトークンを取得
         $request_token = $consumer->getToken();
        $request_token_secret = $consumer->getTokenSecret();

// リクエストトークンをセット
         $consumer->setToken($request_token);
        $consumer->setTokenSecret($request_token_secret);

// 発行済みのアクセストークンをセット
         $consumer->setToken($access_token);
        $consumer->setTokenSecret($access_token_secret);

        $tweet = date('Y/m/d H:i:s');

// OAuthを利用してTwitterの投稿APIへつぶやきを投げる
         $response = $consumer->sendRequest('http://api.twitter.com/1/statuses/update.xml', array('status' => $tweet), 'POST');

// 投稿した結果を取得
         $xml = new SimpleXMLElement($response->getBody());

// 投稿失敗の場合
         if (!empty($xml->error)) {
            System_Daemon::log(System_Daemon::LOG_ERR, $xml->error);
        }

    } catch (HTTP_OAuth_Consumer_Exception_InvalidResponse $e) {
// リクエストトークンの取得が失敗した場合はログを出力し、60秒待機してからリトライ
         System_Daemon::log(System_Daemon::LOG_ERR, $e->getMessage());
        System_Daemon::iterate(60);

        continue;
    } catch (HTTP_OAuth_Exception $e) {
// Twitterへの投稿が失敗した場合はログを出力し、60秒待機してからリトライ
         System_Daemon::log(System_Daemon::LOG_ERR, $e->getMessage());
        System_Daemon::iterate(60);

        continue;
    }

// SLEEP処理(60秒待機)
    System_Daemon::iterate(60);
}

System_Daemon::stop();


基本的に、以前書いたOAuth経由でTwitterへ投稿するプログラムや、System_Daemonの使い方に書いたプログラムをベースに書いています。

60秒待機の処理(System_Daemon::iterate)が、デーモンが動くサイクルになっています。

ここを調整すれば、好きなタイミングでTwitterへ投稿処理が行われます。

ただ、接続処理による遅延などがあるので厳密に投稿が1分ごとに行われるわけではありませんが・・・。

また、エラー発生時も同様に60秒待機してからリトライの処理を行うようにしています。


エラー処理の部分だけは新たに加えていますが、try~の中でリクエストトークンの発行依頼を行い、取得できなかった場合は最初のcatchにてその例外エラー(HTTP_OAuth_Consumer_Exception_InvalidResponse)を取得するようにしています。

また、実際にTwitterへ投稿しようとした際に反応がなかったりした場合は、最後のcatchにてその例外エラー(HTTP_OAuth_Exception)を取得しています。


Twitterの過負荷(鯨さん出現)などによって、結構エラーが発生することが多いです。

例外処理が発生し、適切なエラーを捕捉てあげないとPHPは致命的なエラー(fatal error)を発行します。

(詳細は、マニュアル参照

そして、致命的なエラーが発生するとデーモンも落ちてしまいます


また、投稿結果のレスポンスを受けてのエラーハンドリングは、「OAuthを使ってPHPからTwitterへ投稿する 」の最後に書いたようなエラーメッセージのレスポンスをTwitterから受け取った場合の対処です。

まぁ、一度正常に動いてしまえばコンシューマーキーやアクセストークンが間違っていたり、投稿内容が重複したりして怒られるということは無いかと思いますがね。。。


- Twitter botからの投稿イメージ


A Day In The Boy&#39;s Life-TwitterBot投稿イメージ


2010.09.09追記

一日中、このbotを動かしてみて拾ったエラーをさらしとく。

メッセージは例外処理でHTTP_OAuthが返したエラーメッセージを拾ったものです。


Unable to connect to tcp://api.twitter.com:80. Error #0:  [l:78]

Unable to connect to ssl://twitter.com:443. Error #136080474:  [l:78]

Failed getting token and token secret from response [l:72]

User is over daily status update limit. [l:67]

しかも、結構出てる量が多い・・・。

API使い切ったのはしょうがないですけど、接続エラーが24時間で60回弱でてました。