いまさらWeb::Scraperを使ってみました。
使うネタがなかったのがスルーし続けた一番の理由だったのですが、それではいけないと思い、CISCO RECORDSの商品情報を取得するスクリプトという、僕以外誰も興味がないスクリプトを書いてみました。
cisco_scraper.pl
#!/usr/bin/perl
use strict;
use warnings;
use Web::Scraper;
use URI;
use YAML;
use Data::Dumper;
my $uri = shift;
my %scraper;
$scraper{'link'} = scraper {
process 'a', 'name' => 'TEXT';
process 'a', 'uri' => sub {
return URI->new_abs( $_->attr('href'), $uri )->as_string;
};
result qw/name uri/;
};
$scraper{'genre'} = scraper {
process '//a[1]', 'top' => $scraper{link};
process '//a[2]', 'style' => $scraper{link};
result qw/top style/;
};
$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;
};
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.de_price', 'price' => 'TEXT';
process 'td.de_label>a', 'label' => $scraper{link};
process 'td.de_genre', 'genre' => $scraper{genre};
process 'td[headers="de_format"]', 'format' => 'TEXT';
process 'td[headers="de_release"]', 'release' => 'TEXT';
process 'td[headers="de_country"]', 'country' => 'TEXT';
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 '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/;
};
my $item = $scraper{'item'}->scrape( URI->new($uri) );
warn Dump $item;
で、ためしに、このページを解析してみると
$ ./cisco_scraper.pl http://www.cisco-records.co.jp/html/item/003/100/item355640.html
---
arrival: 2007/09/03
artist: Capsule
country: JAPAN
format: 12"EP
genre:
style:
name: POP DANCE
uri: http://www.cisco-records.co.jp/list/style.php?qGenre=4&qStyle=128
top:
name: HOUSE
uri: http://www.cisco-records.co.jp/html/genretop/genretop_4.html
image: http://www.cisco-records.co.jp/upimages/003/100/item355640p1.jpg
label:
name: Contemode
uri: http://www.cisco-records.co.jp/html/label/L348/labelL34869_0desc.html
number: 95449
price: '¥1,365'
release: 2007/09/05
sheet: 1
star: ★★★★★
title: Capsule Rmx EP
tracks:
- title: ' Sugarless Girl (Rmx Ver.) '
uri: http://www.cisco-records.co.jp/track/003/100/95449_1.ram
- title: ' CrazEEE Skyhopper (Rmx Ver.) '
uri: http://www.cisco-records.co.jp/track/003/100/95449_2.ram
こんな感じになります。
後はブックマークレットとか作れば今よりもっと簡単にレコードレビューが書けるはず。
Web::Scraper自体はとっても簡単だし、コールバックのおかげでとっても柔軟です。
・・・が、DSLというかXPathがいかんせんめんどっちー。
たとえば
<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;
};
なんてことをしてるのですが、もっといい方法があるはず。
この辺のレシピがもっともっとあったら幸せになれそうです。
追記(09/19/2007):
Big Sky :: Web::Scraper 0.15で何が変わったのか...とおまけ
string_valueを使えばスマートになるそうです。thx!
ついでに0.15からはURI->new_absしなくて@hrefで絶対URLを取得できるそうな。便利。
追記(09/19/2007):
さらにリプライ。
参考: