PerlでTwitterのBotを作ってみる
Perl なんて触ったことない人ですが、とりあえず動いたのでメモ書き。とは言え、 「作ってみる」なんてのは嘘で、ほぼコピペです。すみません m(_ _)m
基本方針
基本的にここのスクリプトを動かすことしかしてません。いようつさんありがとうございます。
さて、Twitter から呼びかけを読み込むには「API」「Web ページ」「IM」の 3 通りがあります。 API は制限がうざい、Web ページは変更の可能性がある、ということでとりあえず IM 経由。 つまり、Bot のアカウントで IM を登録しておき、そこからメッセージを取得することで スクリプト内に発言をげとしてしまう感じです。
続いて Bot が発言する方は API を利用します。こちらも IM 経由にしたり、Web ページにしても いいのかも知れませんが、Perl 歴 1 日では無理ですので、元ネタ通りにまずはいきましょう。 ちなみに、Follow 返しの方はまだいじってませんので、今回は手動で Follow して実験してます orz
というわけでおおまかな流れは以下。
- CPAN の準備
- Jabber.jp でアカウント取得
- Twitter で Bot アカウント取得&IM 設定
- Perl スクリプト動かす
うーむ、自分では 1 行もコードを書かないというダメっぷり。まぁこれからがんばります。
動作環境
- Ubuntu 7.10 サーバ版
- Perl 5.8.8
CPAN
まずは、Perl のモジュール管理 CPAN を使うところから始めます。 これは Debian でいう apt みたいなもんで、Perl の便利なモジュールが コマンド一つでインスコできる優れもの。
-
参考ページ
ここを参考に入れました。OS 入れて間もないので、make とかが無かったので とりあえず apt-get
$ sudo apt-get install make lynx gcc g++
すごい適当です。とりあえず入れたって感じ。これで準備できたので、コマンドで CPAN 起動。
$ sudo cpan
これで初期設定に入ります。基本 Enter 連打で、以下だけ変更。
Policy on building prerequisites (follow, ask or ignore)? [ask] follow
Parameters for the 'make install' command? [] UNINST=1
なぜかは知りません orz とりあえず。地域を選択すれば FTP サーバの選択になると 思いますので、適当に選択。しばらくすればプロンプトが返ってくるはず。 ちなみに、この設定は後でも変えれるみたいなので、あまり考えずサクサクやりました。
cpan>
試しにインストール。
cpan> install Jcode
これでしばらくすれば入ったはず。途中、dankogai の文字が見えました^^ 他、参考サイトに書いてあった以下のモジュールをインストールしました。
cpan> install Bundle::LWP
cpan> install Bundle::CPAN
cpan> install Crypt::SSLeay
結構時間かかるかも。あとはスクリプト動かしてみて、エラー(そんなモジュール無いよ)と 言われた時に適時インスコすればよし。
Jabber.jp
次は IM のアカウント取り。Jabber ってのがある。よくわかんないけど、自分でサーバ立てること とかも可能らしいし、GTalk が Jabber と同じプロトコルらしい。が、そこまではよく分からんので、 Jabber.jpという所が動かしているサーバを利用させてもらいます。
いいやり方はよく分かりませんが、Jabber.jpにある Pandion という IM クライアントをインスコして、サイトのチュートリアルに従ってアカウントを 作っちゃって下さい。バージョンが違うっぽくて微妙に画面が違いますが、まぁ なんとかなるでしょう。ここは省略。とりあえず、これで Jabber の情報がそろいました。
-
Jabber サーバ
- jabber.jp
-
Jabber ユーザ名(例)
- jabberuser
-
Jabber パスワード(例)
- jabberpass
続いて、Bot 用のアカウントを Twitter で取得します。これは説明不要でしょう。
-
Twitter ユーザ名(例)
- botuser
-
Twitter パスワード(例)
- botpass
そうしたら、そのアカウントで Setting を開き、IM 通知の設定をします。 プルダウンから Jabber を選択し、ユーザ名に「jabberuser@jabber.jp」と 入れれば OK。その後のページで表示される緑色の文字列を メモしておきます。
続いて、先ほどインスコした Pandion を使って、友達として Twitter を 登録します。アドレスは「twitter@twitter.com」です。そうしたら、 この人に向けて、先ほどメモした文字列を発言しましょう。これで 登録完了。Bot が Follow している人の発言(IM 通知 ON にした人のみ)が twitter@twitter.com の発言として流れてくるようになります。
スクリプト
さて、仕上げです。スクリプト自体は最初のページの方が公開されている ソースをほぼそのまま流用させてもらっています。ハックしたのは以下。
- Bot に向けた発言を抜き出す正規表現のところで、Bot のユーザ名を変数にした
- ダイスを振る部分はそっくり消去して、オウム返しするだけにした
- 日本語で発言するときに UTF-8 にエンコードするようにした
というわけで、とりあえずソースコード。
#!/usr/bin/perl -w
use strict;
use warnings;
use utf8;
use Jcode;
use Net::Jabber;
use YAML;
use Net::Twitter;
my $server = 'jabber.jp';
my $jabbername = 'jabberuser';#jabber.jpのユーザネーム
my $jabberpass = 'jabberpass';#jabber.jpのパスワード
my $resource = '';
my $twittername = 'botuser';#TwitterのBot用ユーザネーム
my $twitterpass = 'botpass';#TwitterのBot用パスワード
$SIG{HUP} = \&Stop;
$SIG{KILL} = \&Stop;
$SIG{TERM} = \&Stop;
$SIG{INT} = \&Stop;
my $Connection = new Net::Jabber::Client(
debuglevel => 1,
debugfile => "jabber.log",
);
$Connection->SetCallBacks(
message=>\&InMessage,
presence=>\&InPresence,
iq=>\&InIQ);
my $status = $Connection->Connect(
hostname=>$server
);
if (!(defined($status)))
{
print "ERROR: Jabber server is down or connection was not allowed.\n";
print " ($!)\n";
exit(0);
}
my @result = $Connection->AuthSend(
username=>$jabbername,
password=>$jabberpass,
resource=>$resource);
if ($result[0] ne "ok")
{
print "ERROR: Authorization failed: $result[0] - $result[1]\n";
exit(0);
}
print "Logged in to $server...\n";
$Connection->RosterGet();
print "Getting Roster to tell server to send presence info...\n";
$Connection->PresenceSend();
print "Sending presence to tell world that we are logged in...\n";
while(defined($Connection->Process())) { }
print "ERROR: The connection was killed...\n";
exit(0);
sub Stop
{
print "Exiting...\n";
$Connection->Disconnect();
exit(0);
}
sub InMessage
{
my $sid = shift;
my $message = shift;
my $type = $message->GetType();
my $fromJID = $message->GetFrom("jid");
my $from = $fromJID->GetUserID();
my $resource = $fromJID->GetResource();
my $subject = $message->GetSubject();
my $body = $message->GetBody();
print "===\n";
print "Message ($type)\n";
print " From: $from ($resource)\n";
print " Subject: $subject\n";
print " Body: $body\n";
# print "===\n";
# print $message->GetXML(),"\n";
print "===\n";
if ($body =~ /([^:]+):.*\@$twittername *(.*)/i) {
ProcMessage($1, $2);
}
}
sub InIQ
{
my $sid = shift;
my $iq = shift;
my $from = $iq->GetFrom();
my $type = $iq->GetType();
my $query = $iq->GetQuery();
my $xmlns = $query->GetXMLNS();
print "===\n";
print "IQ\n";
print " From $from\n";
print " Type: $type\n";
print " XMLNS: $xmlns";
# print "===\n";
# print $iq->GetXML(),"\n";
print "===\n";
}
sub InPresence
{
my $sid = shift;
my $presence = shift;
my $from = $presence->GetFrom();
my $type = $presence->GetType();
my $status = $presence->GetStatus();
print "===\n";
print "Presence\n";
print " From $from\n";
print " Type: $type\n";
print " Status: $status\n";
# print "===\n";
# print $presence->GetXML(),"\n";
print "===\n";
}
sub ProcMessage
{
my $from = shift();#差出人Twitterユーザ名
my $body = shift();#発言内容
my $twit = Net::Twitter->new(
username=>$twittername
, password=>$twitterpass
);
my $mes = '@'. "$from $body". "とか言って、バッカじゃないの!";
Jcode::convert(\$mes, 'utf8');
my $res = $twit->update($mes);
print "$mes \n";
}
細かいところはまだよく分かってないですが、まぁなんとなく分かったのでパス。 これを適当な場所において
$ perl bot.pl
で実行。おそらくモジュールが無いよというエラーが返ってくるはず。 そうしたら、その無いと言われたモジュールをシコシコインスコしましょう。
cpan> install Net::Twitter
cpan> install Web::Scraper
cpan> install Net::XMPP
cpan> install Net::Jabber
cpan> install JSON::XS
なんかこの辺を入れました。途中 Net::Plagger を入れたりして遊んでますので どれがホントにいるんだかよく分かりません orz ただ、Net::Jabber は一発で 上手く入らなくて、困っていたところ、一回 Net::XMPP を入れてから、 もう一回実行したらうまくいきました。その辺は適当にやってください。 JSON::XS は Net::Twitter で日本語がうまくいかない時に要るかもで 入れましたが、もしかしたら Jcode で変換するだけでいいのかも知れません。
何度かエラーを潜り抜けて、スクリプトを実行に成功すると、 Jabber への認証のあと、IM に Twitter がログインしていることが 表示されます。その状態で、Bot が Follow している人(hogehoge さん)から
@botuser ほげほげ
と発言すると、そのメッセージが来たことがターミナルに表示され、Bot は
@hogehoge ほげほげとか言って、バッカじゃないの!
というツンツンしたお返事を返します。ヤター!
これ以後は、Bot の挙動を自由にできます。スクリプト内の ProcMessage という ルーチンの中をいじれば如何様にも。すばらしいです、いようつさん。感謝感謝。
TODO
-
自動 Follow 返しも実験
- メールでの Follow 通知を利用する ← Gmail で専用アカウント作るか
-
発言を受けて、何かのサイトから情報を取得し返すような Bot をやってみる
- API のあるサイトや、無いサイトで HTML などから情報を取る練習も兼ねて
-
タイムラインの取得や発言を Web ページ経由で出来ないか探る
- IM や API は抜けがありそうなので、いずれ。