在 Forge - Bloglines Web 服务,续

作者:Reuven M. Lerner

我写这篇专栏是在 2004 年 11 月 2 日美国大选几天之后。作为一个公认的政治迷,我享受着计算机化的、永远在线的评论的现代时代。我不再需要切换电视频道或在当地图书馆阅读几份报纸;现在,我可以跟踪从候选人到媒体再到各种党派网站的声音片段。

跟上许多不同的新闻和评论网站会消耗大量时间。正如我们过去几个月所看到的那样,每个人都受益于新闻聚合器的创建——这些程序读取 Weblog、报纸和其他经常更新的网站生成的 RSS 和 Atom 联合供稿。正如其名称所示,聚合器获取这些供稿并将它们放入一个易于访问的列表中。

Bloglines.com 是一家提供基于 Web 的新闻聚合器的互联网创业公司。就其本身而言,这不应该让任何人感到惊讶;联合供稿、聚合和 Web 的结合使这成为一个自然的想法。而且,Bloglines 并不是独一无二的;还有其他可能不太知名的基于 Web 的新闻聚合器。

然而,Bloglines 为其订阅者提供的一项独特服务是能够使用 Bloglines 的内部数据库来创建他们自己的新闻聚合器或他们自己的应用程序,这些应用程序建立在 Bloglines 收集的数据之上。任何有兴趣收获 Bloglines 引擎结果的程序员都可以免费获得此信息,并且根据相当宽松的许可协议。Bloglines 大约每小时检查数十万个博客和网站的更新,这意味着使用 Web 服务 API 的人可以确保获得最新的 Weblog 内容。

上次 [LJ, 2005 年 1 月],我们查看了 Notifier API,该 API 提供对特定用户可用但未读供稿的访问。我们还讨论了 Blogroll API,该 API 允许用户确定并以编程方式使用(如果他们愿意)指向供稿的人员列表。正如我们所看到的,这些 API 使我们可以轻松地找出是否有新的 Weblog 条目可用,或者创建我们自己的自定义聚合页面,列出感兴趣的 Weblog。

但是,我们在该文章中公开的功能中缺少一些东西。很高兴知道我的 Bloglines 订阅中有新的 Weblog 条目,但如果我知道哪些博客已更新,那就更好了。而且,获得我当前订阅的列表很好,但我如果能知道哪些订阅已更新,并且知道它们最近一次更新是什么时候、每个 Weblog 中有多少新条目以及这些条目包含什么,我会更高兴。换句话说,我希望能够用我自己的界面替换当前的 Bloglines 界面,以 Bloglines.com 网站不指定的格式显示新的 Weblog 条目。

幸运的是,Bloglines 的 Web 服务开发人员通过 sync API 实现了这一点。本月,我们将继续探索 Bloglines Web 服务,详细了解它提供的 sync API。我们还将创建我们自己的简单新闻聚合器,提供与 Bloglines 界面相同的一些功能。

订阅和项目

归根结底,像 Bloglines 这样的新闻聚合器只是一个 URL 列表。实际上,我们两个月前使用通用供稿解析器创建的基于 Python 的新闻聚合器正是这样一个程序——它查看文件中的一组 URL,并检索与这些 URL 关联的最新项目。每个单独的 Weblog 帖子都必须与列表中的一个 URL 相关联。从订阅列表中删除 URL 会使其关联的帖子与该用户无关,并且他们不可见。

Bloglines 拥有多个用户而不是单个用户这一事实意味着它不仅必须跟踪一组不同的 URL,还必须跟踪哪个 URL 与每个用户相关联。虽然这显然使事情变得有些复杂,但现代高级语言使这两种数据结构之间的区别很容易理解。我们必须创建一个哈希表,其中键是用户 ID,值是与该特定用户关联的列表,而不是简单地存储 URL 列表。一旦我们有了用户的唯一 ID,我们就可以轻松地跟踪该特定用户的订阅。

