2009年声優言及数 作業メモ(2) 所属事務所を調べたい

という無謀な試み。「所属事務所」というメタデータを付加することで、面白い傾向が見えてくるといいなーと。ただ、この業界は事務所の移り変わりが激しいからなあ・・・あまり意味はないのかもしれない。今年は何人移籍したのやら。エリたんもバオバブだしなー。

とりあえず、昔書いた変換コードをパッケージにする。
URIエスケープを含んだ文字コード変換とか色々 - XXXannex

use Exporter;
package EEncode;

use strict;
use warnings;
use Encode;
use URI::Escape;
#use Smart::Comments;

our @ISA    = qw(Exporter);
our @EXPORT = qw(convert_s2s convert_s2e convert_s2eu convert_s2E convert_s2Eu convert_e2s convert_e2e convert_e2eu convert_e2E convert_e2Eu convert_eu2s convert_eu2e convert_eu2eu convert_eu2E convert_eu2Eu);

my $ESCAPED     = 1;  # normal URI-escaped
my $ESCAPED_ALL = 2;  # all URI-escaped
my $ESCAPED_WP  = 4;  # URI-escaped without prefix '%' (must be used with $ESCAPED or $ESCAPED_ALL)
my $ENCODE_SJIS = 8;
my $ENCODE_EUC  = 16;
my $ENCODE_UTF8 = 32;

# alias
our $ES = $ENCODE_SJIS;
our $EE = $ENCODE_EUC;
our $EU = $ENCODE_UTF8;

my %ENCODER = (
  $ENCODE_SJIS => find_encoding('sjis'),
  $ENCODE_EUC  => find_encoding('euc-jp'),
  $ENCODE_UTF8 => find_encoding('utf-8'),
  );

sub ___convert{
  my ($str, $frome, $toe, $from, $to) = @_;
  my $value = $str;
  ### args : ($str, $frome, $toe, $from, $to)
  ## at first unescape characer
  if($frome & $ESCAPED_WP){
    $value =~ s/(..)/%$1/g;
  }
  if($frome & $ESCAPED){
    $value = URI::Escape::uri_unescape($value);
  }
  ## encode if "from" is specified
  if($from and $to){
    ### from encoder : $ENCODER{$from}
    ### to   encoder : $ENCODER{$to}
    Encode::_utf8_off($value);
    $value = $ENCODER{$to}->encode($ENCODER{$from}->decode($value));
    Encode::_utf8_off($value);    
  }
  ## escape again
  if($toe & $ESCAPED){
    $value = URI::Escape::uri_escape($value);
  }
  elsif($toe & $ESCAPED_ALL){
    $value = URI::Escape::uri_escape($value, '\x00-\xff');
  }
  if($toe & $ESCAPED_WP){
    $value =~ s/%//g;
  }
  return $value;
}

## wrapper function:
## s : string
## u : without prefix
## e : escaped
## E : escaped_all

sub convert_s2s   { ___convert($_[0], 0, 0,                        $_[1], $_[2]); }
sub convert_s2e   { ___convert($_[0], 0, $ESCAPED,                 $_[1], $_[2]); }
sub convert_s2eu  { ___convert($_[0], 0, $ESCAPED|$ESCAPED_WP,     $_[1], $_[2]); }
sub convert_s2E   { ___convert($_[0], 0, $ESCAPED_ALL,             $_[1], $_[2]); }
sub convert_s2Eu  { ___convert($_[0], 0, $ESCAPED_ALL|$ESCAPED_WP, $_[1], $_[2]); }

sub convert_e2s   { ___convert($_[0], $ESCAPED, 0,                        $_[1], $_[2]); }
sub convert_e2e   { ___convert($_[0], $ESCAPED, $ESCAPED,                 $_[1], $_[2]); }
sub convert_e2eu  { ___convert($_[0], $ESCAPED, $ESCAPED|$ESCAPED_WP,     $_[1], $_[2]); }
sub convert_e2E   { ___convert($_[0], $ESCAPED, $ESCAPED_ALL,             $_[1], $_[2]); }
sub convert_e2Eu  { ___convert($_[0], $ESCAPED, $ESCAPED_ALL|$ESCAPED_WP, $_[1], $_[2]); }

sub convert_eu2s   { ___convert($_[0], $ESCAPED|$ESCAPED_WP, 0,                        $_[1], $_[2]); }
sub convert_eu2e   { ___convert($_[0], $ESCAPED|$ESCAPED_WP, $ESCAPED,                 $_[1], $_[2]); }
sub convert_eu2eu  { ___convert($_[0], $ESCAPED|$ESCAPED_WP, $ESCAPED|$ESCAPED_WP,     $_[1], $_[2]); }
sub convert_eu2E   { ___convert($_[0], $ESCAPED|$ESCAPED_WP, $ESCAPED_ALL,             $_[1], $_[2]); }
sub convert_eu2Eu  { ___convert($_[0], $ESCAPED|$ESCAPED_WP, $ESCAPED_ALL|$ESCAPED_WP, $_[1], $_[2]); }

