CSS Selector in Perl とか subtech - Bulknews::Subtech - CSS selector to XPath あたりで議論していた CSS 2 Selectors to XPath コンパイラなモジュールをつくって、CPAN に HTML::Selector::XPath としてリリースしました。
使い方は naoya さんが先に書いてますが、HTML から正規表現を使うことなくスクレイプするのに便利。たとえば Mixi にログインしてマイミク最新日記と、1件目のタイトル、本文を抜き出すコードが、以下のようにかけます。
#!/usr/bin/perl use strict; use warnings; use utf8; use Encode; use HTML::Selector::XPath; use HTML::TreeBuilder::XPath; use WWW::Mechanize; binmode STDOUT, ":utf8"; my $mech = WWW::Mechanize->new; $mech->get("http://mixi.jp/"); $mech->submit_form( fields => { email => $ARGV[0], password => $ARGV[1], }, ); $mech->get("http://mixi.jp/home.pl"); $mech->get("http://mixi.jp/new_friend_diary.pl"); my @nodes = $mech->xpath(q|//a[@class="new_link" and contains(@href, "view_diary.pl?id=")]|); print map $_->dump, @nodes; my $link = URI->new( $nodes[0]->attr('href'), $mech->url ); $mech->get($link); my $author = $mech->xpath('//td[contains(@background, "http://img.mixi.jp/img/bg_w.gif")]/b/font[@color="#605048"]')->content->[0]; $author =~ s/さんの日記$//; print "Author: $author\n"; my $title = $mech->xpath('//td[@bgcolor="#FFF4E0" and @width=430]'); print "Title: ", $title->content->[0], "\n"; my $body = $mech->selector("td.h12"); print map { ref $_ ? $_->as_HTML : $_ } $body->content_list;
bgcolor とか width とかが変わったら書き直しやん!というツッコミはあると思いますが、正規表現で書くよりはかなり書きやすくなってます。ちなみに WWW::Mechanize::xpath と ::selector は use Perl の記事 に書いてあります。WWW::Mechanize のプラグインモジュール化する予定。
ruby のスクレイピングツールキット scrAPI にあるはてなダイアリーキーワードからのスクレイプ例も、
> export URL=http://d.hatena.ne.jp/keyword/%BA%B0%CC%EE%A4%A2%A4%B5%C8%FE > ~/tmp/selector.pl $URL "span.title > a:first-child" 紺野あさ美 (href=/keyword/%ba%b0%cc%ee%a4%a2%a4%b5%c8%fe?kid=800) > ~/tmp/selector.pl $URL "span.furigana" こんのあさみ (class=furigana) > ~/tmp/selector.pl $URL "ul.list-circle > li:first-child > a" アイドル (href=/keywordlist?cname=idol)
のようにできました。