当然,Bloglines 正在跟踪的订阅不是几千个用户,而是成千上万甚至数十万的用户。因此,可以肯定地假设他们没有使用如此简单的实现,这对于小型实验或为少量人员设计的聚合器来说就足够了。当您接近 Bloglines 的用户负载时,事情会变得有点棘手。每个用户的订阅列表不能是一个简单的 URL;它更可能是一个与 URL 关联的 ID 号(或数据库术语中的主键)。这样的系统让多个参与者有机会订阅网站的联合供稿,并允许 Bloglines 根据他们当前的订阅推荐他们可能喜欢的新 Weblog。

因此,得知从 Bloglines 检索新的 Weblog 帖子是一个两步过程,第一步要求我们检索订阅列表,这不足为奇。也就是说,我们首先要求 Bloglines 提供与用户关联的订阅 ID 列表。然后,我们要求 Bloglines 向我们发送此用户和此订阅 ID 的所有新项目。

Bloglines Web 服务 API 的实现有多种不同的语言版本。因为 Perl 是我创建新应用程序的默认语言,所以我将使用已上传到 CPAN(综合 Perl 存档网络,一个全球性的 Web 和 FTP 服务器集合,可以从中检索 Perl 及其模块)的 WebService::Bloglines 模块。例如,清单 1 包含一个简单的程序 (bloglines-listsubs.pl),它显示用户每个订阅的标题、订阅 ID 和 URL。每个订阅都有许多其他值可用;WebService::Bloglines 的文档以及 Bloglines API 文档都详细列出了这些值。

清单 1. 显示用户的订阅

#!/usr/bin/perl

use strict;
use diagnostics;
use warnings;

use WebService::Bloglines;

my $username = 'reuven@lerner.co.il';
my $password = 'MYPASS';

my $bloglines =
  WebService::Bloglines->new(username => $username,
                             password => $password);

# Do we want to mark them as read?
my $mark_unread = 0;

# From what date do we want to download items?
# (This should be in Unix "time"

my $subscriptions = $bloglines->listsubs();

if ($subscriptions)
{
    # list all feeds
    my @feeds = $subscriptions->feeds();

    # Get each feed's title and URL
    foreach my $feed (@feeds) {
        my $title  = $feed->{title};
        my $url    = $feed->{htmlUrl};
        my $subId  = $feed->{BloglinesSubId};

        print "Subscribed to '$title', "
            . "subId '$subId' at '$url'\n";
    }
}
else
{
    print "No subscriptions.\n"
}

如果您有兴趣保留 Bloglines.com 界面给用户提供的订阅层次结构,您可能需要检查 folders 函数,而不是清单 1 中使用的 feed 函数。虽然 feed 返回订阅的扁平列表,但 folders 会保持事物按照它们在 Bloglines 站点上存在的组织方式。

获取订阅中的项目

现在我们知道如何检索与特定 Bloglines 用户关联的订阅 ID,我们可以检索与特定订阅 ID 关联的单个项目。例如,清单 2 是一个简短的程序,它检索用户的所有订阅,然后显示每个订阅的所有新更新项目。输出是纯文本格式,而不是 HTML 格式,这意味着显示的链接不可点击。但是,在 cron 作业中运行这样的程序并将它的输出转储到一个 HTML 文件中,从而给出一个最新的个性化供稿列表,这并非特别困难。当然,无论您何时想查看其网站,Bloglines 都会免费提供此类服务。因此,虽然这样的程序是对 Bloglines Web 服务的一个有趣的用途,但它在这些服务之外并没有令人信服的用途。

清单 2. bloglines-getitems.pl

#!/usr/bin/perl

use strict;
use diagnostics;
use warnings;

use WebService::Bloglines;

my $username = 'reuven@lerner.co.il';
my $password = 'MYPASS';

my $bloglines =
  WebService::Bloglines->new(username => $username,
                             password => $password);

# Do we want to mark them as read?
my $mark_unread = 0;

# From what date do we want to download items?
# (This should be in Unix "time"

my $subscriptions = $bloglines->listsubs();

