EDGE Now!は、参加者みんなからURLを紹介してもらっているわけですけれども、紹介してもらったURLを一覧するインターフェースがありません。
一見、LATEST SITEの欄に表示されているように見えますが、ここの欄は、午前1時のその日初のクロール直前にリセットされてしまうので、ストックされているわけではないのです。
これをストックしておかないと、特定URLがEDGE Now!にすでに登録されているかどうか分からないので、いろいろおもしろいサービスが作れません。
というわけで、EDGE Now!内部のDBの代わりに、外部でEDGE Now!に新規登録されたサイトをDBに登録してみようと思いました。
Filename: edgenow_sites.db
$ sqlite3 edgenow_sites.db
SQLite version 3.1.2
Enter ".help" for instructions
sqlite> CREATE TABLE urls (
id INTEGER PRIMARY KEY AUTOINCREMENT,
ctime DEFAULT CURRENT_TIMESTAMP,
entryid INTEGER,
url TEXT,
title TEXT,
option TEXT
);
sqlite> .schema
CREATE TABLE sqlite_sequence(name,seq);
CREATE TABLE urls (
id INTEGER PRIMARY KEY AUTOINCREMENT,
ctime DEFAULT CURRENT_TIMESTAMP,
entryid INTEGER,
url TEXT,
title TEXT,
option TEXT
);
sqlite> .q
$
Filename: robot.pl
#!/usr/bin/perl
use strict;
use warnings;
use DateTime::Format::MySQL;
use DBI;
use LWP::UserAgent;
use URI;
use URI::Escape;
use utf8;
use XML::RSS;
use XML::Simple;
binmode STDOUT => ':utf8';
# 定数
our $referer = 'http://labo.dtpwiki.jp/edgenow/index.rdf';
my $db_path = 'edgenow_sites.db';
# LWP::UserAgent 用意
our $ua = LWP::UserAgent->new;
$ua->timeout(10);
$ua->agent( "EDGENow!index.rdf/0.1($referer)" );
# DB 用意
our $dbh = DBI->connect( "dbi:SQLite:dbname=$db_path",
q(), q(),
{ AutoCommit => 0 }
);
my $sth = $dbh->prepare( "INSERT INTO urls "
."(entryid, url, title, option, ctime ) "
."VALUES (?, ?, ?, ?, ?)");
my $sth2 = $dbh->prepare( "SELECT * FROM urls WHERE entryid = ?" );
# メインルーチン
my $result = get_data(); #EDGE Now!からXMLデータをある分だけ取得
# 帰ってきたハッシュを処理。DBと照合してまだ無い項目を追加します
foreach my $id ( sort keys %$result ) {
my $hash = $result->{ $id };
my $result = $sth2->execute( $id ) or die $DBI::errstr;
my $ref = $sth2->fetchrow_hashref;
next if $ref;
next if ref( $hash ) ne 'HASH';
next unless $hash->{url}->[0];
my $title = ref( $hash->{title }->[0] ) eq 'HASH'
? q() # NULLの場合
: $hash->{title }->[0]; # NULLでない
my $option = ref( $hash->{option}->[0] ) eq 'HASH'
? q() # NULLの場合
: $hash->{option}->[0]; # NULLでない
my $url = uri_unescape( $hash->{url}->[0] );
my $ctime = _date( $hash->{entryTime}->[0] );
$sth->execute( $id, $url, $title, $option, $ctime );
print "INSERT INTO urls "
."( entryid, url, title, option, ctime ) "
."VALUES ( $id, '$url', '$title', "
."'$option', '$ctime' )\n";
}
$dbh->commit; # DBコミット
exit;
# EDGE Nowから必要分取得する
sub get_data {
my $refs = {};
my $i = 0;
my $max;
while ( 1 ) {
my $ref = get_EDGENow( $i ); # EDGE Now!からページ
# 指定でハッシュ取得
$max = $ref->{module}->[1]->{count} if $i == 0; # 項目数
$refs = {
%$refs,
%{ $ref->{siteList}->[0]->{site} }
}; # ハッシュ合流
$i++;
last if ($i * 5 >= $max); # もうEDGE Now!から取得しなくてよし
}
return $refs;
}
# EDGE Now!から1ページ分取得する
sub get_EDGENow {
our ( $ua, $referer );
my $page = shift;
my $proxy = 'http://edgenow.jp/xml/edgeNow.php';
my $uri = URI->new( $proxy );
$uri->query_form( page => $page, ) if $page;
my $req = HTTP::Request->new( GET => $uri->as_string );
$req->referer( $referer );
my $res = $ua ->request( $req );
my $xml = $res->content;
my $xs = XML::Simple->new();
my $ref = $xs->XMLin( $xml, forcearray => 1 );
return $ref;
}
# EDGE Now!の日付データをMySQL形式に変換
sub _date {
my $date = shift;
my @s = split( ' ', $date );
my $timestamp = "$s[0]-$s[1]-$s[2] $s[3]:$s[4]:$s[5]";
my $dt = DateTime::Format::MySQL
->parse_datetime( $timestamp )
->set_time_zone( 'local' );
return DateTime::Format::MySQL
->format_datetime( $dt->set_time_zone( 'UTC' ) );
}
実行例:
$ ./robot.pl
INSERT INTO urls ( entryid, url, title, option, ctime ) VALUES ( 5670, 'http://www.suzurankai.com', 'リリー オブ ザ バレイ-サロン ド フルール 少人数制サロンの フラワーアレンジメント教室です。', '', '2008-04-14 14:11:11' )
INSERT INTO urls ( entryid, url, title, option, ctime ) VALUES ( 5671, 'http://30d.jp', '30日間限定オンラインアルバム | 30days Album™', '', '2008-04-14 14:11:11' )
INSERT INTO urls ( entryid, url, title, option, ctime ) VALUES ( 5672, 'http://tha.jp/feed', 'tha feed!', '', '2008-04-14 14:11:14' )
$
このrobot.plを、EDGE Now!のクローリング間隔である2時間ごとに回すとOK。
こうやって、DBに登録した奴を利用して、
M.C.P.C.: EDGE Now!のリンク件数を返す野良API(XML-RPC)
にて、URLから、EDGE Now!に紹介した人数が得られるようになっています。次回は、EDGE Now!に紹介した人数が得られるXML-RPCサーバのプログラムを紹介するつもり。