naoyaさんのエントリー「HTML::TreeBuilder + CSSセレクタがいい感じな件」を読んで「ほー、HTML::Parser使うよりスマートにスクレイピングできそうじゃのぅ」などと漠然と思ってたのですが、一念発起して実際に使ってみる事にしました。



use strict;
use URI::Fetch;
use HTML::Selector::XPath qw/selector_to_xpath/;
use HTML::TreeBuilder::XPath;
use HTML::Entities qw/decode_entities/;

my $uri='http://ragnarek.sakura.ne.jp/rep/rep396.htm';

my $res=URI::Fetch->fetch($uri)
        or die(URI::Fetch->errstr);

my $treebuilder=HTML::TreeBuilder::XPath->new;
$treebuilder->parse($res->content);
$treebuilder->eof;

my $section=$treebuilder->findnodes(selector_to_xpath('body'))->shift;

my $font_etement=HTML::Element->new('html');
$font_etement->push_content($_) for $section->look_down(_tag=>'font',size=>'3');
print $font_etement->as_text;

なんとなく分かるかもしれません…が、EDEN's Shiftの結果ファイルから、更新日を抜き出すスクリプトです。getdate.plとかいう名前で保存して実行してやると



>perl -w getdate.pl
106年10月18日

という感じで取得してきてくれます。ちなみに今使っているHTML::Parserで書いたバージョンは



use strict;
use HTML::Parser;
use LWP::UserAgent;

my $result_of_we='http://ragnarek.sakura.ne.jp/rep/rep396.htm';
my $request = HTTP::Request->new('GET',$result_of_we);
my $response = $obj_ua->request($request, './temp.htm');
my $flag_fontsize3=0;
my $date='';
sub start_1
{
my $tagname=$_[0];
my %hash_attr=%{$_[1]};

if($tagname eq 'font'
&&$hash_attr{'size'}
&&$hash_attr{'size'} eq '3')
{
$flag_fontsize3=1;
}
}

sub text_1
{
if($flag_fontsize3)
{
$date=$_[0];
}
}

sub end_1
{
my $tagname=$_[0];
if($tagname eq 'font')
{
$flag_fontsize3=0;
}
}

my $obj_parser=HTML::Parser->new(api_version => 3
,start_h => [\&start_1, "tagname, attr"]
,end_h => [\&end_1, "tagname"]
,text_h => [\&text_1, "text"]
,marked_sections => 1
,);
$obj_parser->parse_file("./temp.htm");

という感じです。うん、確かに前者のほうがスマートだ。


ただ如何せん、StrictなHTML相手でないと使いにくい面がある…ような印象があります。同じ定期更新型ネトゲでも精霊伝説の結果ファイルとかだとガシガシしやすそうな感じですね。