[追記] 変更が多くなってきたため、wiki で情報を管理することにしました。
以下の情報は古いです。
先週末にプチブレイクした flagtter について、以前の情報が古くなっていたため、最新の情報を書いておく。
つくってからもう 8 ヶ月も経っているけど、実はあれからいろいろ変わっている。
- cron で動かしていたサーバが元々それほどスペックが高くないもので 5 分毎に実行とかしていたため、リソースを意外と食ってしまい、アカウントを ban されてしまった。そのため、今はレンタルサーバ (sakura) で動かしている。
- 使用していた http://twitter.1x1.jp/search/ があんまりきちんと動かなくなってきたため、http://pcod.no-ip.org/yats/ を利用するように変更した。RSS の中身がけっこう違っていたため、現状のようにそれなりに動くようにするにはちょっと苦労した。
- 検索条件のひとつの「するんだ」を「るんだ」や「んだ」にして、捕捉する範囲を広げようと思っていたが、「るんだ」だと何故かマッチする発言がないと言われていた、「んだ」だと全然違うのも拾ってしまう、という理由から結局「するんだ」に落ち着いていたが、最近は「るんだ」もマッチするようになっていたので「るんだ」に変更した。
とりあえず修正後のソースを晒す。
#!/usr/local/bin/ruby -Ku # -*- coding: utf-8 -*- 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("pcod.no-ip.org", "/yats/search?query=俺+たら+るんだ&lang=ja&rss") } rescue # RSS が入手できなかったら終了 log.close exit(0) rescue TimeoutError # RSS が入手できなかったら終了 log.close exit(0) end # RSS から文字列を抽出 → 投稿 rexml = REXML::Document.new(result) rexml.elements.each("//feed/entry") { |item| name = item.elements["title"].text if ((name <=> "flagtter") != 0) time = Time.parse(item.elements["updated"].text.gsub(/T/, " ").gsub(/Z/, "")) if ((log.mtime - 9 * 60 * 60) < time) text = item.elements["summary"].text if (text.match(/俺.*たら.*るんだ/)) text.gsub!(/.*俺/, "俺").gsub!(/るんだ.*/, "るんだ") status = "『#{text}』とつぶやいた @#{name} にフラグがセットされました。" # 投稿 begin timeout(120) { request1 = Net::HTTP::Post.new('/statuses/update.json') request1.basic_auth(USERNAME, PASSWORD) request1.body = "status=" + status Net::HTTP.start("twitter.com", 80) { |http| response1 = http.request(request1) } # 発言者をフォロー # 投稿に成功した場合だけフォローするようにする request2 = Net::HTTP::Post.new("/friendships/create/#{name}.json") request2.basic_auth(USERNAME, PASSWORD) Net::HTTP.start("twitter.com", 80) { |http| response2 = http.request(request2) } } rescue # ignore rescue Timeout::Error # ignore end log.puts "#{time} - #{status}" # 失敗してもログには追記 end break # 1 回につき 1 投稿のみ end end } log.flush log.close
基本的に検索時にマッチした発言の中の最新の 1 件しか対象としないため、短時間に複数あると取りこぼす。これを解決するために一度 DB に突っ込んでから、連投で ban されない程度にポストするような仕組みにするべきかなと思っている。
あと、mecab を使ったら、変則的な「俺」「たら」「るんだ」にも対応できるかなとも思っているので、調べてみようかなと思っている。