次に作業メモ(1)でリストアップした名前からWikipediaページのエントリーをとって来る。中島愛みたいに「(声優)」と付いている名前が案外多いので、ここスクリプトを若干変更。

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[]', => { 'name' => ['TEXT', sub {s/ \(.+//;} ], 'link' => '@href' };
    result 'names';
  }->scrape(new URI($_));
  $l ? map {"$_->{name}\t$_->{link}"} @$l : ();
} @$uris;

こんな感じに。んで、2カラム目を使って本文をダウンロードします。

while read name link; do
  base=`echo $link | sed -e 's/.*\///; s/_(.*//'`
  echo "wget -O ${base}.html '$link'; sleep 1"
done < sy.out > dl.sh

うーん、メチャメチャ遅い。プロセス起動のオーバーヘッドがこんなにかかるとはなあ。同じ処理をperlでやると超早い。

$ time perl -nle '@l=split(/\t/); $base=$l[1]; $base=~s/.*\///; $base=~s/_\(.*//; print "wget -O ${base}.html \"$l[1]\"; sleep 1"' sy.out > /dev/null

real    0m0.101s
user    0m0.077s
sys     0m0.000s
$ time while read name link; do base=`echo $link | sed -e 's/.*\///; s/_(.*//'`; echo "wget -O ${base}.html '$link'; sleep 1"; done < sy.out > /dev/null

real    4m26.659s
user    2m36.290s
sys     1m59.463s

まあ、それはともかくとして。

色々試行錯誤したいので、直接読み取らずに一旦ダウンロードしておきます。そして保存したhtmlファイルに対して、所属事務所っぽい物をとって来る。この辺はヒューリスティックにならざるを得ないが・・・上手い方法はあるんだろうか。
声優さんの一覧+所属事務所の情報と言うことであれば、こういうサイトも見つけた。
http://jp.jade-voice.com/actor/actress.php
割と網羅されてるっぽいけど・・・ここでもプロダクションエースは総スルーで笑った。エロゲー声優が入ってないのは仕方ないか・・・。でも、補助的には使えそう。

use strict;
use warnings;
use File::Basename;
use FindBin;
use lib "$FindBin::RealBin/../lib";
use EEncode;

my $infile = shift;
die "open [$infile] failed" unless -f $infile;

print $infile, "\t";
print convert_e2s(basename($infile, '.html')), "\t";

open my $fh, '<', $infile or die;
my @l = <$fh>;
close $fh;

#1. check profile table
for(my $i=0; $i<@l; $i++){
  if($l[$i] =~ m{<th.*(所属|事務所).*</th>}){
    my $pro = $l[++$i];
    $pro =~ s/<.*?>//g;
    print $pro;
    exit;
  }
}

#2. check text
foreach(@l){
  tr/\x0A\x0D//d;
  s/<.*?>//g;
  foreach(split(//)){
    if(/所属|事務所/){
      print "$_\t";
    }
  }
}

#3. check 18X-game
foreach(@l){
  s/<.*?>//g;
  if(/アダルトゲーム/){
    print "所属不明(エロゲー)\n";
    exit;
  }
}

#4. check net
foreach(@l){
  s/<.*?>//g;
  if(/ネット声優/){
    print "ネット声優\n";
    exit;
  }
}

print "\n";

こういう、いかにもなクイックハック感は嫌いじゃない(笑)
実行結果はこんな感じ。

%E3%80%86%E9%87%8E%E6%BD%A4%E5%AD%90.html	〆野潤子	賢プロダクション
%E3%81%82%E3%81%8A%E3%81%8D%E3%81%95%E3%82%84%E3%81%8B.html	あおきさやか	ぷろだくしょんバオバブ
%E3%81%82%E3%81%8B%E3%81%84%E3%81%A8%E3%81%BE%E3%81%A8.html	あかいとまと	C&amp;Oプロダクション
%E3%81%82%E3%81%8D%E3%82%84%E3%81%BE%E3%81%8B%E3%81%8A%E3%82%8B.html	あきやまかおる	カレイドスコープ
%E3%81%82%E3%81%8D%E3%82%84%E3%81%BE%E3%82%8B%E3%81%AA.html	あきやまるな	81プロデュース
%E3%81%82%E3%81%95%E3%82%8A%E2%98%86.html	あさり☆	所属不明(エロゲー)
%E3%81%82%E3%81%A5%E3%81%BF%E3%82%8C%E3%81%84%E3%81%8B.html	あづみれいか	
%E3%81%82%E3%82%8A%E3%81%99.html	ありす	所属不明(エロゲー)

ま、概ねおっけーな感じ?もしかしたら事務所名の表記ゆれ(ぷろだくしょんバオバブ = バオバブみたいな)があるかもしれないので、そこは注意ですね。