Perl で CSS セレクタ
ruby でスクレイピングして web の情報を取得するのには、今まで正規表現か xpath でやってたので、わりと面倒でした。で、ふと scrAPI というスクレイピングツールキットを知ったのですが、これがかなり便利そう。
このツールキットを使うと、CSS3 なセレクタを記述することで、要素を取得することができます。
という Ruby の scrAPI での CSS セレクタがいい感じでございますなあと指をくわえて見てたんだけど、
Per discussions in CSS Selector in Perl, I made a quick perl module HTML::Selector::XPath, which is available at http://svn.bulknews.net/repos/public/HTML-Selector-XPath/trunk/ now.
と miyagawa さんがモジュールを作ってました。CSS セレクタを Xpath に変換するというもの。おお熱い。氏曰く、コードは Prototype の CSS セレクタの内部処理を Xpath に変換してやるパッチ あたりからインスパイアだそうな。これがあれば Perl で CSS セレクタでスクレイピングできる!
trunk から checkout してちょっと試してみました。
use HTML::TreeBuilder::XPath; use Smart::Comments; my $selector = HTML::Selector::XPath->new('ul.bookmarkinfo li.favorited'); my $xpath = $selector->to_xpath; ### $xpath
という感じで CSS セレクタな文字列から XPath を生成して出力すると、
### $xpath: '//ul[contains(concat(\' \', @class, \' \'), \' bookmarkinfo \')] //li[contains(concat(\' \', @class, \' \'), \' favorited \')]'
id を入力すると、その id がはてなブックマークで何件お気に入られてるかを調べるスクリプト、とかもこんな感じで簡単に書けます。
#!/usr/local/bin/perl use strict; use warnings; use URI::Fetch; use HTML::Selector::XPath; use HTML::TreeBuilder::XPath; my $id = shift or die "usage: $0 <id>"; my $res = URI::Fetch->fetch(sprintf 'http://b.hatena.ne.jp/%s/', $id) or die URI::Fetch->errstr; my $tree = HTML::TreeBuilder::XPath->new; $tree->parse($res->content); $tree->eof; my @nodes = $tree->findnodes(selector('ul.bookmarkinfo li.favorited')); printf "User '%s' is favorited from %d users\n", $id, $nodes[0]->content->[1]; sub selector { HTML::Selector::XPath->new(shift)->to_xpath; }
実行すると、
% perl favorited_count.pl jkondo User 'jkondo' is favorited from 683 users
と出る。楽チン! すばらしー。夢がひろがりんぐ。イベントドリブンで指定したシンボルに代入できるようなフレームワークでラップすれば scrAPI の完成ですな。
あと、この HTML::Selector::XPath のテストが最近話題の Test::Base を使っててイカス、というところも見逃せません。
*1:途中で改行してます