通用摘要解析器问题

0 投票
1 回答
1286 浏览
提问于 2025-04-17 20:54

我正在写一个Python脚本,用来解析RSS链接。

我使用了通用Feed解析器,但是在处理一些链接时遇到了问题,比如在解析FreeBSD安全公告时。以下是我的示例代码:

    feed = feedparser.parse(url)
    items = feed["items"]

基本上,feed["items"]应该返回所有的条目,也就是以item开头的字段,但它总是返回空。

我可以确认,以下链接的解析结果是正常的:

这是不是因为FreeBSD的链接不符合标准,导致的问题呢?

编辑:

我使用的是Python 2.7。最后我决定结合使用feedparser和BeautifulSoup,正如Hai Vu所建议的那样。以下是我稍微修改过的示例代码:

def rss_get_items_feedparser(self, webData):
    feed = feedparser.parse(webData)
    items = feed["items"]
    return items

def rss_get_items_beautifulSoup(self, webData):
    soup = BeautifulSoup(webData)
    for item_node in soup.find_all('item'):
        item = {}
        for subitem_node in item_node.findChildren():
            if subitem_node.name is not None:
                item[str(subitem_node.name)] = str(subitem_node.contents[0])
        yield item

def rss_get_items(self, webData):
    items = self.rss_get_items_feedparser(webData)
    if (len(items) > 0):
        return items;
    return self.rss_get_items_beautifulSoup(webData)

def parse(self, url):
        request = urllib2.Request(url)
        response = urllib2.urlopen(request)
        webData = response .read()
        for item in self.rss_get_items(webData):
            #parse items

我还尝试直接将响应传递给rss_get_items,而不先读取它,但当BeautifulSoup尝试读取时,它会抛出一个异常:

  File "bs4/__init__.py", line 161, in __init__
    markup = markup.read()
TypeError: 'NoneType' object is not callable        

1 个回答

1

我发现问题出在使用了 namespace

对于 FreeBSD 的 RSS 源:

<rss xmlns:atom="http://www.w3.org/2005/Atom" 
     xmlns="http://www.w3.org/1999/xhtml" 
     version="2.0">

对于 Ubuntu 的源:

<rss xmlns:atom="http://www.w3.org/2005/Atom" 
     version="2.0">

当我从 FreeBSD 的源中去掉多余的命名空间声明后,一切都正常了。

那么这对你意味着什么呢?我想到几种不同的方法:

  1. 使用其他工具,比如 BeautifulSoup。我试过,似乎可以正常工作。
  2. 下载整个 RSS 源,进行一些搜索和替换来修复命名空间,然后再使用 feedparser.parse()。这种方法有点 hack,不推荐自己使用。

更新

这里有一段 rss_get_items() 的示例代码,它会返回一个 RSS 源中的项目列表。每个项目都是一个字典,包含一些标准的键,比如 title(标题)、pubdate(发布日期)、link(链接)和 guid(唯一标识)。

from bs4 import BeautifulSoup
import urllib2

def rss_get_items(url):    
    request = urllib2.Request(url)
    response = urllib2.urlopen(request)
    soup = BeautifulSoup(response)

    for item_node in soup.find_all('item'):
        item = {}
        for subitem_node in item_node.findChildren():
            key = subitem_node.name
            value = subitem_node.text
            item[key] = value
        yield item

if __name__ == '__main__':
    url = 'http://www.freebsd.org/security/rss.xml'
    for item in rss_get_items(url):
        print item['title']
        print item['pubdate']
        print item['link']
        print item['guid']
        print '---'

输出:

FreeBSD-SA-14:04.bind
Tue, 14 Jan 2014 00:00:00 PST
http://security.FreeBSD.org/advisories/FreeBSD-SA-14:04.bind.asc
http://security.FreeBSD.org/advisories/FreeBSD-SA-14:04.bind.asc
---
FreeBSD-SA-14:03.openssl
Tue, 14 Jan 2014 00:00:00 PST
http://security.FreeBSD.org/advisories/FreeBSD-SA-14:03.openssl.asc
http://security.FreeBSD.org/advisories/FreeBSD-SA-14:03.openssl.asc
---
...

注意事项:

  • 为了简洁,我省略了错误检查。
  • 我建议只有在 feedparser 失败时才使用 BeautifulSoup API。原因是 feedparser 是处理这个任务的合适工具。希望他们将来能更新得更宽容一些。

撰写回答