Billboardのランキングをperlで取得する

とりあえず書いてみた

Billboardのアルバムランキングを取得するモジュールを書いてみた.
どうせならと思い,threadを使ってみた.
かなり簡単だった.
それよりも,Web::Scraperって本当に便利だな.

package Music::Billboard;
use strict;
use threads;
use threads::shared;
use Carp;
use Web::Scraper;
use URI;
use YAML::Syck;

sub go {
    my @albums = (
	threads->new(\&_albums_parsePage,'Albums','1-10'),
	threads->new(\&_albums_parsePage,'Albums','11-50'),
	threads->new(\&_albums_parsePage,'Albums','51-100'),
	);
    foreach(@albums){
	$_->join;
    }
}

sub _albums_parsePage {
    my ($genre,$scope) = @_;
    my $uri = new URI(
	qq{http://www.billboard.com/bbcom/charts/chart_display.jsp?f=The+Billboard+200&pageNumber=Top+${scope}&g=${genre}}
	);
    
    my $page_scraper = scraper {
	process 'table.cbbTable_rowOn, table.cbbTable_rowOff, table.c50Table_row1, table.cbbTable_row1',
	'songs[]' => scraper {
	    process '.c50Table_text1, .cbbTable_text1',rank => 'TEXT';
	    process '.c50Table_text2, .cbbTable_text2',lastWk => 'TEXT';
	    process '.c50Table_text3, .cbbTable_text3',artist => 'TEXT';
	    process '.c50Table_text4, .cbbTable_text4',albumName => 'TEXT';
	    result 'rank','lastWk','artist','albumName';
	};
	result 'songs';
	
    };
    $page_scraper->user_agent->agent("Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)");
    my $data = $page_scraper->scrape( $uri );
    print Dump $data;
}

1;

追記:threads::sharedで苦戦

threads::sharedでhashを共有したら,なぜかうまくいかない.
ドキュメントを読み漁っているが,解決法が分からない..

my %hash :shared;
...
sub thread_task {# threadで動かすサブルーチン
     $hash{test} = &share({});
     $hash{test}->{a} = 1;
}

これじゃ,やり方がまずいのかな
と思って,配列で試してみた.

my @array :shared;
...
sub thread_task {# threadで動かすサブルーチン
     foreach(0..10){
          push @array,$_;
     }
}

これだとうまくいく.
リファレンスの扱いがだめなのかな.
まだ理解できない.

追記2:shared_clone()を使ってみた

ここを参考に,shared_clone()を使ってみた.
結果,arrayではうまくいくが,hashではうまくいかない.

とりあえずモジュールの中身を覗いてみた(参照)

# Used by shared_clone() to recursively clone
#   a complex data structure or object
$make_shared = sub {
    my ($item, $cloned) = @_;
...
    # Make copies of array, hash and scalar refs and refs of refs
    my $copy;
    my $ref_type = reftype($item);
...
    # Copy a hash ref
    elsif ($ref_type eq 'HASH') {
        # Make empty shared hash ref
        $copy = &share({});
        # Add to clone checking hash
        $cloned->{$addr} = $copy;
        # Recursively copy and add contents
        foreach my $key (keys(%{$item})) {
            $copy->{$key} = $make_shared->($item->{$key}, $cloned);
        }
    }

&share({});で初期化して,中身をディープコピーって,普通のことしかやってないよな.
やっぱやり方はあってるはず...

解決..

なんかしょうもないことをやっていた.

use YAML::Syck;
...
my %hash :shared;
...
print Dump %hash;

こうやって確認していたけど,print Dumpじゃ,hashのリファレンスは展開されないのか.
初めに確認すべきだった.

解決その2

データのDumpをするのに,今まではYAML::Syckを使っていたけど,YAML::TInyを使うようにすればいいらしい.