Published on Blog Developer's Cookbook.
Printer friendly version of http://blog.bulknews.net/cookbook/blosxom/rss/blogrolling2rss.html.


BlogRolling を利用して RSS 巡回先を管理

by miyagawa at Sat, 25 Oct 2003 23:05

RSS は Aggregator で読むだけではなく、様々な使用方法があります。お気に入りの RSS リスト(巡回先) が肥大してくると、この管理もなかなか大変です。今回は BlogRolling というサービスを使用して、RSS 巡回先の管理を行ってみます。


BlogRolling

RSS Aggregator に登録した Blog サイトの巡回先が肥大化してくると、以下のような問題が生じます。 これは Web ブラウザの Bookmark を自宅と職場で同期したいという要望に非常によく似ています。オンラインでブックマーク管理できる各種オンラインブックマークサービスが登場したのと同様に(*1)、自分の巡回する Blog サイトのリストを Web 上で管理できるサービスが、BlogRolling です。

BlogRolling は、Weblogs.Comchanges.xml に掲載されている更新情報をもとにして(*2)、自分の巡回する Blog リストを更新順に並べかえてくれるサービスです。BlogRolling の URL リストは JavaScript で HTML 出力する機能を持っているため、巡回リストを更新時間順に(*3)ソートして、自分の Blog の SideBar などに張りつけることができます。ちょうど はてなダイアリー のサイドバーに はてなアンテナ のアンテナを張りつけるのに似ていますね。

こうして巡回先リストを Web 上の BlogRolling に保持しておくことで、

のように各所で利用している「巡回リスト」が BlogRolling で一括管理できるようになります。

BlogRolling はブラウザから 1-Click で登録する Bookmarklet や "BlogRoll Me" (*4) などの簡易登録インタフェースも用意しているため、「お、このサイトいいな」と思った際に、すぐに追加できるのも便利なところです。

BlogRolling に登録したサイトの RSS 一覧を取得

BlogRolling の巡回結果は JavaScript 以外にも RSS や OPML(*5) での出力もサポートしています。RSS での出力は List 1 のようになっており、更新時刻順に Blog サイトのタイトルや URL が item の要素に出力されています。

このように、BlogRolling で管理した巡回先マスタ(RSS)から Blog リストを抽出して、RSS の更新情報をメールで送信 などのアプリケーションに渡すようにすれば、Web で管理した Blog リストについて、メーラで更新情報を取得できるという大層なアプリケーションが簡単に作成できます。

注意すべきは、BlogRolling の出力する RSS には、サイト毎の RSS の URL は含まれていないことです。RSS Auto Discovery を利用して RSS のリストを作成してあげればよいでしょう。

サンプルコード

BlogRolling の BlogRoll (*6) から RSS リストを抽出するスクリプトは List 2 のようになります。

use HTML::RSSAutodiscovery;
use LWP::Simple;
use Storable;
use XML::RSS;
使用するモジュールを use します。データのキャッシュに Storable、また RSS Auto Discovery 用に HTML::RSSAutodiscovery を使用します。

our $CacheFile     = "rss.cache";
our $BlogRollingId = "fd16d26c9ad1029c21a48955b8c19731";
設定項目を our で格納します。ここでは URL から RSS へのマッピングを保存するキャッシュファイルのパス、また BlogRolling のアカウント ID (*7) を設定します。

my $cache = eval { Storable::retrieve($CacheFile) } || {};
Storable 形式で保存されたキャッシュをロードします。ファイルがない場合は例外が投げられるので, eval でトラップして初期化します。

my $url = "http://rpc.blogrolling.com/rss.php?r=$BlogRollingId";
my $xml = LWP::Simple::get($url);
RSS を出力する RPC に、自分の BlogRolling ID を付加して RSS ファイルを HTTP GET します。

my $rss = XML::RSS->new();
   $rss->parse($xml);

for my $item (@{$rss->{items}}) {
    $cache->{$item->{link}} ||= discover_rss($item->{link}) or next;
    print $cache->{$item->{link}}, "\n";
}
いつものように、XML::RSS でパースして、各 item について処理します。item の link に Blog の URL が格納されています。キャッシュを lookup して、存在しなければ discover_rss で、その URL への RSS を探します。見つかれば標準出力に print します。

sub discover_rss {
    my $url = shift;
    my $discovery = HTML::RSSAutodiscovery->new();
    my $rss = $discovery->parse($url);
    unless (@$rss) {
        warn "no RSS found for $url\n";
        return;
    }
    return $rss->[0]->{href};
}
今回は HTML::RSSAutodiscovery を使用して RSS の自動探索を行っています。マッチした結果は配列リファレンスで取得できます。自動探索に失敗すると要素が 0個の配列となるため、warning を出力し return します。マッチした場合には 1つめのエントリの href 要素を RSS の URL として返します。

