セミコン見ル野のシブすぎ技術に男泣き! が大好きでTECH総研のフィードを購読している。

のだけど、このフィードはなんだかエントリ数が少ない。今(2009/03/25 21:20)確認しても、25日9:00更新の二件だけが含まれている。
使っているアグリゲータの巡回タイミングと合わないのか、時々とりこぼしがある。

同連載に特化した過去記事一覧ページがあるのでこれをフィードにしたらとりこぼしもなくせそう。


よろしい、ならばPipes

と思ってさっそくYQLを書いてみる。class指定で1記事分を楽勝で特定できる。
が、なぜかresultがnull。
なんでだ、と思ったらクッキーを食べないと「クッキー受け入れて」ページが表示されるというオチ。

仕方ないので自分のサーバでPlaggerを定期実行してフィードを生成しweb公開→これをアグリゲータに食わせる、という方針に。

Config::PitとWeb::ScraperとPlaggerで24時間365日のゲーム監視体制 を参考(パクって)にWeb::ScraperしてYAMLで出力するperlスクリプトを用意。これをplaggerから呼び出してPublish::Feedでフィードに。

■perlスクリプト:scrape_semicon.pl
#!/usr/bin/perl

use utf8;
use strict;
use warnings;
no warnings 'uninitialized';

use URI;
use WWW::Mechanize;
use Web::Scraper;
use DateTime;
use YAML;
use DateTime::Format::W3CDTF;

my $uri = URI->new(q|http://rikunabi-next.yahoo.co.jp/tech/docs/ct_s01300.jsp?p=028|);
my $mech = WWW::Mechanize->new(cookie_jar => {});
$mech->show_progress(1);
my $res = $mech->get($uri);
if(!$res->is_success)
{
die $res->status_line;
}

my $result = scraper {
process '//title', 'title' => 'TEXT';
process '//td[@class="j-18-120"]', 'entry[]' => scraper {
process '//a', 'title' => 'TEXT';
process '//a', 'link' => sub {
my($n) = @_;
return URI->new_abs($n->attr('href'), $uri)->as_string;
};
process '//span' , 'date' => sub {
my($n) = @_;
my $t = $n->as_trimmed_text;
if($t =~ /\(([0-9]+)\.([0-9]+)\.([0-9]+)\)/)
{
my($y, $m, $d) = ($1, $2, $3);
$y += 2000 if $y < 100;
my $dt = DateTime->new(
year => $y,
month => $m,
day => $d,
time_zone => 'local',
);

my $f = DateTime::Format::W3CDTF->new;
return $f->format_datetime($dt);
}
return undef;
};
};
}->scrape($res->decoded_content);

$result->{link} = $uri->as_string;

binmode STDOUT, ":utf8";
print YAML::Dump $result;

0;
「link」を「@href」を指定せずにぐりぐりと文字列でreturnしている。
過去記事一覧ページにおいて当該記事へのhrefは相対URLで書かれている。scrape()の第二引数にURIを渡して「@href」を用いればWeb:ScraperがURI->new_absしてくれるのだけど、この結果Publish::FeedにURIオブジェクトが渡ってくるためフィードエントリのリンク先が「URI::http=SCALAR(0xxxxxxx)」になってしまったから。
(追記)Dump前に$YAML::Stringify = 1 で文字列で出力してURIオブジェクトに復元されないようにしたらいいみたい。
 
■yaml
plugins:
- module: Subscription::Config
config:
feed:
- url: script:/path/to/scrape_semicon.pl
- module: CustomFeed::Script
- module: Publish::Feed
config:
format: Atom
dir: /path/to/out
filename: semicon.xml


後はplagger -c YAMLを実行するシェルスクリプトを作って(loggerでログ出力したいので)、crontabに登録。


一定の構造のyamlをSTDOUTに吐くところまでをtry&errorで繰り返して、後はplaggerで実行するだけ、という手順が楽でいい。