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)
のようにできました。