HTML::TokeParserを使ってみる

いろいろと HTMLを解析することがあるけど、最近はほとんどテンプレートから
生成されたものなので、正規表現で簡単にかけることが多い。でもたまに、
手書きだったり、オーサリンツール使っていたりするサイトだと、微妙に
属性の順番が変わっていたり、スペースの数が違ってたり、スペースの位置が
違っていたりして、正規表現では完璧にマッチしていないってことがあった。


スペースの対応ぐらいは量指定子を使えばなんとかなるけど、属性の順番が
違っていたりすると面倒。そんなときに HTML::TokeParserが使える。
特定のタグを取ってきて、その属性のハッシュリファレンスを取れたり、
属性の登場の順番を保持した配列リファレンスが取れたりできます。なんで
この属性はこの値で他にはこんな属性もある、でも順番はバラバラみたいな
ときも簡単に対応できる。以下はそういう例ではないですけど、"a"タグの
href属性を取ってきて, jpgにマッチしたものを収集するというもの。

#!/usr/bin/perl
use strict;
use warnings;

use HTML::TokeParser;
use LWP::Simple;

my $url = shift @ARGV or die "usage html_tokeparser.pl url\n";
my $content = get $url;

my $parser = HTML::TokeParser->new( \$content );

die "Error constructor of HTML::TokeParser\n" unless defined $parser;

my @jpgs;
while ( my $tag = $parser->get_tag("a") ) {
    my $attr = $tag->[1];
    next unless defined $attr->{'href'};

    push @jpgs, $attr->{'href'} if $attr->{'href'} =~ m/\.jpg$/;
}

print $_, "\n" for @jpgs;

get_tagメソッドは配列リファレンスを返します。4つの要素があって、
順番に タグ名, 属性のハッシュリファレンス, 属性の配列リファレンス,
タグ全体となります。