feedparser在脚本运行时失败,但在交互式Python控制台中无法重现
当我运行Eclipse或者在iPython中执行我的脚本时,它出现了这个错误:
'ascii' codec can't decode byte 0xe2 in position 32: ordinal not in range(128)
我不知道为什么,但当我用同样的URL执行feedparse.parse(url)这条语句时,没有出现错误。这让我很困惑。
代码其实很简单:
try:
d = feedparser.parse(url)
except Exception, e:
logging.error('Error while retrieving feed.')
logging.error(e)
logging.error(formatExceptionInfo(None))
logging.error(formatExceptionInfo1())
这是错误的详细信息:
d = feedparser.parse(url)
File "C:\Python26\lib\site-packages\feedparser.py", line 2623, in parse
feedparser.feed(data)
File "C:\Python26\lib\site-packages\feedparser.py", line 1441, in feed
sgmllib.SGMLParser.feed(self, data)
File "C:\Python26\lib\sgmllib.py", line 104, in feed
self.goahead(0)
File "C:\Python26\lib\sgmllib.py", line 143, in goahead
k = self.parse_endtag(i)
File "C:\Python26\lib\sgmllib.py", line 320, in parse_endtag
self.finish_endtag(tag)
File "C:\Python26\lib\sgmllib.py", line 360, in finish_endtag
self.unknown_endtag(tag)
File "C:\Python26\lib\site-packages\feedparser.py", line 476, in unknown_endtag
method()
File "C:\Python26\lib\site-packages\feedparser.py", line 1318, in _end_content
value = self.popContent('content')
File "C:\Python26\lib\site-packages\feedparser.py", line 700, in popContent
value = self.pop(tag)
File "C:\Python26\lib\site-packages\feedparser.py", line 641, in pop
output = _resolveRelativeURIs(output, self.baseuri, self.encoding)
File "C:\Python26\lib\site-packages\feedparser.py", line 1594, in _resolveRelativeURIs
p.feed(htmlSource)
File "C:\Python26\lib\site-packages\feedparser.py", line 1441, in feed
sgmllib.SGMLParser.feed(self, data)
File "C:\Python26\lib\sgmllib.py", line 104, in feed
self.goahead(0)
File "C:\Python26\lib\sgmllib.py", line 138, in goahead
k = self.parse_starttag(i)
File "C:\Python26\lib\sgmllib.py", line 296, in parse_starttag
self.finish_starttag(tag, attrs)
File "C:\Python26\lib\sgmllib.py", line 338, in finish_starttag
self.unknown_starttag(tag, attrs)
File "C:\Python26\lib\site-packages\feedparser.py", line 1588, in unknown_starttag
attrs = [(key, ((tag, key) in self.relative_uris) and self.resolveURI(value) or value) for key, value in attrs]
File "C:\Python26\lib\site-packages\feedparser.py", line 1584, in resolveURI
return _urljoin(self.baseuri, uri)
File "C:\Python26\lib\site-packages\feedparser.py", line 286, in _urljoin
return urlparse.urljoin(base, uri)
File "C:\Python26\lib\urlparse.py", line 215, in urljoin
params, query, fragment))
File "C:\Python26\lib\urlparse.py", line 184, in urlunparse
return urlunsplit((scheme, netloc, url, query, fragment))
File "C:\Python26\lib\urlparse.py", line 192, in urlunsplit
url = scheme + ':' + url
File "C:\Python26\lib\encodings\cp1252.py", line 15, in decode
return codecs.charmap_decode(input,errors,decoding_table)
部分解决:
当传给feedparser.parse()的URL是Unicode格式时,会出现这个问题。如果是ASCII格式的URL就不会出现。而且需要注意的是,你需要一个包含一些高字符Unicode字符的源。我不太明白为什么会这样。
2 个回答
1
根据提问者的评论:试试任何网址,比如 u'myfeed.blah/xml',应该能重现这个问题。
>>> from pprint import pprint as pp
>>> import feedparser
>>> d = feedparser.parse(u'myfeed.blah/xml')
>>> pp(d)
{'bozo': 1,
'bozo_exception': SAXParseException('not well-formed (invalid token)',),
'encoding': 'utf-8',
'entries': [],
'feed': {},
'namespaces': {},
'version': ''}
>>> d = feedparser.parse(u'http://myfeed.blah/xml')
>>> pp(d)
{'bozo': 1,
'bozo_exception': URLError(gaierror(11001, 'getaddrinfo failed'),),
'encoding': 'utf-8',
'entries': [],
'feed': {},
'version': None}
>>> d = feedparser.parse("http://feedparser.org/docs/examples/atom10.xml")
>>> d['bozo']
0
>>> d['feed']['title']
u'Sample Feed'
>>> d = feedparser.parse(u"http://feedparser.org/docs/examples/atom10.xml")
>>> d['bozo']
0
>>> d['feed']['title']
u'Sample Feed'
>>>
请不要再乱说了;给出一个真正会导致问题的网址。
1
看起来你遇到问题的这个网址里包含了一些编码的文本(比如拉丁-1编码,其中0xe2
表示“上面有个圈的字母a”,也就是â
),但是没有正确的内容类型头(应该在Content-Type:
里有一个charset=参数,但实际上没有)。
如果是这样的话,feedparser
就无法猜测编码,默认使用ascii
,结果就失败了。
feedparser文档的这一部分详细解释了这个问题。
不幸的是,解决这个普遍问题没有什么“灵丹妙药”(因为有些人不遵守XML规则)。你可以尝试捕捉这个异常,然后在处理程序中单独读取网址的内容(使用urllib2
),并尝试用各种可能的编码进行解码——最后当你用这种方式得到了一个可用的unicode对象时,就把这个对象传给feedparser.parse
(它的第一个参数可以是网址、文件流,或者包含数据的unicode字符串)。