IBM®
跳转到主要内容
    中国 [选择]    使用条款
 
 
Select a scope: Search for:    
    首页    产品    服务与解决方案     支持与下载    个性化服务    
跳转到主要内容

developerWorks 中国  >  XML  >

技巧:使用 Universal Feed Parser 驾驭 RSS

当人们忽视了标准时,工具可以节约时间

developerWorks
文档选项

未显示需要 JavaScript 的文档选项


级别: 中级

Uche Ogbuji (uche.ogbuji@fourthought.com), 首席顾问, Fourthought, Inc.

2005 年 1 月 01 日

RSS 被认为是基于 XML(或 XML/RDF)标准的。不幸的是,RSS 背后那个以牛仔作风闻名的社区有很多离经叛道的成分,生成的消息包(feed)甚至都不是结构良好的 XML。Mark Pilgrim 开发的 Universal Feed Parser 是一个很好的工具,能够解析结构不完善的消息包,本篇技巧将介绍如何使用这个工具从 RSS 中抽取消息包信息。

XML 到处都有标准,但让每个人都照规矩行事并不是一件容易的事。Web 以蔑视 HTML 和 XHTML 标准的网页而出名,这也是造成很多受到广泛关注的问题的缘由。W3C 的 Dave Raggett 开发了颇受欢迎的工具 Tidy(请参阅 参考资料)来挽救这种局面,它将“标签汤”(粗心和结构错误的 HTML)转化成结构良好的 XHTML。RSS 是另一个理论标准被混乱的现实打破的例子。更糟的是,RSS 存在很多相互竞争的标准,有一些相差甚大。沿着 Raggett 的思路,Mark Pilgrim 开发了 Universal Feed Parser,用他的话来说就是“极端自由的 RSS 解析器”。但 Universal Feed Parser 的功能不止于此,引用文档中的说法:

Universal Feed Parser 是一个下载和解析连锁消息包的 Python 模块。它可以处理 RSS 0.90、Netscape RSS 0.91、Userland RSS 0.91、RSS 0.92、RSS 0.93、RSS 0.94、RSS 1.0、RSS 2.0、Atom 和 CDF 消息包。

从这个列表就可以看出人们为何把 RSS 和混乱联系在一起。Atom(请参阅 我最近撰写的相关文章)本来希望给 RSS 一个全新的面貌,但实际上仅仅增加了一种选择。所幸的是,Universal Feed Parser 吸收了大家所能设想到的各种消息包格式,包括那些宣称遵循某种 RSS 标准但又有细微不同的消息包。本文给出的示例代码利用 Universal Feed Parser 能够处理各种 RSS 消息包。

简单的消息包列表程序

清单 1 示范了 Universal Feed Parser 的用法,它从给定的 URL 读入 RSS 并在控制台上显示消息包中的基本信息。


清单 1. 在标准输出中显示消息包信息
import sys
import feedparser
#List of uples (label, property-tag, truncation)
COMMON_CHANNEL_PROPERTIES = [
    ('Channel title:', 'title', None),
    ('Channel description:', 'description', 100),
    ('Channel URL:', 'link', None),
]
COMMON_ITEM_PROPERTIES = [
    ('Item title:', 'title', None),
    ('Item description:', 'description', 100),
    ('Item URL:', 'link', None),
]
INDENT = u' '*4
def feedinfo(url, output=sys.stdout):
    """
    Read an RSS or Atom feed from the given URL and output a feed
    report with all the key data
    """
    feed_data = feedparser.parse(url)
    channel, items = feed_data.feed, feed_data.entries
    #Display core feed data
    for label, prop, trunc in COMMON_CHANNEL_PROPERTIES:
        value = channel[prop]
        if trunc:
            value = value[:trunc] + u'...'
        print >> output, label, value
    print >> output
    print >> output, "Feed items:"
    for item in items:
        for label, prop, trunc in COMMON_ITEM_PROPERTIES:
            value = item[prop]
            if trunc:
                value = value[:trunc] + u'...'
            print >> output, INDENT, label, value
        print >> output, INDENT, u'---'
    return
if __name__ == "__main__":
    url = sys.argv[1]
    feedinfo(url)
  

