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


Weblogs.com Ping Gateway to はてなアンテナ

by miyagawa at Thu, 09 Oct 2003 05:29

Movable Type などの Blog ツールは、Weblogs.Com などの Ping Server に更新を通知する機能を持っています。この更新通知は、Weblogs.Com Ping Specs にあるような XML-RPC の API を通じて行われており、日本では ping.bloggers.jpMyBlog Japan などがこの XML-RPC Server の仕様を実装しています。

今回のレシピでは、この Ping Server を実装して、受けとった Ping を はてなアンテナ に更新通知するプロキシをつくってみます。


Weblogs.Com の XML-RPC Ping Spec は xmlrpc.com で解説されています(*1)

weblogUpdates.ping (weblogname, weblogurl) returns struct

To tell Weblogs.Com that a weblog has changed, call weblogUpdates.ping on rpc.weblogs.com, port 80, path /RPC2.

It takes two parameters, both strings. The first is the name of the weblog, the second is its URL.

We read the weblog to determine if it has changed, therefore the weblog must already be updated when you call weblogUpdates.ping.

It returns a struct that indicates success or failure. It has two elements, flerror and message. If flerror is false, it worked. If it's true, message contains an English-language description of the reason for the failure.

ここで最初に記述されている rpc.weblogs.com, port 80, path /RPC2 は Weblogs.Com で使用している URI で、実際にはMTなどのツールでは設定項目で変更することができるため、これは任意の通知先 URL となります。

それ以外を整理すると、
メソッド名weblogUpdates.ping
引数(String weblogname, String weblogurl)
返り値struct { Boolean flerror, String message }
のような XML-RPC API となります。

サンプルコード

Perl で XML-RPC のクライアントやサーバを記述するには、SOAP のツールキットである SOAP::Lite にバンドルされている XMLRPC::Lite モジュールを使用するのが簡単です (*2)。ここでは CGI スクリプトによってXML-RPCのエンドポイントをつくることができる XMLRPC::Transport::HTTP を使用します。作成したスクリプトは List 1 のようになります。

my $server = XMLRPC::Transport::HTTP::CGI
    ->dispatch_to('weblogUpdates')
    ->handle;
ここでは、XMLRPC::Transport::HTTP::CGI から dispatch_to メソッドを呼び出して、weblogUpdates パッケージのメソッドに dispatch するよう設定しています。これで、weblogUpdates.ping のメソッドを処理することができるようになります。実際に XML-RPC クライアントからリクエストが来ると、weblogUpdates->ping(@args); のようにクラスメソッドで API がコールされます。よって weblogUpdates パッケージ に ping というクラスメソッドを用意すればよいことになります。これは別のモジュール等で実装して呼び出すのが一般的ですが、今回のスクリプトでは、ゲートウェイとなるスクリプトにインラインでメソッドを記述する形にしました。

package weblogUpdates;

use LWP::Simple;
use URI::Escape;

my $HatenaURL;
BEGIN { $HatenaURL = "http://a.hatena.ne.jp/check?url=%s"; }

sub ping {
    my($class, $blog_name, $blog_url) = @_;
    my $api_url = sprintf $HatenaURL, uri_escape($blog_url);
    if (LWP::Simple::get($api_url)) {
        return { flerror => XMLRPC::Data->type(boolean => 0) };
    } else {
        return { flerror => XMLRPC::Data->type(boolean => 1),
                 message => "request failed." };
    }
}
引数に $blog_name, $blog_url を受けとり、はてなアンテナの更新通知URLを生成(*3)LWP::Simple モジュールでリクエストを送信しています。

はてなアンテナの更新通知については、http://a.hatena.ne.jp/check に記述がある API を使用しました。

更新通知用APIについて
※このページをはてなアンテナに対して能動的に更新を通知するためのAPIとして公開します。お使いの掲示板CGIなどで、ページ更新時にアクセスして頂くことで迅速な更新の反映が可能となります。
※アクセスURL http://a.hatena.ne.jp/check?url=チェックしたいページのエンコード済みURL

本来であれば、はてなの更新通知 API の返り値をチェックすべきですが、現状では HTML をパースする以外にエラーかどうかを調べる方法はない(*4) ようですので、ここではコンテンツが返ってくるかどうかのチェックだけとしています(*5)。返り値として、struct (= Perl ではハッシュリファレンス) を返しています。返り値の boolean 値をつくるためには XMLRPC::Data をつかって明示的に boolean 値を作成します。成功の場合は flerror を false (0) で返し、失敗であれば flerror を true (1), message にエラー文字列を入れて return しています。

このスクリプト (ping_to_hatena) を CGI として動作させる URL (たとえば http://blog.example.com/ping_to_hatena) に設置し、Blog の Ping 通知先にその URL を記述すれば、Blog の更新をはてなアンテナに即座に反映させることができるというわけです。

Listings

List 1: ping_to_hatena.pl
#!/usr/local/bin/perl -w
# ping_to_hatena - Weblogs.Com Ping Server Gateway to Hatena Antenna

use strict;
use XMLRPC::Transport::HTTP;

my $server = XMLRPC::Transport::HTTP::CGI
    ->dispatch_to('weblogUpdates')
    ->handle;

package weblogUpdates;

use LWP::Simple;
use URI::Escape;

my $HatenaURL;
BEGIN { $HatenaURL = "http://a.hatena.ne.jp/check?url=%s"; }

sub ping {
    my($class, $blog_name, $blog_url) = @_;
    my $api_url = sprintf $HatenaURL, uri_escape($blog_url);
    if (LWP::Simple::get($api_url)) {
        return { flerror => XMLRPC::Data->type(boolean => 0) };
    } else {
        return { flerror => XMLRPC::Data->type(boolean => 1),
                 message => "request failed." };
    }
}
*1) 実際には Weblogs.Com には SOAP や REST (HTML Form) のサービス実装も用意されていますが、各種 Blog ツールが通知として利用しているのは XML-RPC のものです。
*2) 実際 XMLRPC::Lite は SOAP::Lite のサブクラスとして実装されています。
*3) URI::Escape で URL エンコードを忘れずに!
*4) やるのであれば、HTMLに対して正規表現で /ご指定のページはアンテナに登録されていません/ にマッチさせるのが簡単かもしれません。
*5) たとえば a.hatena.ne.jp にアクセスできない場合や、500 Internal Server Error を返す場合などにエラーとなります

Copyright©2002-2003 Tatsuhiko Miyagawa