Storable::nstore($cache => $CacheFile);
最後にキャッシュした結果をファイルに書き出します。これによって1つの URL に対して複数回 RSS の自動探索を行うことが防げます(*8)

実行例

コマンドラインで実行すれば、RSS の URL 一覧が STDOUT に出力されます。

% ./blogrolling2rss.pl
http://www2u.biglobe.ne.jp/%7Ekyo-n/blog/blosxom.cgi/index.rss
http://blog.bulknews.net/cookbook/blosxom/index.rss10
http://blog.bulknews.net/mt/index.rdf
http://shibuya.pm.org/blosxom/index.rss10
http://naoya.dyndns.org/~naoya/mt/index.rdf

この結果をファイルに格納するようにして、

% ./blogrolling2rss.pl > blogrolling.txt

このファイル内の RSS を rss2email に食わせれば、前述したようなメールによる Blog サイト Aggregator の出来上がりです。しかも巡回先リストの管理画面つき (BlogRolling のサイトで行えます)です。

See Also

Listings

List 1: sample.xml
<?xml version="1.0"?>
<!-- RSS generation done by 'Blogrolling.com'-->
<rss version="0.92">
<channel>
<title>blog.bulknews.net</title>
<link>blog.bulknews.net</link>
<description>Blogrolling.com RSS Feed</description>
<lastBuildDate>Thu, 23 Oct 2003 11:52:08 GMT</lastBuildDate>
<docs>http://www.blogrolling.com/</docs>
<webMaster>rss@blogrolling.com (Blogrolling RSS Generator)</webMaster>
<item>
<title>HAIL 2 U !! - Weblog</title>
<link>http://www2u.biglobe.ne.jp/%7Ekyo-n/blog/blosxom.cgi</link>
<description>Last updated: 12:08:48 GMT on Thursday, October 23</description>
</item>
<item>
<title>Blog Developer's Cookbook</title>
<link>http://blog.bulknews.net/cookbook/blosxom</link>
<description>http://blog.bulknews.net/cookbook/blosxom</description>
</item>
<item>
<title>blog.bulknews.net</title>
<link>http://blog.bulknews.net/mt/</link>
<description>http://blog.bulknews.net/mt/</description>
</item>
<item>
<title>Shibuya Perl Mongers</title>
<link>http://shibuya.pm.org/</link>
<description>http://shibuya.pm.org/</description>
</item>
<item>
<title>NDO::Weblog</title>
<link>http://naoya.dyndns.org/</link>
<description>http://naoya.dyndns.org/</description>
</item>
</channel>
</rss>
List 2: blogrolling2rss.pl
#!/usr/local/bin/perl -w
# blogrolling2rss - extract RSS feeds from BlogRolling URL list

use strict;
use HTML::RSSAutodiscovery;
use LWP::Simple;
use Storable;
use XML::RSS;

our $CacheFile     = "rss.cache";
our $BlogRollingId = "fd16d26c9ad1029c21a48955b8c19731";

my $cache = eval { Storable::retrieve($CacheFile) } || {};

my $url = "http://rpc.blogrolling.com/rss.php?r=$BlogRollingId";
my $xml = LWP::Simple::get($url);

my $rss = XML::RSS->new();
   $rss->parse($xml);

for my $item (@{$rss->{items}}) {
    $cache->{$item->{link}} ||= discover_rss($item->{link}) or next;
    print $cache->{$item->{link}}, "\n";
}

Storable::nstore($cache => $CacheFile);

sub discover_rss {
    my $url = shift;
    my $discovery = HTML::RSSAutodiscovery->new();
    my $rss = $discovery->parse($url);
    unless (@$rss) {
        warn "no RSS found for $url\n";
        return;
    }
    return $rss->[0]->{href};
}
*1) そうしたサービスがすべて廃れていることには目をつむりましょう ;-)
*2) BlogRolling 独自に Ping を受けつける RPC Interface も公開しています。
*3) 設定で更新時間順以外のソートも可能です。
*4) Blog サイトが、自サイトを BlogRolling リストに追加させるためのリンク
*5) Outline Processor Markup Language: 今回は扱いません
*6) BlogRolling の用語で巡回リストのこと
*7) BlogRolling にログインして "Get Code" で取得できます。
*8) RSS が見つからないときだけは、何度も引きにいってしまいます。これを防ぐ場合には、見つからないときでも 0 や '' などの結果を入れて defined で判別するように変更します。

Copyright©2002-2003 Tatsuhiko Miyagawa