Web::Scraperの0.15がリリースされたので、色々試してみてます。
ほんのりと変わった所を調べてみます。
UserAgentが置き換えられるようになった
uaのスコープを変えて頂けたので、先日の「
WWW::MechanizeとWeb::Scraperでtwitterのfriendsを全部取ってみる」でやった以下の様な無理やりなUA置き換えでなく
undef &Web::Scraper::__ua;
*Web::Scraper::__ua = sub {
$mech;
};
以下のようにキレイな置き換えが出来るようになります。
$Web::Scraper::UserAgent = $mech;
スコープもourになってますから、別のパッケージ作るときにも便利かもしれませんね。
ショートカットとしてRAWが使えるようになった
これはインラインのjavascriptをそのままスクレイピングするのに使えますね。
#!/usr/bin/perl
use strict;
use warnings;
use Web::Scraper;
use URI;
use YAML;
use Data::Dumper;
my $my_script = scraper {
process '//script[2]', 'code' => 'raw';
result 'code';
};
my $item = $my_script->scrape( URI->new("http://mattn.kaoriya.net") );
warn Dump $item;
この例では、はてなスターのトークン設定部が取得出来ます。
--- |-
<!--
Hatena.Star.Token = '43aa5d7954c8fc062faae4eaaa864913599c277b';
-->
※htmlというショートカットでも使えます。
相対URLから絶対URLを自前で生成しなくてもよくなった
「
お腹が空いてきたのでWeb::Scraperでモスバーガーのメニューをスクレイピング」でやったように、今までは
process '.', url => sub {URI->new_abs($_->attr('href'), $uri)->as_string;};
というコードが必要でしたが、「@」による属性参照でリンクエレメントであるようならば、自動的に絶対URLを生成してくれます。
上のようなコードも
process '.', url => '@href';
と楽になりますね。
以上が私が0.13と0.15のdiffをざーーーーと見た感じの変更点です。
おまけ
今日はこれに付け加え、一つtipsを...
Web::ScraperでCISCO RECORDSをスクレーピングより
たとえば
<li><span>1</span>Track 1</li>
というHTMLから"Track1"だけを抽出しようにも
process 'li', 'title' => 'TEXT';
だと
1Track1
なんて結果になるのでそれを回避するために
process 'li', 'title' => sub {
my $elem = shift;
$elem->find_by_tag_name('span')->delete;
return $elem->as_text;
};
なんてことをしてるのですが、もっといい方法があるはず。
treeを壊さずやるとすれば、TextNodeを参照するのがいいかと思います。
例えば、XPathのnode()を使い、番号指定で取得します。だた現状のWeb::ScraperではTextNodeはショートカットで参照出来ませんので、以下のようにstring_valueを返すように手を加えると上手く行きます。
※相対URLの修正も含んでいます。
--- cisco_scraper.pl Tue Sep 18 13:30:20 2007
+++ cisco_scraper2.pl Tue Sep 18 14:12:49 2007
@@ -14,9 +14,7 @@
$scraper{'link'} = scraper {
process 'a', 'name' => 'TEXT';
- process 'a', 'uri' => sub {
- return URI->new_abs( $_->attr('href'), $uri )->as_string;
- };
+ process 'a', 'uri' => '@href';
result qw/name uri/;
};
@@ -27,23 +25,15 @@
};
$scraper{'track'} = scraper {
- process 'li', 'title' => sub {
- my $elem = shift;
- $elem->find_by_tag_name('span')->delete;
- return $elem->as_text;
- };
- process 'li>a', 'uri' => sub {
- return URI->new_abs( $_->attr('href'), $uri )->as_string;
- };
+ process '//li/node()[4]', 'title' => sub {$_->string_value;};
+ process 'li>a', 'uri' => '@href';
result qw/title uri/;
};
$scraper{'item'} = scraper {
process 'td.de_title', 'title' => 'TEXT';
process 'td.de_artist', 'artist' => 'TEXT';
- process 'td.nm_jacket>img', 'image' => sub {
- return URI->new_abs( $_->attr('src'), $uri )->as_string;
- };
+ process 'td.nm_jacket>img', 'image' => '@src';
process 'td.de_price', 'price' => 'TEXT';
process 'td.de_label>a', 'label' => $scraper{link};
process 'td.de_genre', 'genre' => $scraper{genre};
@@ -53,12 +43,7 @@
process 'td[headers="de_sheet"]', 'sheet' => 'TEXT';
process 'td[headers="de_arrival"]', 'arrival' => 'TEXT';
process 'td[headers="de_nomber"]', 'number' => 'TEXT';
- process 'p.de_star', 'star' => sub {
- my $elem = shift;
- $elem->find_by_tag_name('span')->delete;
- return $elem->as_text;
-
- };
+ process '//p[@class="de_star"]/node()[2]', 'star' => sub {$_->string_value;};
process 'ul[id="de_sound"]>li', 'tracks[]' => $scraper{track};
result
qw/title artist image price label genre format release release country sheet arrival number star tracks/;
このTextNode参照の需要があるならショートカットでも良いと思うんですが、いまんところ無さそうですね。
追記
otsune氏より「diff -uじゃないと...」という指摘で修正。