ablog

不器用で落着きのない技術者のメモ

Web::Scraper の filter が便利

WWW::Mechanize と Web::Scraper を使って HTML からテキストを抽出して CSV を作成する Perl スクリプト - ablog
で scrape したのと同じようなページのテキストを scrape したいという要望があって、使いまわせるぞと思ったら。。。
ガーン!
テキストリンクじゃなくてボタンになっている。
HTMLソースを見てみると、

<input value="詳細" onclick="... ; if (...) { window.location.href='...'; } ;return false" type="button">

ということは、「window.location.href='...'」 部分から URL を抽出すればおkか。
id:otsune さんに教えて頂いた filter を使って、

my $list_scraper = scraper { process '/html/body/div/div[3]/table/tbody/tr/td/input[2]', 
	'link[]' => ['@onclick', sub {s/^.*window\.location\.href=\'(\?.+)\'.*$/$1/sg; } ]; };

としてみたらいけた。filer 便利というか Web::Scraper めちゃ便利!

#!/usr/bin/env perl
use strict;
use warnings;
use WWW::Mechanize;
use WWW::Mechanize::AutoPager;
use Web::Scraper;
use Text::CSV;
use utf8;
use Encode;

my $list_scraper = scraper { process '/html/body/div/div[3]/table/tbody/tr/td/input[2]', 
	'link[]' => ['@onclick', sub {s/^.*window\.location\.href=\'(\?.+)\'.*$/$1/sg; } ]; };
my $detail_scraper = scraper {
	process '/html/body/div/div/form/fieldset/div/span', '1' => 'TEXT';
	process '/html/body/div/div/form/fieldset/div[2]/span', '2' => 'TEXT';
	process '/html/body/div/div/form/fieldset/div[3]/span', '3' => 'TEXT';
	process '/html/body/div/div/form/fieldset/div[4]/span', '4' => 'TEXT';
	process '/html/body/div/div/form/fieldset/div[5]/span', '5' => 'TEXT';
	process '/html/body/div/div/form/fieldset/div[6]/span', '6' => 'TEXT';
	process '/html/body/div/div/form/fieldset/div[7]/span', '7' => 'TEXT';
	process '/html/body/div/div/form/fieldset/div[8]/span', '8' => 'TEXT';
	process '/html/body/div/div/form/fieldset/div[9]/span', '9' => 'TEXT';
	process '/html/body/div/div/form/fieldset/div[10]/span', '10' => 'TEXT';
	process '/html/body/div/div/form/fieldset/div[11]/span', '11' => 'TEXT';
	process '/html/body/div/div/form/fieldset/div[12]/span', '12' => 'TEXT'; };

my $mech = WWW::Mechanize->new;
my $csv = Text::CSV->new;
$mech->autopager->add_site(
	url => 'http://foo.ablog.co.jp/',
	nextLink => '//a[@title="Go to next page"]' );
$mech->get('http://foo.ablog.co.jp/foo-bar/login');
$mech->submit_form('fields', {'name', 'foo', 'password', 'foo'});   # login
$mech->get('http://foo.ablog.co.jp/foo-bar/cs/');         # move to list page
$mech->submit_form();                                               # submit search button

my @url_list;
while(){
	my $list = $list_scraper->scrape($mech->content); # scrape list page
	push @url_list, @{$list->{link}};                 # add urls to array
	$mech->get($mech->next_link);                     # move to next page
	last if ( $@ or !defined($mech->next_link) );     # quit if last page
}


open my $out_file, ">:encoding(utf8)", "list.csv" or die $!;
foreach (@url_list) {
	$mech->get("http://foo.ablog.co.jp/foo-bar/$_");            # move to detail page
	my $detail = $detail_scraper->scrape($mech->content);       # scrape detail page
	$csv->combine(@{$detail}{sort {$a <=> $b} keys %$detail});  # to csv
	print $out_file $csv->string . "\n";                        # write a line to file
}
close $out_file;

__END__