2011-04-27 98 views
9

我想使用lxml解析下載的RSS,但我不知道如何處理UnicodeDecodeError?使用lxml解析RSS時出現編碼錯誤

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) 

回答

0

你或許應該只試圖定義的字符編碼作爲最後的手段,因爲它是明確的編碼是基於什麼樣的XML序言(如果而不是通過HTTP頭)。無論如何,除非你想重寫編碼,否則不需要將編碼傳遞給etree.XMLParser。所以擺脫encoding參數,它應該工作。

編輯:好的,問題實際上似乎與lxml。下面的作品,無論出於何種原因:

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

當我運行沒有編碼參數...; /的腳本時,仍然有相同的錯誤。爲什麼etree.XMLParser完成錯誤,儘管傳遞正確的編碼? – domi 2011-04-28 00:45:50

+1

它現在正在工作,但我不得不升級lxml到2.2.8版本,因爲2.2.4我無法解析遠程URL。此外,當我改變這個問題時,我的問題的代碼工作:tree = etree.parse(StringIO.StringIO(response),parser) – domi 2011-04-28 20:46:39

4

它往往更容易得到字符串加載並整理出了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) 

代碼可以在這裏嘗試: http://scraperwiki.com/scrapers/lxml_and_encoding_declarations/edit/#

44

我遇到了類似的問題,而且事實證明這無關與編碼。發生了什麼 - lxml正在拋出一個完全不相關的錯誤。在這種情況下,錯誤在於.parse函數需要文件名或URL,而不是包含內容本身的字符串。但是,當它試圖打印出錯誤時,它會窒息非ASCII字符並顯示完全混淆的錯誤消息。這是非常不幸的,其他人紛紛發表意見,在這裏這個問題:

https://mailman-mail5.webfaction.com/pipermail/lxml/2009-February/004393.html

幸運的是,你是一個很容易解決。只是.fromstring取代.parse,你應該完全好走:

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) 

我的機器只是測試這一點,它工作得很好。希望能幫助到你!

+0

parse() - > fromstring()爲我做了訣竅。謝謝! – 2012-03-05 10:18:26

+8

您的日子可能會與永恆的美麗和和諧的祝福! – Art 2012-06-08 11:46:21

+0

你救了我大概一個小時的瘋狂,謝謝 – mottalrd 2012-10-09 14:30:59