如何在Python中解析GB2312编码的RSS
我有一个用GB2312编码的RSS源。
当我尝试用下面的代码来解析它时:
for item in XML.ElementFromURL(feed).xpath('//item'):
title = item.find('title').text
但是它无法解析这个源。
有没有什么办法可以解析GB2312编码的RSS源呢?
下面是使用下面编码后,Plex媒体服务器的错误日志:
for item in XML.ElementFromURL(feed, encoding='gb2312').xpath('//item'):
title = item.find('title').text
:
***Error Log:***
> File "C:\Documents and Settings\subhendu.swain\Local Settings\Application Data\Plex Media Server\Plug-ins\Zaobao.bundle\Contents\Code\__init__.py", line 24, in GetDetails
for item in XML.ElementFromURL(feed, encoding='gb2312').xpath('//item'):
File "C:\Documents and Settings\subhendu.swain\Local Settings\Application Data\Plex Media Server\Plug-ins\Framework.bundle\Contents\Resources\Versions\2\Python\Framework\api\parsekit.py", line 81, in ElementFromURL
return self.ElementFromString(self._core.networking.http_request(url, values, headers, cacheTime, autoUpdate, encoding, errors, immediate=True, sleep=sleep, opener=self._opener, txn_id=self._txn_id).content, isHTML=isHTML)
File "C:\Documents and Settings\subhendu.swain\Local Settings\Application Data\Plex Media Server\Plug-ins\Framework.bundle\Contents\Resources\Versions\2\Python\Framework\api\parsekit.py", line 76, in ElementFromString
return self._core.data.xml.from_string(string, isHTML)
File "C:\Documents and Settings\subhendu.swain\Local Settings\Application Data\Plex Media Server\Plug-ins\Framework.bundle\Contents\Resources\Versions\2\Python\Framework\components\data.py", line 134, in from_string
return etree.fromstring(markup)
File "lxml.etree.pyx", line 2532, in lxml.etree.fromstring (src/lxml/lxml.etree.c:48270)
File "parser.pxi", line 1545, in lxml.etree._parseMemoryDocument (src/lxml/lxml.etree.c:71812)
File "parser.pxi", line 1424, in lxml.etree._parseDoc (src/lxml/lxml.etree.c:70673)
File "parser.pxi", line 938, in lxml.etree._BaseParser._parseDoc (src/lxml/lxml.etree.c:67442)
File "parser.pxi", line 539, in lxml.etree._ParserContext._handleParseResultDoc (src/lxml/lxml.etree.c:63824)
File "parser.pxi", line 625, in lxml.etree._handleParseResult (src/lxml/lxml.etree.c:64745)
File "parser.pxi", line 565, in lxml.etree._raiseParseError (src/lxml/lxml.etree.c:64088)
XMLSyntaxError: switching encoding: encoder error, line 1, column 36
2011-09-28 09:34:33,453 (9d0) : DEBUG (core) - Response: 404
2 个回答
你的错误信息是 XMLSyntaxError: switching encoding: encoder error, line 1, column 36
。你在寻求建议。这里有个新主意:告诉我们“第一行”大约前50个字节的内容。这样可能有人能帮你找到解决办法。
更新:编码声明不正确。数据并不是用 gb2312
编码的。它至少是 GBK,也就是 cp936。GB2312-80(80是指1980年)是一个有限的字符集。那些不使用 UTF-8 的中文网站,至少会使用更全面的 GBK(已经使用超过10年),并且正在向更高级的 GB18030(它本身就是一种 UTF 编码)过渡。请看下面:
[Python 2.7.1]
>>> import urllib
>>> url = "http://www.zaobao.com/sp/sp.xml"
>>> data = urllib.urlopen(url).read()
>>> len(data)
10071
>>> data[:100]
'<?xml version="1.0" encoding="GB2312"?>\n\n<rss version="2.0"\n>\n\n<channel>\n<title>\xc1\xaa\xba\xcf\xd4\xe7\xb1\xa8\xcd\xf8 zaobao.co'
>>> x = data.decode('gb2312')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'gb2312' codec can't decode bytes in position 1771-1772: illegal multibyte sequence
>>> data[1771:1773]
'\x95N'
>>> x = data.decode('utf8')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "C:\python27\lib\encodings\utf_8.py", line 16, in decode
return codecs.utf_8_decode(input, errors, True)
UnicodeDecodeError: 'utf8' codec can't decode byte 0xc1 in position 80: invalid start byte
>>> x = data.decode('gbk')
>>> y = data.decode('cp936')
>>> x == y
True
我建议你尝试 XML.ElementFromURL(feed, encoding='gbk')
。
如果这样可以工作,你可能想要让你的代码更稳健,以防这个并不罕见的问题。你可以用 urllib 读取数据,检查是否是 gb2312
,如果发现是,就用 gb18030
替代。
更新2:如果有人提到 chardet
:由于 GBK 使用了 GB2312 中许多未使用的字符位置,而 chardet 不会在实际使用的字符位置上工作,也不尝试通过试解码来验证其答案,因此 chardet 会错误地猜测为 GB2312。
我猜你是在使用Plex XML API。文档里提到,如果你确定使用的编码是GB2312,可以调用XML.ElementFromURL(feed, encoding='gb2312')
。
如果这个XML确实是用GB2312编码的,那么它的声明部分应该是<?xml version="1.0" encoding="gb2312"?>
(或者如果是UTF-16编码的话,应该以字节顺序标记开头)。否则,这个XML就是无效的。如果XML声明里没有encoding
,也没有字节顺序标记,解析器默认会认为是UTF-8编码,因此在没有encoding
声明的情况下,使用其他字符编码的XML就是无效的。既然不指定编码会导致你出错,我觉得可能是这个RSS源不是有效的XML。