はてダのはてブ内人気記事ベスト50を取ってくるperl script

http://d.hatena.ne.jp/tragedy/20080522/p1で作っているベスト50つうのは、本人も言うとおり『d.hatena.ne.jp』 の人気エントリー - はてなブックマークを成形したものだそうで。

であれば、普通にスクレイピングしてくればいいのかな、ということで。

#!/usr/bin/perl

use strict;
use Web::Scraper;
use URI;
use utf8;

# init
my $entry_body = scraper {
    process '.entry-body > a.bookmark', 'url'   => '@href';
    process '.entry-body > a.bookmark', 'title' => 'TEXT';
    process '.entry-body > a.domain'  , 'writer'  => 'TEXT';
    process '.entry-footer > strong > a' , 'users' => 'TEXT';
    result qw(url title writer users);
};
my $bookmarks = scraper {
    process 'div.entry', 'entries[]' => $entry_body;
    result "entries";
};

# scrape
my $url_string = "http://b.hatena.ne.jp/entrylist?url=http%3A%2F%2Fd.hatena.ne.jp%2F&sort=count";
my @result= ();
my $max_page = 1;
foreach my $page (0..${max_page}){
    my $of = $page*50;
    my $scraped = $bookmarks->scrape(URI->new($url_string."&of=$of"));
    push (@result,@{$scraped});
}

# output
binmode(STDOUT, ":utf8");

my $count=0;
foreach my $item (@result){
    $item->{'writer'} =~ s/^d:id://;
    $item->{'users'}  =~ s/ users$//;
    $count = count($item->{'users'});
    my @lines = (
        $count,
        $item->{'title'},
        $item->{'url'},
        "id:".$item->{'writer'},
        $item->{'users'}." users"
    );
    print join("\t",@lines),"\n";
}

exit;

{
    my ($outcount,$count,$prev_value) = (0,0,undef);
    sub count(){
        my ($value) = @_;
        $count++;
        if($prev_value != $value){
            $outcount = $count;
            $prev_value = $value;
        }
        return($outcount);
    }
}

なんてスクリプトで、タブ区切りの一覧が出力できる。

表形式で出したければ、HTML::Templateとかで、

<table><TMPL_LOOP NAME='loop'>
<tr>
  <td><TMPL_VAR NAME='count'>
  <td><a href="<!--TMPL_VAR NAME='url'-->"><TMPL_VAR NAME='title'></a></td>
  <td><a href="http://d.hatena.ne.jp/<!--TMPL_VAR NAME='writer'-->"><TMPL_VAR NAME='writer'></a></td>
  <td><a href="http://b.hatena.ne.jp/entry/<!--TMPL_VAR NAME='url'-->"><TMPL_VAR NAME='users'> users</a></td>
</tr></TMPL_LOOP></table>

こんなファイルを作って、そこにパラメータ出力してやればいい。

はてな記法スタイルで十分なら、出力部分は、print joinとかやっているところをコメントアウトして、代わりに

print <<"EOL";
|$count|[$item->{'url'}:title=$item->{'title'}]|d:id:$item->{'writer'}|[http://b.hatena.ne.jp/entry/$item->{'url'}:title=$item->{'users'} users]|
EOL

でどうだろう。

スクリプトとこのHTMLを一つのファイルに書いておいてzipで固めた奴も置いておきます。
問題は、これWeb::Scraperが使えるマシンじゃないと動かないことくらいかな。

それにしても

perlでこういうのを作るのには5分とかからないのに、ActionScript3で何か作ろうとするとドはまりする。
これ、もしかすると、慣れとか腕とかの問題より、検索して資料が出てくるかどうかの問題が大きかったりするのかもしれないなあ。

追記

さっき、複数ページを取れるように書き換えた。$max_pageを0オリジンで書き換える(現在は$max_page=1で、ベスト100まで取りに行く)と、ベスト200だろうがベスト1000だろうが好きなだけ。ただまあ時間はかかるけどね。

さらに追記。

http://b.hatena.ne.jp/entrylist?sort=countはURLで絞り込めるので、$url_stringのところにその絞り込んだ結果のURL*1を書いてあげれば、fc2 blogの人気エントリでもdankogaiの人気エントリランキングでも好きなだけ成形できたりして。

三追

ランク表示($count)をブクマ数が同じなら同順位になるように変更した。若干手抜きだがまあこの用途でなら問題ないはず。