Hatena::Diary

スタジオズブリ RSSフィード

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 GemGAEアップロードする方法などは、全部同じです。


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の動作の流れを示すと、以下のようになります。

1、Google様がcronjobで特定のURLをフェッチ

2、URLへのgetをSinatraがキャッチ

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


当たり前ですが、人様の作ったものに乗っかる場合は自分の好きな機能を載っけることはできません。そういうものです。

スパム対策のためのダミーです。もし見えても何も入力しないでください
ゲスト


画像認証

トラックバック - http://d.hatena.ne.jp/zentoo/20090928/1254156587
おとなり日記