[追記] このエントリはつくった時の話で今はいろいろと変わってます。詳しくは以下のエントリでどうぞ。
Ruby の勉強の成果を出してみようと twitter bot をつくってみました。
名前のとおり、死亡フラグをセットします。
つまり、以下のようなうっかり発言をすると...
「ふらぐったー」にフラグをセットされます。
動作は以下のとおりです。
- Twitter 検索で "俺" "たら" "するんだ" という文字列を含む発言の検索結果を RSS で取得します。
- 検索結果のうち、自分自身 (@flagtter) の発言は除きます。
- さらにその中でログファイルの最終更新時刻より新しい発言である場合は "俺.*たら.*するんだ" という正規表現を含むかチェックします。*1
- 上記の条件を満たしていたら、それ以外の部分をカットしたものをテンプレートの文字列 *2 に埋め込み、post します。
以上の処理を 5 分周期で cron に実行させています。*3
今のところ、条件にマッチする発言が 1 件/日くらい出現してしかないので気にしていませんが、短時間に条件にマッチする発言が複数、投稿された場合には取りこぼす可能性が大いにあります。
また、cron を動かしているサーバに負荷をかけてしまっているせいかどうかはわかりませんが 10% くらいの確率で ruby スクリプトの実行中に abort してしまうので、その時は bot 動作に失敗します。
更新頻度は低いと思われるので、かなり面白くないと思いますが、気が向いた方はフォローをどうぞ。
忘れてましたけど、以下にコードも晒しておきます。
- Timeout がよくわからなかったので適当。
- 文字列を UTF-8 にしたら、-Ku をつけないと動かなかったのは教訓。
[追記] id:rairairou のリクエストで自動 follow 機能を入れてみました。 *4
#!/usr/pkg/bin/ruby -Ku require 'net/http' require 'rexml/document' require 'time' require 'timeout' FILE = ENV["HOME"] + "/var/log/flagtter.log" USERNAME = "flagtter" PASSWORD = "********" Net::HTTP.version_1_2 log = File.open(FILE, "a") result = "" # 検索結果の RSS を入手 begin timeout(60) { result = Net::HTTP.get("twitter.1x1.jp", "/rss/search/?keyword=俺+たら+するんだ&text=1") } rescue # RSS が入手できなかったら終了 log.close exit(0) rescue TimeoutError # RSS が入手できなかったら終了 log.close exit(0) end # RSS から文字列を抽出 → 投稿 rexml = REXML::Document.new(result) rexml.elements.each("//rss/channel/item") { |item| name = item.elements["title"].text.gsub(/ <.*>/, "") if ((name <=> "@flagtter") != 0) time = Time.rfc822(item.elements["pubDate"].text) if (log.mtime < time) text = item.elements["description"].text if (text.match(/俺.*たら.*するんだ/)) text.gsub!(/.*俺/, "俺").gsub!(/するんだ.*/, "するんだ") status = "『#{text}』とつぶやいた #{name} にフラグがセットされました。" # 投稿 begin timeout(60) { request1 = Net::HTTP::Post.new('/statuses/update.json') request1.basic_auth(USERNAME, PASSWORD) request1.body = "status=" + status Net::HTTP.start("twitter.com", 80) { |http| response = http.request(request1) } # 発言者をフォロー # 投稿に成功した場合だけフォローするようにする request2 = Net::HTTP::Post.new("/friendships/create/#{name[1..-1]}.json") request2.basic_auth(USERNAME, PASSWORD) Net::HTTP.start("twitter.com", 80) { |http| response = http.request(request2) } } rescue # ignore rescue Timeout::Error # ignore end log.puts "#{time} - #{status}" # 失敗してもログには追記 end break # 1 回につき 1 投稿のみ end end } log.flush log.close