技术开发 频道

用于Python的RSS

  【IT168 技术文档】RSS 是迄今为止最为成功的 XML 服务之一。尽管它的起源非常混乱,但它已经成为了通过 Web 站点交换内容信息的社区标准。Python 是一个很棒的 RSS 处理工具,Mike Olson 和 Uche Ogbuji 介绍了一些可用于 RSS 处理的模块。

  RSS 是一个可用多种扩展来表示的缩写:“RDF 站点摘要(RDF Site Summary)”、“真正简单的辛迪加(Really Simple Syndication)”、“丰富站点摘要(Rich Site Summary)”,也许还能用其他扩展来表示。在如此混乱的名称背后,您会发现和这样一个平凡的技术领域相关的故事多得令人吃惊。RSS 是用于分发 Web 站点上的内容的摘要的一种简单的 XML 格式。它能够用于共享各种各样的信息,包括(但不是仅限于)简讯、Web 站点更新、事件日历、软件更新、特色内容集合和基于 Web 进行拍卖的商品。

  RSS 是 Netscape 在 1999 年创建的,它允许将许多信息源中的内容聚集到 Netcenter 门户网站中(这个门户网站现在已经不存在了)。UserLand 社区中的 Web 狂热爱好者们成为了 RSS 早期的支持者,RSS 很快就成为了一种非常流行的格式。这种流行使得人们很难对 RSS 进行改进从而使它能用于更多的地方。这种限制导致了 RSS 的发展出现了分歧。其中一个组选择了一种基于 RDF 的方式,目的在于利用大量的 RDF 工具和模块,而另一个组则选择了一种更加紧缩的方式。前者被称之为 RSS 1.0,而后者则被称之为 RSS 0.91。就在上个月由于 RSS 非 RDF 变体的一个新版本的出现使得两者之间的竞争进一步加剧,这一新版本被它的创造者称之为“RSS 2.0”。

  RSS 0.91 和 1.0 非常流行,并且许许多多的门户网站和 Web 日志都使用它们。事实上,blogging 社区是 RSS 的主要用户,而 RSS 就是某些现有的用于 XML 交换的网络令人印象深刻的理由。这些网络已在有机地增长,并且真正地成为现有的最成功的 XML 服务的网络。RSS 成为一种 XML 服务是因为它被通过网际协议交换 XML 信息(绝大多数的 RSS 交换是 RSS 文档的简单 HTTP GET)。在本文中,我们介绍的不过是许多可以与 RSS 一起工作的 Python 工具中的少数几个。我们不提供针对 RSS 的技术上的介绍,因为您可以在其他许多的文章中获得这些内容。(请参阅参考资料)。我们推荐您首先简单地熟悉一下 RSS 知识,并且能了解 XML。您不需要去了解 RDF。

  [ 由于 RSS 使用了 XML 描述而没有使用 WSDL,所以我们将 RSS 作为一个“XML 服务”而不是一个“Web 服务”对待。- 编者按 ]

  RSS.py

  Mark Nottingham 编写的 RSS.py 是用于 RSS 处理的一个 Python 库。它非常完善并且编写的很好。它需要 Python 2.2 和 PyXML 0.7.1。它的安装是非常简单;您只需从 Mark 的主页中下载 Python 文件并将它复制到您的 PYTHONPATH 中的某处。

  大多数 RSS.py 的用户本身只需要关心它所提供的两个类:CollectionChannel 和 TrackingChannel。后者似乎是这两个类中更有用的一个。TrackingChannel 是一个包含以每一项的关键字为索引的所有的 RSS 数据的数据结构。CollectionChannel 是一个类似的数据结构,但它的结构更像 RSS 文档本身,它的顶层通道信息使用 URL 表示的散列值指向项细节。您很可能会使用 RSS.ns 结构中的实用程序名称空间声明。清单 1 是一个简单的脚本,它将下载并解析用于 Python 新闻的 RSS 供给,并以一个简单的清单形式打印来自各项的所有信息。

  清单 1:使用 RSS.py 的一个简单练习

  from RSS import ns, CollectionChannel, TrackingChannel   #Create a tracking channel, which is a data structure that   #Indexes RSS data by item URL   tc = TrackingChannel()   #Returns the RSSParser instance used, which can usually be ignored   tc.parse("http://www.python.org/channews.rdf")   RSS10_TITLE = (ns.rss10, 'title')   RSS10_DESC = (ns.rss10, 'description')   #You can also use tc.keys()   items = tc.listItems()   for item in items:   #Each item is a (url, order_index) tuple   url = item[0]   print "RSS Item:", url   #Get all the data for the item as a Python dictionary   item_data = tc.getItem(item)   print "Title:", item_data.get(RSS10_TITLE, "(none)")   print "Description:", item_data.get(RSS10_DESC, "(none)")

  我们从创建一个 TrackingChannel 实例开始,并且将从 http://www.python.org/channews.rdf 上的 RSS 供给解析得到的数据填入其中。RSS.py 使用元组作为 RSS 数据的属性名称。对于那些不习惯 XML 处理技术的人来说,这种方式看上去也许不太寻常,但它对于精确了解原始的 RSS 文件中的内容的确是一种很有效的方式。因此,一个 RSS 0.91 title 元素被认为不同于一个 RSS 1.0 中的同名元素。应用程序有足够的数据来忽略这个差异,如果您愿意,可以通过忽略每个元组的名称空间的部分来忽略这个差异;但基本的 API 是与初始 RSS 文件的语法相结合的,所以这个信息没有丢失。在代码中,我们使用这个属性数据来聚集用于显示的新闻供给中的所有项。请注意,我们很仔细地不去假定任何特殊的项可能会有什么属性。我们使用如下代码所示的安全的形式来检索属性。

  print "Title:", item_data.get(RSS10_TITLE, "(none)")

  如果没有找到该属性则它会提供一个缺省值,而不是这个示例。

  print "Title:", item_data[RSS10_TITLE]

  由于您不可能会知道 RSS 供给中所使用的是什么元素,因此这样的谨慎是有必要的。清单 2 显示了清单 1 的输出。

  清单 2:清单 1 的输出

  $ python listing1.py   RSS Item: http://www.python.org/2.2.2/   Title: Python 2.2.2b1   Description: (none)   RSS Item: http://sf.net/projects/spambayes/   Title: spambayes project   Description: (none)   RSS Item: http://www.mems-exchange.org/software/scgi/   Title: scgi 0.5   Description: (none)   RSS Item: http://roundup.sourceforge.net/   Title: Roundup 0.4.4   Description: (none)   RSS Item: http://www.pygame.org/   Title: Pygame 1.5.3   Description: (none)   RSS Item: http://www.cosc.canterbury.ac.nz/~greg/python/Pyrex/   Title: Pyrex 0.4.4.1   Description: (none)   RSS Item: http://www.tundraware.com/Software/hb/   Title: hb 1.88   Description: (none)   RSS Item: http://www.tundraware.com/Software/abck/   Title: abck 2.2   Description: (none)   RSS Item: http://www.terra.es/personal7/inigoserna/lfm/   Title: lfm 0.9   Description: (none)   RSS Item: http://www.tundraware.com/Software/waccess/   Title: waccess 2.0   Description: (none)   RSS Item: http://www.krause-software.de/jinsitu/   Title: JinSitu 0.3   Description: (none)   RSS Item: http://www.alobbs.com/pykyra/   Title: PyKyra 0.1.0   Description: (none)   RSS Item: http://www.havenrock.com/developer/treewidgets/index.html   Title: TreeWidgets 1.0a1   Description: (none)   RSS Item: http://civil.sf.net/   Title: Civil 0.80   Description: (none)   RSS Item: http://www.stackless.com/   Title: Stackless Python Beta   Description: (none)

  当然,你可能会遇到稍微有些不同的输出,这是因为在您对它进行试验时新闻项可能已经更改了。RSS.py 通道对象也提供方法来添加并修改 RSS 信息。您可以使用 output() 方法将结果写回 RSS 1.0 格式。通过将在清单 1 中解析的信息写回去来对它进行试验。在交互式模式下通过运行 python -i listing1.py 来启动脚本。在产生的 Python 提示符下,运行以下示例。

  >>> result = tc.output(items)

  >>> print result

  结果是一个打印输出的 RSS 1.0 文档。为了它能工作您必须有 RSS.py,版本 0.42 或者更高的版本。较早版本中的 output() 方法中有一个错误。

  rssparser.py

  Mark Pilgrim 为 RSS 文件解析提供了另一个模块。它并不提供 RSS.py 所提供的所有的功能部件和选项,但它却提供了一个非常自由的解析器,它能很好的处理 RSS 世界中所有令人混乱的差异。以下摘自 rssparser.py 页面:

  # 如您所见,大多数 RSS 供给都很糟糕。无效的字符、未转义的 & 符号(Blogger 供给)、无效的实体(Radio 供给)和未转义以及无效的 HTML(通常为注册中心所提供的)。或者只是 RSS 0.9x 元素和 RSS 1.0 元素的一个笼统的混合(可移动类型供给(Movable Type feeds))。

  # 还有许多太前沿的供给,就象 Aaron 的 feed。他将一个摘录放入描述元素中而将完整的文本放入 content:encoded 元素中(象 CDATA)。这是一个有效的 RSS 1.0,但没有人回真正使用它(除了 Aaron),几乎没有新闻聚集器支持它,并且许多解析器还排斥它。其他解析器被 RSS 0.94 中的新元素(guid)所困惑(请参阅 Dave Winer 的供给作为一个示例)。还有 Jon Udell 的供给,其中还有他才从创作中挑选出来的 fullitem 元素。

  XML 和 Web 服务会增加互操作性几乎已成定局,所以这样考虑其实很可笑。无论如何,设计 rssparser.py 目的就是要处理所有这些荒唐的情况。

  安装 rssparser.py 也十分简单。请您下载 Python 文件(参阅参考资料),将“rssparser.py.txt”重命名为 “rssparser.py”,并将它复制到您的 PYTHONPATH 中。我同样建议您取得可选的 timeoutsocket 模块,它可以改进 Python 中的套接字操作的超时行为,这样有助于取得 RSS feeds 而不必为了防止错误就停止应用程序线程。

  清单 3 是一个等同于清单 1 的脚本,但它使用了 rssparser.py,而不是 RSS.py。

  清单 3:使用一个简单的 rssparser.py 练习

  import rssparser   #Parse the data, returns a tuple: (data for channels, data for items)   channel, items = rssparser.parse("http://www.python.org/channews.rdf")   for item in items:   #Each item is a dictionary mapping properties to values   print "RSS Item:", item.get('link', "(none)")   print "Title:", item.get('title', "(none)")   print "Description:", item.get('description', "(none)")

  如您所见,这段代码非常简单。RSS.py 和 rssparser.py 不能互相取代在很大程度上是因为前者有更多的功能部件,并且维护着 RSS 供给中更多的语法信息。后者更简单,并且是一个容错能力更强的解析器(RSS.py 解析器只能接受格式良好的 XML)。

  它的输出应该与清单 2 中的输出相同。

0
相关文章