古いMechanizeスクリプトを少しモダンにする
まずは定義
- 古い
- Ruby 1.8.5 + Mechanize 0.8 + Hpricot 前提のもの
- モダン
- Ruby 1.9 + Mechanize 1.0 + Nokogiri 前提のもの
Mechanize 2.0 は新しすぎるので手を出しません。
WWW::Mechanize -> Mechanize 変更
Mechanize は 1.0 で WWW ネームスペースがなくなりました。これは機械的に置き換えます。個人的には常に以下のような subclass を用意していたので、この作業はそれほど大変ではありませんでした。
Bundler でまとめて gem のバージョンを管理
gem のバージョンを gem メソッドで指定できることを知って以降、とにかくあの面倒くさい時期の Mechanize に触れないように
gem 'mechanize', '< 0.9'
require 'mechanize'
require 'hpricot'
とかやっていたのですが、個々のファイルでこのように書いていると書き直しや gem のインストールが面倒なので Bundler でまとめてしまいます。具体的には
Gemfile
を用意して、
gem 'mechanize', '< 2'
などとします。で、
bundle install
します。
system の gem を汚さない方法
もし system wide な gem に変更を加えるのが難しい場合1は
bundle install --path vendor
のようにして、変更を加えるコードの場所に gem をインストールします。これ以降の作業は全部
bundle exec ./script
みたいな形で行います。この場合は利用する gem は基本的に全部 Gemfile に書いておく必要があるので、
gem 'rake'
などを書き足す必要があるかもしれません。
最初のネック - Hpricot と Nokogiri の encoding の扱いの違い
- Hpricot ベースの Mechanize はパース時にもページの encoding はそのままスルー
- form や link の検索時には "ラベル".tosjis などのように変換が必要
- Nokogiri ベースの Mechanize はパース時の encoding はすべて UTF-8 に統一
- UTF-8 でコードを書いている場合は form や link の検索時には何も考える必要なし ex) link_with( "ラベル" ).click
- ただしパース前の Mechanize#page は元の encoding のまま保存されている。
到達したページから何らかの情報を取得したい場合は一度手で UTF-8 に変換しないとややこしいです。特に Nokogiri に渡し直す場合は UTF-8 への変換が必須になります。
Hpricot から Nokogiri に切り替える
- 何はともあれ全部 UTF-8 化する
# -*- coding: utf-8 -*-
$KCODE='u' unless defined? ::Encoding
を付けて回りましょう。もちろん関連ファイルは全部 UTF-8 に統一します。もうさすがに ja_JP.eucJP な環境はない…ですよね?
- 文字コード変換をどんどん削除
link_with( :text => 'ラベル'.tosjis ).click
-> link_with( :text => 'ラベル' ).click
これで内部で UTF-8 のパース済みデータを持っている Mechanize と比較的仲良くできます。
恐らく、当初思っていたよりは面倒は起きずになんとかなると思います。
パースに失敗する場合
もっと詳しいところがあるのでどうぞ!
- RubyのMechanizeを解説 for 1.0.0 - きたももんががきたん。
- RubyのMechanizeのよくある質問 - きたももんががきたん。
- Ruby Mechanize 2.0 リリース - きたももんががきたん。
Ruby 1.9 対応
上の作業だけで Mechanize 1.0 + Nokogiri 1.5 に対応できていたら、そのまま Ruby 1.9 に対応できる可能性は比較的高いです。ぜひ rvm などから ruby のバージョンを切り替えてテストしてみることをお勧めします。
ただし、1.9 ではどうしてもうまく動かない場合もあります。(いま実際にそれでハマっているコードも手元にあります。これをどうするかは今後考えます。)
そんなことあるのかな? ↩