Python 使用lxml解析RSS时出现编码错误

Python 使用lxml解析RSS时出现编码错误,python,rss,lxml,scraperwiki,chardet,Python,Rss,Lxml,Scraperwiki,Chardet,我想用lxml解析下载的RSS,但我不知道如何处理UnicodeDecodeError request = urllib2.Request('http://wiadomosci.onet.pl/kraj/rss.xml') response = urllib2.urlopen(request) response = response.read() encd = chardet.detect(response)['encoding'] parser = etree.XMLParser(ns_cle

我想用lxml解析下载的RSS,但我不知道如何处理UnicodeDecodeError

request = urllib2.Request('http://wiadomosci.onet.pl/kraj/rss.xml')
response = urllib2.urlopen(request)
response = response.read()
encd = chardet.detect(response)['encoding']
parser = etree.XMLParser(ns_clean=True,recover=True,encoding=encd)
tree = etree.parse(response, parser)
但我有一个错误:

tree   = etree.parse(response, parser)
File "lxml.etree.pyx", line 2692, in lxml.etree.parse (src/lxml/lxml.etree.c:49594)
  File "parser.pxi", line 1500, in lxml.etree._parseDocument (src/lxml/lxml.etree.c:71364)
  File "parser.pxi", line 1529, in lxml.etree._parseDocumentFromURL (src/lxml/lxml.etree.c:71647)
  File "parser.pxi", line 1429, in lxml.etree._parseDocFromFile (src/lxml/lxml.etree.c:70742)
  File "parser.pxi", line 975, in lxml.etree._BaseParser._parseDocFromFile (src/lxml/lxml.etree.c:67
740)
  File "parser.pxi", line 539, in lxml.etree._ParserContext._handleParseResultDoc (src/lxml/lxml.etr
ee.c:63824)
  File "parser.pxi", line 625, in lxml.etree._handleParseResult (src/lxml/lxml.etree.c:64745)
  File "parser.pxi", line 559, in lxml.etree._raiseParseError (src/lxml/lxml.etree.c:64027)
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc5 in position 97: ordinal not in range(128)

您可能只应该尝试将字符编码定义为最后的手段,因为很清楚编码是基于XML prolog的(如果不是通过HTTP头)。无论如何,除非您想覆盖编码,否则没有必要将编码传递到
etree.XMLParser
;所以去掉
编码
参数,它应该可以工作

编辑:好的,问题实际上似乎出在
lxml
上。无论出于何种原因,以下工作:

parser = etree.XMLParser(ns_clean=True, recover=True)
etree.parse('http://wiadomosci.onet.pl/kraj/rss.xml', parser)

首先为lxml库加载和排序字符串,然后对其调用fromstring,通常比依赖lxml.etree.parse()函数和难以管理的编码选项更容易

这个特定的rss文件以编码声明开始,所以一切都应该正常工作:

<?xml version="1.0" encoding="utf-8"?>

下面的代码显示了一些不同的变体,您可以应用这些变体来对不同的编码进行etree解析。您还可以请求它写出不同的编码,这些编码将出现在标题中

import lxml.etree
import urllib2

request = urllib2.Request('http://wiadomosci.onet.pl/kraj/rss.xml')
response = urllib2.urlopen(request).read()
print [response]
        # ['<?xml version="1.0" encoding="utf-8"?>\n<feed xmlns=... <title>Wiadomo\xc5\x9bci...']

uresponse = response.decode("utf8")
print [uresponse]    
        # [u'<?xml version="1.0" encoding="utf-8"?>\n<feed xmlns=... <title>Wiadomo\u015bci...']

tree = lxml.etree.fromstring(response)
res = lxml.etree.tostring(tree)
print [res]
        # ['<feed xmlns="http://www.w3.org/2005/Atom">\n<title>Wiadomo&#347;ci...']

lres = lxml.etree.tostring(tree, encoding="latin1")
print [lres]
        # ["<?xml version='1.0' encoding='latin1'?>\n<feed xmlns=...<title>Wiadomo&#347;ci...']


# works because the 38 character encoding declaration is sliced off
print lxml.etree.fromstring(uresponse[38:])   

# throws ValueError(u'Unicode strings with encoding declaration are not supported.',)
print lxml.etree.fromstring(uresponse)
导入lxml.etree
导入urllib2
请求=urllib2。请求('http://wiadomosci.onet.pl/kraj/rss.xml')
response=urllib2.urlopen(request).read()
打印[答复]

# ['\n我遇到了类似的问题,结果证明这与编码无关。发生的情况是-lxml向您抛出了一个完全不相关的错误。在这种情况下,错误是.parse函数需要一个文件名或URL,而不是包含内容本身的字符串。但是,当它试图打印错误时,它会阻塞非ascii字符,显示完全混淆的错误消息。非常不幸,其他人在此处对此问题发表了评论:

幸运的是,您的解决方案非常简单。只需将.parse替换为.fromstring,您就完全可以开始了:

request = urllib2.Request('http://wiadomosci.onet.pl/kraj/rss.xml')
response = urllib2.urlopen(request)
response = response.read()
encd = chardet.detect(response)['encoding']
parser = etree.XMLParser(ns_clean=True,recover=True,encoding=encd)

## lxml Y U NO MAKE SENSE!!!
tree = etree.fromstring(response, parser)

刚刚在我的机器上测试过,效果很好。希望能有所帮助!

在没有编码参数的情况下运行脚本时仍然会出现相同的错误…;/。尽管通过了正确的编码,为什么etree.XMLParser仍会出错?它现在可以工作了,但我必须将lxml升级到2.2.8版本,因为使用2.2.4我无法解析远程URL。而且当我改变这一点时,我问题中的代码就起作用了:tree=etree.parse(StringIO.StringIO(response),parser)先生,愿你们的日子永远美丽和谐!