HTML 解析
UI 変更があって以来 API 経由だと Twitter のリアルタイム性が失われてしまったので、以前ちょこっと作っていた Twitter にログインしてホームの HTML を解析して json を起こすプログラムを手直ししてみた。
久々に触ったら hpricot の API がさっぱりになっていて焦った・・・search を押さえとけば今後はなんとかなるかな。
require 'rubygems' require 'mechanize' require 'json/lexer' class TwitterJSON # error class LoginError < StandardError ; end class OverLimitError < StandardError ; end # RETRY_MAX = 5 # constructor def initialize(user_name , password , option = {}) option[:max_history] ||= 1 @user_name = user_name @password = password @logined = false @agent = WWW::Mechanize.new @agent.max_history = option[:max_history].to_i end # get json def json login unless @logined parse end # # private methods # private def login start = Time.now puts "login ... start" if $DEBUG page = @agent.get('http://twitter.com') form = page.forms[1] form["session[username_or_email]"] = @user_name form["session[password]"] = @password page = @agent.submit(form) body = page.root.get_elements_by_tag_name("body")[0] if body && body[:class] == "account" puts "login ... end (" + (Time.now - start).to_s + ")" if $DEBUG @logined = true else raise LoginError.new end end def parse start = Time.now puts "parse ... start" if $DEBUG table = nil 0.upto(RETRY_MAX){|i| puts "request try #{i}" if $DEBUG page = @agent.get('http://twitter.com/home') table = page.root.get_element_by_id("timeline") break if table } raise OverLimitError.new until table list = [] table.search("tr.hentry"){|tr| next unless tr.elem? screen_name = $1 if tr.find_element("a")[:href] =~ /.*\/(.*)$/ name = tr.find_element("img")[:alt] img = tr.find_element("img")[:src] text = tr.find_element("span").innerHTML.strip text = text.gsub(/@<a .*?>(.*?)<\/a>/ , "@\\1") text = text.gsub(/<a href="(.*?)".*?>.*?<\/a>/ , "\\1") date = tr.at("span.published")[:title] id = tr[:id].split("_")[1] user = {"name" => name , "screen_name" => screen_name , "profile_image_url" => img} list << {"user" => user , "text" => text , "created_at" => date , "id" => id} } puts "parse ... end (" + (Time.now - start).to_s + ")" if $DEBUG list.to_json end end
次はこれを呼び出すサーバアプリ
#ruby -Ku require 'webrick' require 'rubygems' require 'kconv' require 'twitter_json' def main server = WEBrick::HTTPServer.new({ :Port => 3000, :BindAddress => '0.0.0.0', }) server.mount('/', Bookcious) ['INT', 'TERM'].each do |sig| Signal.trap(sig) { server.shutdown } end server.start end class Bookcious < WEBrick::HTTPServlet::AbstractServlet include WEBrick::HTMLUtils def do_GET(req, res) do_POST(req,res) end def do_POST(req, res) res['Content-Type'] = 'text/plain; charset=utf-8' @@twitter_json ||= TwitterJSON.new("id","password") res.body = @@twitter_json.json.toutf8 end end main
後は Twitter クライアントからサーバプログラムにアクセスするようにすれば OK。必要最低限のデータしか取ってないのは (ry
快適になったヽ(*´∀`)ノ キャッホーイ!!