いけむランド

はてダからやってきました

ふらぐったー再掲

[追記] 変更が多くなってきたため、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 を使ったら、変則的な「俺」「たら」「るんだ」にも対応できるかなとも思っているので、調べてみようかなと思っている。