WWW::MechanizeでPOSTするデータを直接書くための野良拡張
先日のニコニコ動画のコメント取得スクリプトでは、WWW::Mechanizeを使用していましたが、最後にコメントを取得する部分だけはNet::HTTPクラスを直接使用していました。
comments = Net::HTTP.start(comment_host, 80) {|http| response = http.post(path, body) response.body }
というのは、WWW::MechanizeではPOSTリクエストはクエリをハッシュか配列でしか渡せないため、コメント取得のためのリクエスト文字列をボディに直接書くことができないためです。
body = %!<thread res_from="-500" version="20061206" thread="#{thread_id}" />! # こいつ
しかし、せっかくWWW::Mechanizeを使っているので最後までこのままやりたいところです。
というわけで、勝手に直接データを書けるように拡張しました。
# file: mechanize-ext.rb require 'mechanize' module WWW class Mechanize self.class_eval { def post_data(url, data='', enctype=nil) cur_page = current_page || Page.new( nil, {'content-type'=>'text/html'}) request_data = data abs_url = to_absolute_uri(url, cur_page) request = fetch_request(abs_url, :post) request.add_field('Content-Length', request_data.size.to_s) page = fetch_page(abs_url, request, cur_page, [request_data]) add_to_history(page) page end } end end
これで、
require 'mechanize-ext' agent = WWW::Mechanize.new body = '<hoge foo="bar"/>' res = agent.post_data('http://example.com/api', body)
こんなリクエストも送ることができます。(たぶん、ニコニコでしか試してないけど…)
ちなみに、レスポンスは、WWW::Mechanize::Fileのオブジェクトなので、文字列を取り出すときはres.bodyで。
リクエストフィールドをもっと加えたい場合は、request.add_fieldすればいいと思います。
追記
post_dataの引数enctypeを使っていないことに気づいた。(でも修正はしていない)