if ($subscriptions)
{
    # list all feeds
    my @feeds = $subscriptions->feeds();

    foreach my $feed (@feeds) {
        my $title  = $feed->{title};
        my $url    = $feed->{htmlUrl};
        my $subId  = $feed->{BloglinesSubId};

        print "Subscribed to '$title', "
            . "subId '$subId' at '$url'\n";


    my $update;

    # Trap errors!
    eval {$update = $bloglines->getitems($subId);};

    # Keep track of errors, showing "no change"
    if ($@) {
        if ($@ =~ /^304 No Change/) {
            print "\t No change\n";
        }
        else {
            print "\t Error code '$@' "
                . "retrieving updates.\n";
        }
    }

    # No errors?  Show some basics about the items.
    else
    {
        foreach my $item ($update->items)
        {
        my $title       = $item->{title};
        my $creator     = $item->{dc}->{creator};
        my $link        = $item->{link};
        my $pubDate     = $item->{pubDate};
        print "\t$title by $creator "
            . "on $pubDate ($link)\n";
        }
    }
    }
}
else
{
    print "No subscriptions.\n"
}


Bloglines 在其 Web 服务定义中所做的一个巧妙的事情是使用 HTTP 返回代码来指示错误和异常情况。例如,200 (OK) 响应代码表示可以读取新项目,并且 getitems($subId) 包含一个或多个此类数据结构。304(未更改)响应代码通常表示 HTML 页面自上次请求以来没有更改,但此处具有略有不同的功能;它表示特定的订阅者已经看到了此订阅的所有可用项目。其他响应代码(401、403 和 410)表示身份验证错误,可能意味着请求用户在键入 Bloglines 用户名、密码或两者时犯了错误。

不幸的是,Perl 对此类响应代码的处理不太理想。为了处理它们,我们必须调用$bloglines->getitems()在 eval 块内部,并在 eval 之后立即检查 $@ 的非空值。如果 $@ 为空,我们可以假设我们收到了 200 (OK) HTTP 响应代码,并且有新项目可以读取。但是,如果它包含一个值,那么我们可以像在清单 2 中所做的那样重写输出消息。但是,如果我们未能将此方法调用捕获在 eval 块中,那么我们的程序将在我们第一次收到 200 以外的任何响应代码时因致命的运行时错误而终止。

最后,两个可选参数使 Bloglines 功能完整。第一个参数称为 n,是一个简单的真假(1 或 0)值,它告诉 Bloglines 是否应该更新它发送给您的文章的已读位。通常,当用户使用 Bloglines.com Web 界面查看 Weblog 帖子时,此值设置为 1,这意味着您不会第二次看到任何已读文章。或许是因为他们知道 Web 服务 API 目前是其他新闻聚合应用程序的补充,Bloglines 明智地将此 API 中的默认值更改为 0。

第二个可选参数,通常称为“d”,告诉 Bloglines 你想要下载特定网站帖子的起始日期。该值采用 UNIX 时间格式,即自 1970 年 1 月 1 日以来的秒数。大多数主要语言的 time 函数都可以轻松获取此数字,这允许你非常精确地指示你想深入挖掘到特定网站历史记录的深度,该历史记录存储在 Bloglines 中。

结论

说实话,我是一个热情的 Bloglines 用户,但不确定该网站和公司的未来方向。我无法想象它会无限期地免费且没有任何广告,除非其投资者非常慈善或极其天真。我喜欢它优秀的界面,我能够轻松访问我依赖的 Weblogs 来获取政治见解——或者咆哮,这取决于你如何解读这种评论——以及它快速、强大的功能。

但正如 Amazon、eBay 和 Google 在过去几年中所展示的那样,为你的核心数据提供 Web 服务接口为许多新的创意应用程序打开了大门,而这些应用程序是公司内部开发人员从未想过的。 Bloglines 才刚刚开始通过 Web 服务公开其功能,尽管它只朝着这个方向迈出了初步的、试探性的一步,但我所看到的似乎很有希望。我期待看到基于此 API 构建的应用程序,以及 Bloglines 及其竞争对手将提供的其他 API,试图使 Bloglines 成为 Weblogs、读者和开发人员的中心站点。

本文资源: www.linuxjournal.com/article/7961

Reuven M. Lerner 是一位长期的 Web/数据库顾问和开发人员,现在是西北大学学习科学专业的毕业生。 他的 Weblog 在 altneuland.lerner.co.il,你可以通过 reuven@lerner.co.il 联系他。

加载 Disqus 评论