今日のCPANモジュール
use WWW::Mechanize;
WWW::Mechanize を使うと、人間がブラウザですること (URL を開き、リンクをたどり、ID・Pass を入力、ログインボタンを押す…) を Perl にエミュレートさせることができます。略称 Mech(メック)。あまりに簡単・便利なのでなにかと悪用されることも多いモジュールです(うそです)。
Perl での HTTP 通信まわりは、LWP (libwww-perl) ファミリーが担当しており、ウェブの HTTP リクエストは LWP::UserAgent モジュールを使って操作します。
Mech はその LWP::UserAgent の高度なラッパーモジュールです。LWP::UserAgent の 全機能に加え、cookie の処理やヒストリ(戻るボタンに相当)、HTMLを人が見るように扱えるよう解析、といった処理を自動で行なってくれる賢いモジュールです。素で LWP::UserAgent を使ってやることもできますがかなりめんどうです。
しかも使い方は簡単で、
use WWW::Mechanize;
my $mech = new WWW::Mechanize( autocheck => 1 );
と、インスタンスを作成した後、
$mech->get("http://www.google.co.jp/");
$mech->submit_form(...
$mech->get(...
というように、Mech のメソッドを並べブラウジングをエミュレートしていきます。
(なお、new に渡した autocheck => 1 は、リクエストに失敗した時そこで die するという意味です。autocheck しない場合は $mech->success などで手動でチェックする必要があります)
Mech のメソッドはいろいろありますが、基本的に以下の3つのメソッドだけで、行きたいページまでたどれるはずです。
get()
引数で指定したURLを開きます。$mech->get('http://www.google.co.jp/blogsearch?hl=ja&q=link:e8y.net&scoring=d');follow_link()
今いるページ内で、引数で指定した条件のリンクを探し、クリック(移動)します。指定できる条件にはurl - そのリンクのURL。a タグなら href の値 url_abs - 絶対パスにしたもの。http://e8y.net/index.html にある <a href="/blog/" は http://e8y.net/blog/ となる。 text - そのリンクのタグの innerHTML name - name 属性の値 tag - タグ名。a や frame、iframe のように小文字で来ます例えば、
$mech->follow_link(text => "もっと読む");で、「もっと読む」というリンクを探しクリックしたように遷移します。
それぞれの条件名の後に
_regexをつけると、正規表現で指定できます。あと、n =>でその何番目、というのを指定できます(指定しない場合は、最初に見つかったリンクに飛びます)。これらは、好きに組み合わせることができます。$mech->follow_link( text_regex => qr/^全てを見る/, url_abs_regex => qr{^http://mixi.jp/}, n => 2, );これで、『テキストが「全てを見る」で始まり、mixi.jp のドメイン内のリンクで、2番目にあるもの』をクリック となります。
submit_form()
引数で指定した要領でフォームをクリックし次へ進みます。以下のように、fields =>にハッシュリファレンスの形でフォームの値を指定します。$mech->submit_form( fields => { email => 'test@example.com', password => 'p4ssw0rd', }, );follow_link と同じように、何も指定しない場合は一番最初に出てきたフォームに対して処理が行なわれます。なので、引数なしでただ
$mech->submit_form()を実行すると、ページの最初のフォームのデフォルト値そのまま送信されます。フォームが複数ある場合は
form_number =>(何番目)やform_name =>(nameの値)で明示的に指定することもできます。また、フォームの中に Submit ボタンがたくさんある場合にはbutton =>(nameの値)で指定できます。たいていはfields =>だけでよいと思います。
そして、現在の HTML の内容そのものは $mech->content で取得できます。
EXAMPLES
Mixiにログインし、足あとページを取得
my $mech = new WWW::Mechanize( autocheck => 1 );
# トップにアクセスし、
$mech->get('http://mixi.jp/');
# ログイン。
$mech->submit_form(
fields => {
email => 'your-email@example.com',
password => 'p4ssw0rd',
},
);
$mech->get('http://mixi.jp/home.pl');
# 足あとページに遷移
$mech->get('http://mixi.jp/show_log.pl');
print $mech->content;
ちなみに Mixi 用は WWW::Mixi という専用モジュールもあります。Plagger にもプラグインがあります。Plagger については、またいずれ。。.
定時打刻
もっと黒い使い方だと、Desknet's のようなウェブアプリで出退勤管理している会社の場合..
my $mech = new WWW::Mechanize( autocheck => 1 );
# ここでは NEOJAPAN 社のデモサイトを使わせてもらいます。
$mech->get('http://www.desknets.com/standard/product/demo/');
$mech->follow_link(url_regex => qr{/cgi-bin/demo/dnet/dnet.cgi});
# ログインし...
$mech->submit_form(
fields => {
uid => 2, # 山田太郎
_word => '',
save => 1,
},
);
# 出勤!
$mech->submit_form(
button => 's_go',
);
これを cron にしこめば。。。あ、ぼくはやってるわけじゃありません。あくまで例です! 笑
実際にやったお遊びな例では、
出前館でピザを取る
このファイルを参照。出前館というサイトにログイン → 適当なピザを選択 → 注文までを実行しています。こんなこともできますよ、という例として。
あとこの時は、HTTP::Recorder というモジュールを使い、ブラウザの操作を自動で Mech スクリプトとして記録させる、という面白いこともやっています。当時のエントリの下のほうに書いていますので、興味のある方はご覧ください。
JavaScript
さて、遊びだけではなく、ウェブアプリケーションのテストモジュールといったまじめな用途にも向いてます。これは、Test::WWW::Mechanize としてテストモジュール化されています。
ただ、Mech は賢いのですが JavaScript の動作はエミュレートしません。なので、Ajax 部分などクライアント側のテストには向いていません。
クライアント側の挙動のテストを行なうには、実際のブラウザのエンジンを使うのが一番でしょう。これは、Selenium というウェブアプリテストスイートがあります。
Selenium コアは JavaScript によるアプリですが、ドメインをまたげない制限を回避するソリューションとして、プロキシサーバーとして動作する Selenium RC という Java アプリも用意されています。そのプロキシサーバーに対しては各種プログラミング言語から直接テストをたたく API が用意されていますが、Perl 用も WWW::Selenium として CPAN にあります。
Mech については、文字コードまわりやファイルのダウンロード&保存など、まだ話は尽きませんが、関連モジュールを扱うときなどにまた取り上げようと思います。
SEE ALSO
WWW::Mechanize, WWW::Mechanize 和訳
和訳のあるモジュールについては和訳のリンクも載せることにしました。ただ、CPAN モジュールの英語はコードが間に入るのでそんなに難しくないので挑戦してみてください。Mech のドキュメントはわかりやすいお手本のような英語です。
Spidering hacks という本には、Mech を使ったサンプルが多数載っています。

WRITTEN BY
冨田 尚樹 <tomita@cpan.org>