M.C.P.C.

―むり・くり―プラスコミュニケーション(更新終了)


| トップページ |

2008年4月14日 23:31

EDGE Now!の内部DBの代わりを外部に作る

このエントリーをはてなブックマークに追加 mixiチェック

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サーバのプログラムを紹介するつもり。

投稿 大野 義貴 [Web] | |

トラックバック(0)

トラックバックURL: http://blog.dtpwiki.jp/MTOS/mt-tb.cgi/2439

コメントする