清单 COMMON_CHANNEL_PROPERTIESCOMMON_ITEM_PROPERTIES 定义了频道和特别关注的每个条目的属性。Use Universal Feed Parser 尝试使用最常见的名称提供对最常用属性的访问,而不考虑不同 RSS 版本间的差异。清单 1 列出的条目名称适用于 Universal Feed Parser 所能识别的任何格式的任何消息包。工具文档中有一节题为“Content Normalization”,讨论了如何处理源格式术语的差异。 feedinfo 是主函数,负责接收 URL 和可选的输出流(类似文件的对象),默认输出流为系统输出(控制台)。 feedparser.parse 是惟一需要知道的 Universal Feed Parser API。它在一个数据结构中返回所有的消息包数据,可以像嵌套对象那样访问这种数据结构,或者像嵌套词典那样访问(如果愿意的话)。比如,可以使用 feed_data.feedfeed_data.['feed'] 访问顶层频道或者消息包属性。

剩下的代码打印顶层消息包的细节和每个条目。它提供了有限的格式化特性,比如将很长的属性值缩减到给定的字符数(由 COMMON_CHANNEL_PROPERTIESCOMMON_ITEM_PROPERTIES 列表中每一条的第三项决定)。注意,我在处理 Use Universal Feed Parser 的字符串时使用了 Unicode。该工具就是使用 Unicode 对象表示数据,从而很好地保证了消息包数据的国际化。但是如果您恰好对包含非 ASCII 字符的消息包运行 清单 1,那么可能在打印语句中遇到编码错误。如果出现这种情况,则需要明确使用 Python 的 Unicode 设施更小心地处理输出(可以用标准 codecs 模块中的 Unicode 编码器包装输出流)。

下面的片段是对 IBM DeveloperWorks 首页的 RSS 消息包运行 清单 1 的结果,这是一个结构良好的 RSS 2.0 消息包。为了便于查看,我添加了一些新行,并把消息包项减为两个。


清单 2. 对 RSS 消息包运行清单 1
$ python listing1.py http://www.ibm.com/developerworks/news/dw_dwtp.rss
Channel title: IBM developerWorks
Channel description: The latest content from IBM developerWorks...
Channel URL: http://www.ibm.com/developerworks/index.html?ca=drs-tp4704
Feed items:
     Item title: Meet the experts: Ric Telford on the state of autonomic
computing today
     Item description: This question and answer article features Ric
Telford, Director for Autonomic Computing at IBM. deve...
     Item URL:
http://www.ibm.com/developerworks/library/ac-telford/index.html?ca=drs-tp4704
     ---
     Item title: Lightweight RFID framework
     Item description: When administration and cost are an issue, lightweight
RFID is an interim solution...
     Item URL:
http://www.ibm.com/developerworks/library/wi-rfid/index.html?ca=drs-tp4704
     ---
  





回页首


结束语

我曾经多次使用 Universal Feed Parser 作为一种过滤器工具,将任意的消息包转化成 RSS 1.0。它负责最困难的那部分任务,比如应付无法预料的输入。Universal Feed Parser 的测试包给我留下了深刻的印象,它展示了 Mark Pilgrim 为处理 RSS 领域的种种古怪行为付出了多么大的努力。可能有那么一天,RSS 的创建者和用户会就某种消息包格式(比如 Atom)达成一致,但是在那遥远的一天来临之前,Universal Feed Parser 对于每个需要编写代码处理 Weblog 之类信息的人来说,都是一个不可或缺的工具。



参考资料



关于作者

Uche Ogbuji 的照片

Uche Ogbuji 是 Fourthought Inc. 的顾问兼创始人,该公司是一家专为企业知识管理提供 XML 解决方案的软件供应商和咨询公司。Fourthought 开发了 4Suite,这是一个用于 XML、RDF 和知识管理应用程序的开放源代码平台。Ogbuji 先生还是 Versa RDF 查询语言的首席开发人员。他是一位出生于尼日利亚的计算机工程师和作家,目前生活和工作在美国科罗拉多的博耳德。您可以通过 uche.ogbuji@fourthought.com 和 Ogbuji 先生联系。




对本文的评价










回页首


IBM 公司保留在 developerWorks 网站上发表的内容的著作权。未经IBM公司或原始作者的书面明确许可,请勿转载。如果您希望转载,请通过 提交转载请求表单 联系我们的编辑团队。
    关于 IBM 隐私条约 联系 IBM 使用条款