重要な示唆はpodに書かれている以下の一文。XPath表現とか、html、cssセレクタを使えると書いてある。
The scraper and process blocks provide a method to define what segments of a document to extract. It understands HTML and CSS Selectors as well as XPath expressions.
基本のコードひな形
Web::Scraper に渡すのは HTTP::Request にした方がいい。なぜなら、失敗の原因を 1.リクエストに対するレスポンス、2. スクレイピングなのかを切り分けるため。
#!/usr/bin/perl
use warnings;
use strict;
use Data::Dumper;
use LWP::UserAgent;
use URI;
use HTTP::Request;
use Web::Scraper;
my $ua = new LWP::UserAgent();
$ua->agent( 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.135 Safari/537.36' );
$ua->max_size(1000000);
my $uri = URI->new("http://example.com/");
my $request = HTTP::Request->new( GET => $uri );
$request->referer("http://example.com/");
my $scraper = scraper {
process 'a', 'link[]' => '@href';
};
my ($response, $result) = err_handring(
$ua
, $request
, $scraper
, 10
)
print Dumper $result;
exit;
sub err_handring {
my $ua = shift;
my $request = shift;
my $scraper = shift;
my $retry = shift;
my $response;
my $result = {};
while ( defined $@ && $retry-- > 0 ) {
$response = $ua->request($request);
# print Dumper $response;
$result = eval { $scraper->scrape($response) };
if ( !$@ ) {
last;
}
else {
warn $@;
}
}
return ($response, $result);
}
__end__;
aタグのhref属性値
cssセレクタでaタグを抽出している。
my $scraper = scraper {
process 'a', 'link[]' => '@href';
};
xpathでaタグを抽出する場合は以下。
my $scraper = scraper {
process '//a', 'link[]' => '@href';
};
aタグのhref属性値が"http:"から始まるもの
cssセレクタとxpathの区別はprocess文が受け持っていて、以下の基準でなされる。
if the first argument begins with "//" or "id(" it's treated as an xpath expression and otherwise css selector.
正規表現を使ってxpath指定することも出来るようだ。たとえば以下の例はhref属性値がhttp:から始まるaタグを抽出している。xpathって正規表現使えたのかな?
my $scraper = scraper {
process '//a[@href=~/^http:/]', 'link[]' => '@href';
};
aタグのhref属性値が"http:"から始まるもの
さらに、属性セレクタの条件を組み合わせることも出来る。以下の例はclass属性値にgbが含まれて、かつ、href属性値が/から始まるaタグを抽出している。
my $scraper = scraper {
process '//a[@class=~/gb/][@href=~/^\//]', 'link[]' => '@href';
};
aタグの親要素のタグがdivかつクラスが"main-contents"であるもの
my $scraper = scraper {
process '//div[@class="main-contents"]/a', 'link[]' => '@href';
};
抽出内容の後処理の一例
podには書かれていないが、抽出した内容の後処理が出来る。以下の例は、aタグのhref属性値を抽出して、これに含まれる/を削除している。抽出後の$resultをごにょごにょするのと同じこと。
my $scraper = scraper {
process '//a', 'link[]' => ['@href', sub {s/\///g}];
};