2011-08-22

古い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 の扱いの違い

  1. Hpricot ベースの Mechanize はパース時にもページの encoding はそのままスルー
    • form や link の検索時には "ラベル".tosjis などのように変換が必要
  2. 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 1.9 対応

上の作業だけで Mechanize 1.0 + Nokogiri 1.5 に対応できていたら、そのまま Ruby 1.9 に対応できる可能性は比較的高いです。ぜひ rvm などから ruby のバージョンを切り替えてテストしてみることをお勧めします。

ただし、1.9 ではどうしてもうまく動かない場合もあります。(いま実際にそれでハマっているコードも手元にあります。これをどうするかは今後考えます。)

  1. そんなことあるのかな? 

About

例によって個人のなんちゃらです