Wikipediaから声優名一覧を取ってくるPerlスクリプト

めも - XXXannexxpathだけ考えといてスクリプトにしていなかった。
なにやらゴチャゴチャしてしまったなあ。俺のコードはモダンなモジュールを使いこなすほど洗練されてない、というのがよく分かるな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の戻り値に空リストを返すことで要素の除去ができます」とのことなので、その辺のロジックを追加しました。