| 2002 年 11 月 01 日 RSS 是迄今為止最為成功的 XML 服務(wù)之一。除了它那令人混亂的歷史根源,它已經(jīng)成為了通過(guò) Web 站點(diǎn)交換內容信息的社區標準。Python 是用于 RSS 處理的一個(gè)優(yōu)秀的工具,并且 Mike Olson 和 Uche Ogbuji 介紹了可用于這一目的的一些模塊。 RSS 是一個(gè)可用多種擴展來(lái)表示的縮寫(xiě):“RDF 站點(diǎn)摘要(RDF Site Summary)”、“真正簡(jiǎn)單的辛迪加(Really Simple Syndication)”、“豐富站點(diǎn)摘要(Rich Site Summary)”,也許還能用其他擴展來(lái)表示。在如此混亂的名稱(chēng)背后,您會(huì )發(fā)現和這樣一個(gè)平凡的技術(shù)領(lǐng)域相關(guān)的故事多得令人吃驚。RSS 是用于分發(fā) Web 站點(diǎn)上的內容的摘要的一種簡(jiǎn)單的 XML 格式。它能夠用于共享各種各樣的信息,包括(但不是 僅限于)簡(jiǎn)訊、Web 站點(diǎn)更新、事件日歷、軟件更新、特色內容集合和基于 Web 進(jìn)行拍賣(mài)的商品。 RSS 是 Netscape 在 1999 年創(chuàng )建的,它允許將許多信息源中的內容聚集到 Netcenter 門(mén)戶(hù)網(wǎng)站中(這個(gè)門(mén)戶(hù)網(wǎng)站現在已經(jīng)不存在了)。UserLand 社區中的 Web 狂熱愛(ài)好者們成為了 RSS 早期的支持者,RSS 很快就成為了一種非常流行的格式。這種流行使得人們很難對 RSS 進(jìn)行改進(jìn)從而使它能用于更多的地方。這種限制導致了 RSS 的發(fā)展出現了分歧。其中一個(gè)組選擇了一種基于 RDF 的方式,目的在于利用大量的 RDF 工具和模塊,而另一個(gè)組則選擇了一種更加緊縮的方式。前者被稱(chēng)之為 RSS 1.0,而后者則被稱(chēng)之為 RSS 0.91。就在上個(gè)月由于 RSS 非 RDF 變體的一個(gè)新版本的出現使得兩者之間的競爭進(jìn)一步加劇,這一新版本被它的創(chuàng )造者稱(chēng)之為“RSS 2.0”。 RSS 0.91 和 1.0 非常流行,并且許許多多的門(mén)戶(hù)網(wǎng)站和 Web 日志都使用它們。事實(shí)上,blogging 社區是 RSS 的主要用戶(hù),而 RSS 就是某些現有的用于 XML 交換的網(wǎng)絡(luò )令人印象深刻的理由。這些網(wǎng)絡(luò )已在有機地增長(cháng),并且真正地成為現有的最成功的 XML 服務(wù)的網(wǎng)絡(luò )。RSS 成為一種 XML 服務(wù)是因為它被通過(guò)網(wǎng)際協(xié)議交換 XML 信息(絕大多數的 RSS 交換是 RSS 文檔的簡(jiǎn)單 HTTP GET)。在本文中,我們介紹的不過(guò)是許多可以與 RSS 一起工作的 Python 工具中的少數幾個(gè)。我們不提供針對 RSS 的技術(shù)上的介紹,因為您可以在其他許多的文章中獲得這些內容。(請參閱 參考資料)。我們推薦您首先簡(jiǎn)單地熟悉一下 RSS 知識,并且能了解 XML。您不需要去了解 RDF。 [ 由于 RSS 使用了 XML 描述而沒(méi)有使用 WSDL,所以我們將 RSS 作為一個(gè)“XML 服務(wù)”而不是一個(gè)“Web 服務(wù)”對待。- 編者按 ] RSS.py Mark Nottingham 編寫(xiě)的 RSS.py 是用于 RSS 處理的一個(gè) Python 庫。它非常完善并且編寫(xiě)的很好。它需要 Python 2.2 和 PyXML 0.7.1。它的安裝是非常簡(jiǎn)單;您只需從 Mark 的主頁(yè)中下載 Python 文件并將它復制到您的 PYTHONPATH 中的某處。 大多數 RSS.py 的用戶(hù)本身只需要關(guān)心它所提供的兩個(gè)類(lèi): CollectionChannel 和 TrackingChannel 。后者似乎是這兩個(gè)類(lèi)中更有用的一個(gè)。 TrackingChannel 是一個(gè)包含以每一項的關(guān)鍵字為索引的所有的 RSS 數據的數據結構。 CollectionChannel 是一個(gè)類(lèi)似的數據結構,但它的結構更像 RSS 文檔本身,它的頂層通道信息使用 URL 表示的散列值指向項細節。您很可能會(huì )使用 RSS.ns 結構中的實(shí)用程序名稱(chēng)空間聲明。 清單 1是一個(gè)簡(jiǎn)單的腳本,它將下載并解析用于 Python 新聞的 RSS 供給,并以一個(gè)簡(jiǎn)單的清單形式打印來(lái)自各項的所有信息。 清單 1:使用 RSS.py 的一個(gè)簡(jiǎn)單練習 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)") | 我們從創(chuàng )建一個(gè) TrackingChannel 實(shí)例開(kāi)始,并且將從 http://www.python.org/channews.rdf 上的 RSS 供給解析得到的數據填入其中。RSS.py 使用元組作為 RSS 數據的屬性名稱(chēng)。對于那些不習慣 XML 處理技術(shù)的人來(lái)說(shuō),這種方式看上去也許不太尋常,但它對于精確了解原始的 RSS 文件中的內容的確是一種很有效的方式。因此,一個(gè) RSS 0.91 title 元素被認為不同于一個(gè) RSS 1.0 中的同名元素。應用程序有足夠的數據來(lái)忽略這個(gè)差異,如果您愿意,可以通過(guò)忽略每個(gè)元組的名稱(chēng)空間的部分來(lái)忽略這個(gè)差異;但基本的 API 是與初始 RSS 文件的語(yǔ)法相結合的,所以這個(gè)信息沒(méi)有丟失。在代碼中,我們使用這個(gè)屬性數據來(lái)聚集用于顯示的新聞供給中的所有項。請注意,我們很仔細地不去假定任何特殊 的項可能會(huì )有什么屬性。我們使用如下代碼所示的安全的形式來(lái)檢索屬性。 print "Title:", item_data.get(RSS10_TITLE, "(none)") | 如果沒(méi)有找到該屬性則它會(huì )提供一個(gè)缺省值,而不是這個(gè)示例。 print "Title:", item_data[RSS10_TITLE] | 由于您不可能會(huì )知道 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) | 當然,你可能會(huì )遇到稍微有些不同的輸出,這是因為在您對它進(jìn)行試驗時(shí)新聞項可能已經(jīng)更改了。RSS.py 通道對象也提供方法來(lái)添加并修改 RSS 信息。您可以使用 output() 方法將結果寫(xiě)回 RSS 1.0 格式。通過(guò)將在 清單 1 中解析的信息寫(xiě)回去來(lái)對它進(jìn)行試驗。在交互式模式下通過(guò)運行 python -i listing1.py 來(lái)啟動(dòng)腳本。在產(chǎn)生的 Python 提示符下,運行以下示例。 >>> result = tc.output(items) >>> print result | 結果是一個(gè)打印輸出的 RSS 1.0 文檔。為了它能工作您必須有 RSS.py,版本 0.42 或者更高的版本。較早版本中的 output() 方法中有一個(gè)錯誤。
rssparser.py Mark Pilgrim 為 RSS 文件解析提供了另一個(gè)模塊。它并不提供 RSS.py 所提供的所有的功能部件和選項,但它卻提供了一個(gè)非常自由的解析器,它能很好的處理 RSS 世界中所有令人混亂的差異。以下摘自 rssparser.py 頁(yè)面: 如您所見(jiàn),大多數 RSS 供給都很糟糕。無(wú)效的字符、未轉義的 & 符號(Blogger 供給)、無(wú)效的實(shí)體(Radio 供給)和未轉義以及無(wú)效的 HTML(通常為注冊中心所提供的)?;蛘咧皇?RSS 0.9x 元素和 RSS 1.0 元素的一個(gè)籠統的混合(可移動(dòng)類(lèi)型供給(Movable Type feeds))。 還 有許多太前沿的供給,就象 Aaron 的 feed。他將一個(gè)摘錄放入描述元素中而將完整的文本放入 content:encoded 元素中(象 CDATA)。這是一個(gè)有效的 RSS 1.0,但沒(méi)有人回真正使用它(除了 Aaron),幾乎沒(méi)有新聞聚集器支持它,并且許多解析器還排斥它。其他解析器被 RSS 0.94 中的新元素(guid)所困惑(請參閱 Dave Winer 的供給作為一個(gè)示例)。還有 Jon Udell 的供給,其中還有他才從創(chuàng )作中挑選出來(lái)的 fullitem 元素。 XML 和 Web 服務(wù)會(huì )增加互操作性幾乎已成定局,所以這樣考慮其實(shí)很可笑。無(wú)論如何,設計 rssparser.py 目的就是要處理所有這些荒唐的情況。 安裝 rssparser.py 也十分簡(jiǎn)單。請您下載 Python 文件(參閱參考資料),將“rssparser.py.txt”重命名為 “rssparser.py”,并將它復制到您的 PYTHONPATH 中。我同樣建議您取得可選的 timeoutsocket 模塊,它可以改進(jìn) Python 中的套接字操作的超時(shí)行為,這樣有助于取得 RSS feeds 而不必為了防止錯誤就停止應用程序線(xiàn)程。 清單 3是一個(gè)等同于 清單 1的腳本,但它使用了 rssparser.py,而不是 RSS.py。 清單 3:使用一個(gè)簡(jiǎn)單的 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)") | 如 您所見(jiàn),這段代碼非常簡(jiǎn)單。RSS.py 和 rssparser.py 不能互相取代在很大程度上是因為前者有更多的功能部件,并且維護著(zhù) RSS 供給中更多的語(yǔ)法信息。后者更簡(jiǎn)單,并且是一個(gè)容錯能力更強的解析器(RSS.py 解析器只能接受格式良好的 XML)。 它的輸出應該與 清單 2中的輸出相同。
結束語(yǔ) 用于 RSS 的 Python 工具有許多,并且由于篇幅所限我們也無(wú)法一一介紹。如果您想要研究其他的模塊,Aaron Swartz 的 RSS 工具頁(yè)面是一個(gè)起步的好地方。在 Python 中使用 RSS 非常容易,因為它可以使用所有的重要模塊。這些模塊屏蔽了由 RSS 的歷史和流行帶來(lái)的所有混亂。如果您的 XML 服務(wù)需求大部分都涉及到交換 Web 站點(diǎn)的描述性信息,我們極力推薦您在工作中使用最成功的 XML 服務(wù)技術(shù)。 下個(gè)月,我們將解釋如何使用 Python 的 e-mail 包來(lái)編寫(xiě) SMTP 上的 Web 服務(wù)。
參考資料 |