Как разобрать RSS с кодировкой GB2312 в Python
У меня есть RSS канал, который закодирован в GB2312
Когда я пытаюсь разобрать его, используя следующий код:
for item in XML.ElementFromURL(feed).xpath('//item'):
title = item.find('title').text
Он не может разобрать ленту новостей.
Любая идея, как разобрать кодированную RSS-ленту GB2312
Журнал ошибок от Plex Media Server ниже после использования кодировки, как показано ниже
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 ответа
Я предполагаю, что вы используете Plex XML API. В документации указано, что вы можете позвонить XML.ElementFromURL(feed, encoding='gb2312')
если вы знаете, что это действительно используемая кодировка.
Если XML действительно закодирован с помощью GB2312, то объявление должно быть <?xml version="1.0" encoding="gb2312"?>
(или начинаться с метки порядка байтов для UTF-16), иначе XML является недействительным. Если нет encoding
в объявлении XML и без знака порядка байтов парсеры должны принять кодировку UTF-8 по умолчанию, и поэтому недопустимо использовать любую другую кодировку символов для XML без encoding
в декларации. Поскольку не указание кодировки приводит к ошибке для вас, я думаю, что возможно, что RSS-канал не является допустимым XML.
Ваше сообщение об ошибке XMLSyntaxError: switching encoding: encoder error, line 1, column 36
, Вы просили идеи. Вот новая идея: расскажите нам, что находится в первых 50 или около того байтах "строки 1". Тогда кто-то может найти лекарство.
Обновление: объявление кодировки неверно. Данные НЕ кодируются в gb2312
, Это как минимум GBK aka 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 не работает с фактически используемыми слотами и не пытается проверить свой ответ путем пробного декодирования, Chart догадывается о GB2312.