HTTP通信 (Ruby)
Rubyでスクレイピングをやりたくて、HTTP通信の方法から試行錯誤。
"net/http"を使う
最初に辿り着いた、ローレベルな実装方法。
PerlでいうところのLWP::UserAgentを使っている感じで凄く馴染み深い。
こちら*1を参考にさせて頂いて、少し手を加えた。
- GET/POST対応
- パラメータ渡せる
- 取得した文字列はバイナリ扱い(ASCII-8BIT)
Yahooのトップページを取得してみる
require 'net/http' require 'kconv' def http_request(method, uri, query_hash={}) query = query_hash.map{|k, v| "#{k}=#{v}"}.join('&') query_escaped = URI.escape(query) uri_parsed = URI.parse(URI.escape(uri)) # http = Net::HTTP.new(uri_parsed.host) case method.downcase! when 'get' return http.get(uri_parsed.path + '?' + query_escaped).body when 'post' return http.post(uri_parsed.path, query_escaped).body end end url = 'http://www.yahoo.co.jp' body = http_request('GET', url) puts body.toutf8
もっと簡潔に書く方法*2もあった。
文字コードはmetaタグのcharset属性値で判定するのが「行儀がいい」はずだが、判定した文字コードを元にUTF8に変換する適当な方法が見つけられなかったので、kconvでざっくり自動判定させた。
"open-uri"を使う
"net/http"のwrapperで、Kernel.openを拡張して直接URLがオープン出来るようになるGem。
引数がファイルパスでも開けるので注意が必要。*3
丁寧に使えばキャッシュ処理が透過的に実装できるから便利かもしれない。
- GETのみ?
- 取得した文字列はバイナリ扱い(ASCII-8BIT)
Yahooのトップページを取得してみる
require 'open-uri' require 'kconv' url = "http://www.yahoo.co.jp" body = open( URI.escape(url) ).read puts body.toutf8
リソースを取得するだけならこれが最短ぽい。
"mechanize"を使う*4
スクレイピングするなら"mechanize"が定番みたい。もの凄い高機能なGem。
- 勿論GET/POST対応
- パラメータも渡せる
- 受信したページは"nokogiri"がオブジェクト化してくれる
- ページオブジェクトは、Formに値をセットしてSubmit出来る
- ページオブジェクトは、XPathを使って解析できる
Yahooのトップからキーワード検索を行う
require 'mechanize' agent = Mechanize.new agent.user_agent_alias = 'Windows Mozilla' url = 'http://www.yahoo.co.jp' page1 = agent.get(url) form = page1.form_with(:name => 'sf1') form.field_with(:name => 'p').value = "デミオ" page2 = form.submit page2.search('//div[@class="w"]').each do |node| puts node.css('div > h3 > a').inner_text # ざっくり end
一覧ページから詳細ページURLを抽出、各ページに遷移して、その内容を解析…みたいな事がmechanizeだけで完結する。よく出来てるなあ。
Mechanizeは受信したHTMLをUTF8に変換し、以後UTF8で処理する。もしサーバ側にSJIS等でPOSTする必要がある場合はひと工夫必要、らしい。*5