2009-09-28
GAE + JRuby + Sinatra + Ruby Twitter GemでTwitterのBotを作成する
どうやらTwitterにおけるBot作成のノウハウ?にある程度需要がありそうなので、久しぶりの更新です。ちなみに「簡単に誰にでもできる」系の記事ではありません。が、やること自体は単純です。
Twitter上でのBotに必要な要件はだいたい以下のようなものが考えられます(もちろん細かくいえばこれ以外にもあるでしょうが)
1、特定の文字列をランダムに投稿
2、自分のタイムライン、あるいはパブリックタイムライン中の特定の言葉に反応してリプライ
3、自分に対するリプライ中の特定の言葉に反応してリプライ
4、フォローしてくれた人にフォロー返し
5、リムーブした人へのリムーブ返し
個人的には、2と3を分ける必要はないかなあと思っています。というのは、自分のタイムラインには自分へのリプライも含まれているので。ただ、著名なカイジBotのように「リプライでジャンケンを挑まれたらその結果を返す」というような機能を実装する場合には、当然2と3は分けて実装する必要があります。
1〜5のどれについても、「定期的にプログラムを実行する」という仕掛けが必要になります。自宅サーバーやレンタルサーバーにインストールされているのがUnix系のOSならcronで定期実行するのが一番簡単です。が、ここでは敢えてGAE(Goole App Engine)を使っているので、定期実行にはGAEのcronjobを用います。
ちなみにここから下は、http://d.hatena.ne.jp/zentoo/20090821/1250870502 に書いてある内容を前提とします。JRuby+Sinatra+Ruby Twitter GemをGAEにアップロードする方法などは、全部同じです。
GAEのcronjobは、WEB-INF以下にcron.xmlというファイルを作って登録を行います。ちなみにJavaの場合はXMLで、Pythonの場合はYAMLみたい。
cron.xmlの書式は以下の通り。
<cronentries> <cron> <url>/cron/randompost</url> <description>URL for random_post</description> <schedule>every 7 minutes</schedule> </cron> <cron> 略 </cron> </cronentries>
このファイルをアップロードした場合、Google先生によって http://(your_app_name).appspot.com/cron/randompost が7分ごとにフェッチされることになります。cronとかrandompostの部分は何でも構わないのですが、特定のURLの下にまとめておくと後でWebフロントエンドとかを作りたくなった時に便利かもしれません。
GAE+JRuby+Sinatraを用いたBotの動作の流れを示すと、以下のようになります。
3、bot本体の特定のメソッドを起動
これだけだと分かりにくいので、阿部さんで例を示すと以下のようになります
1、Google様がhttp://abe-takakazu/hogehoge/randompost にアクセス
2、Sinatraがそれをキャッチ。URLへのgetメソッドの前には必ずbeforeブロックが実行されるので、その中で阿部さんをインスタンス化(app.rb)
before do @abe = TwitterBot.new("abe_takakazu", <censored>) end
TwitterBotのinitializeメソッドはこんな感じ(twitter_bot.rb)
def initialize(id, password) @id = id http_auth = Twitter::HTTPAuth.new(id, password) @twitter = Twitter::Base.new(http_auth) end
特定のURLにgetメソッドがかけられた場合の動作はSinatraではこういう風に書きます(app.rb)
get "/hogehoge/randompost" do @abe.random_post(0.12) "random_post successed" end
3、インスタンス化された阿部さんのrandom_postメソッドを起動(twitter_bot.rb)
def random_post(rate) return if rand > rate comments = File.readlines("tweets.conf") index = rand(comments.size) post(comments[index]) end
何気に重要なことですが、GAEには「一回のアクセスは30秒で終わらせな!」というドーラおばさんばりの制限があります。なので、インスタンス初期化メソッド(ここでのinitializeメソッド)の中では全体に共通する最小限の動作のみ行い、各メソッドに必要なリソースは各メソッドの中で用意するようにすることで30秒制限を回避します。
大体の仕組みは分かったと思うので後は自分で何とかしてください、と言いたいところですが、それではあんまりなんでオマケを。
おまけ1 cronのセキュリティ
さっき挙げたcron.xmlをアップロードしただけでは、誰でも http://(your_app_name).appspot.com/cron/randompost にアクセスできてしまいます。これはつまり誰でもあなたのbotのrandompostメソッドを起動できてしまうということなので、非常によろしくない。なのでWEB-INF以下のweb.xmlの<web-app></web-app>の間にこう追加してアップロードします。
<security-constraint> <web-resource-collection> <url-pattern>/cron/*</url-pattern> </web-resource-collection> <auth-constraint> <role-name>admin</role-name> </auth-constraint> </security-constraint>
こうすると、Googleアカウントによる認証を抜けないと当該ディレクトリ以下にはアクセスできなくなります。
おまけ2 阿部さんがホイホイを行っているメソッド(の一つ)
def auto_follow welcome = "よかったのかい?ホイホイついてきて。俺はノンケだってかまわないで食っちまう人間なんだぜ" friends = @twitter.friends @twitter.followers.each do |follower| if friends.include?(follower) == false begin @twitter.friendship_create(follower.id) post(welcome, follower.screen_name) rescue next end end end end
それでは、あなた好みのBotを作ってTwitterの海に解き放って下さい。
意味わかんねえ!死ね!って方は以下のURLをどうぞ
http://nyoro-n.appspot.com/twitter
http://pha22.net/text/twitterbot.html
http://sakuratan.biz/archives/1290
当たり前ですが、人様の作ったものに乗っかる場合は自分の好きな機能を載っけることはできません。そういうものです。
- 9 http://twitter.com/abe_takakazu
- 6 http://friendfeed.com/zentooo/5ee7d6f7/gae-jruby-sinatra-ruby-twitter-gemtwitterbot
- 5 http://twitter.com/zentooo
- 4 http://abe-takakazu.appspot.com/
- 3 http://reader.livedoor.com/reader/
- 1 http://74.125.153.132/search?q=cache:VxvhNbwo_R4J:k.hatena.ne.jp/keywordblog/右クリックメニュー+firefox+右クリックメニュー??%
- 1 http://ameblo.jp/konokono7tsuno-oiwaini/
- 1 http://b.hatena.ne.jp/entry/nyoro-n.appspot.com/twitter
- 1 http://b.hatena.ne.jp/entrylist?of=80
- 1 http://b.hatena.ne.jp/keyword/ruby?sort=eid
- 2009-09-27 soundscape out 6/59 10%
- 2009-09-27 BiBoLoG 5/95 5%