RSS订阅现在可以说是非常普遍了,可是你知道RSS文件怎么解析吗,今天从3个不同的版本用python给大家了解下如何解析。
1.先从RSS 0.9X和2.0开始:
下面是一个元素包装类,它允许您使用Python的标准属性访问语法从元素中提取字符数据:
class Wrapper: def __init__(self, ele): self._element = ele def __getattr__(self, tag): if tag.startswith("__"): raise AttributeError(tag) return self._element.findtext(tag)
注意,包装器对于缺少的属性/子元素返回None,除非属性名以两个下划线开头
例如,如果是一个包含RSS 2.0树的元素,那么下面的代码将打印所有条目的标题和链接值:
for item in feed.findall("channel/item"): item = Wrapper(item) print(repr(item.title), item.link)
这是一个包含整个RSS树的子类。这个类允许您迭代项目,并使用属性访问来获取通道级别的元素:
class RSSWrapper(ElementWrapper): def __init__(self, feed): channel = feed.find("channel") ElementWrapper.__init__(self, channel) self._items = channel.findall("item") def __getitem__(self, index): return ElementWrapper(self._items[index])
演示下如何使用使用包装器和urllib模块来获取和解析RSS提要的简短脚本:
from urllib import urlopen from elementtree import ETree URL = "http://xxx.com/rss.xml" tree = ETree.parse(urlopen(URL)) feed = RSSWrapper(tree.getroot()) print("FEED", repr(feed.title)) for item in feed: print("ITEM", repr(item.title), item.link)
然后是RSS 1.0
第1部分中的RSSWrapper类支持RSS 0.9x和2.0。还有第三种RSS格式RSS 1.0,它基于RDF,只是存储频道和条目信息不同。
还有与其他RSS变体不同,item元素是channel元素的兄弟元素,而不是子元素。
为了处理名称空间,我向ElementWrapper类添加了一个xs参数。如果提供该参数,则在访问属性时使用该参数作为名称空间前缀:
class ElementWrapper: def __init__(self, element, xs=None): self._xs = xs or "" self._element = element def __getattr__(self, tag): if tag.startswith("__"): raise AttributeError(tag) return self._element.findtext(self._xs + tag)
此外,RSSWrapper类需要检查顶层元素,并根据实际RSS版本设置命名空间和条目列表:
XS_RDF = "{****}" XS_RSS = "{****}" class RSSWrapper(Wrapper): def __init__(self, feed): xs = None if feed.tag == XS_RDF + "RDF": xs = XS_RSS items = feed.findall(XS_RSS + "item") channel = feed.find(XS_RSS + "channel") else: items = channel.findall("item") channel = feed.find("channel") Wrapper.__init__(self, channel, xs) self._items = items def __len__(self): return len(self._items) def __iter__(self): return iter([self[i] for i in range(len(self))]) def __getitem__(self, index): return Wrapper(self._items[index], self._xs)
我们只需要支持两种类似的格式,检查构造函数中的不同类型就可以很好地工作,但这不是一个非常可扩展的设计。
RSS 0.9
与1.0一样,0.90格式基于RDF,但它为RSS元素使用了不同的名称空间。要区分格式,可以检查channel元素的名称空间:
XS_RSS_0_9 = "{****}" XS_RSS_1_0 = "{****}" def getfeed(path): tree = ETree.parse(urlopen(path)) feed = tree.getroot() if feed.tag == XS_RDF + "RDF": for elem in feed: if elem.tag.endswith("channel"): if elem.tag.startswith(XS_RSS_0_9): return RSS0Wrapper(feed) if elem.tag.startswith(XS_RSS_1_0): return RSS1Wrapper(feed) elif feed.tag == "rss": return RSS2Wrapper(feed) raise IOError("unknown feed format")
这种方法的缺点是不能检查实例类型来查看你有的提要类型,也有人认为这是一种优势,并且如果需要扩展包装器接口时,没有地方可以放置特定于版本的代码。
版权所属,如需转载,请注明出处:搜闲鱼