Wikipediaから声優名一覧を取ってくるPerlスクリプト
めも - XXXannexでxpathだけ考えといてスクリプトにしていなかった。
なにやらゴチャゴチャしてしまったなあ。俺のコードはモダンなモジュールを使いこなすほど洗練されてない、というのがよく分かるなw
もうちょいうまいこと書けそうな気もするのだが・・・とりあえず動くということで。
use strict; use warnings; use Web::Scraper; use URI; use URI::Escape; use Data::Dumper; use List::MoreUtils qw(uniq); my $uri = new URI('http://ja.wikipedia.org/wiki/Category:%E6%97%A5%E6%9C%AC%E3%81%AE%E5%A5%B3%E6%80%A7%E5%A3%B0%E5%84%AA'); my $uris = scraper { process '//table[@class="toc plainlinks"]/tr/td/a', 'list[]' => '@href'; result 'list'; }->scrape($uri); my @names_wiki = uniq map{ sleep 1; # to avoid DoS print STDERR "scraping $_ ... \n"; my $l =scraper { process '//div[@id="mw-pages"]//li/a', 'names[]', => 'TEXT'; result 'names'; }->scrape(new URI($_)); map{ s/ \(.+//; $_; } @$l; } @$uris; print Dumper(\@names_wiki);
s/ \(.+//;
の部分は、(声優)などと書いてある人がいるので、その対策。
追記
コメントでアドバイスいただいた通り、filterを使ってみました。
use strict; use warnings; use Web::Scraper; use URI; use List::MoreUtils qw(uniq); use Data::Dumper; my $base_uri = new URI('http://ja.wikipedia.org/wiki/Category:%E6%97%A5%E6%9C%AC%E3%81%AE%E5%A5%B3%E6%80%A7%E5%A3%B0%E5%84%AA'); my $uris = scraper { process '//table[@class="toc plainlinks"]/tr/td/a', 'list[]' => '@href'; result 'list'; }->scrape($base_uri); my @names_wiki = uniq map{ sleep 1; # to avoid DoS print STDERR "scraping $_ ... \n"; my $l = scraper { process '//div[@id="mw-pages"]//li/a', 'names[]', => ['TEXT', sub {s/ \(.+//;} ]; result 'names'; }->scrape(new URI($_)); $l ? @$l : (); } @$uris; print Dumper(\@names_wiki);
具体的にはこの辺。
process '//div[@id="mw-pages"]//li/a', 'names[]', => ['TEXT', sub {s/ \(.+//;} ];
mapを2重に使うという怪しい部分が無くなって、かなりシンプルになってしまった。・・・というか、xpathで値を取り出す以外の部分がほとんど無くなってしまった。Web::Scraperすごいっす。
ただ、修正に伴って、"Can't use an undefined value as an ARRAY reference"というエラーが出るように。
例えば http://ja.wikipedia.org/w/index.php?title=Category:%E6%97%A5%E6%9C%AC%E3%81%AE%E5%A5%B3%E6%80%A7%E5%A3%B0%E5%84%AA&from=%E3%82%92 は「を」から始まる声優名のリストがあるページなのですが、そんな頭文字の人はいないらしくscraperの返り値が空になってしまうようです。(むしろ、今まで出なかったのはなぜ?という気もしますが・・・。)
じゃあundefかどうかを判定して、undefならリストに追加しないようにすればOKでしょう。調べてみると、「mapの戻り値に空リストを返すことで要素の除去ができます」とのことなので、その辺のロジックを追加しました。