lxmlを使用してRSSを解析する際のエラーをエンコードします
-
25-10-2019 - |
質問
ダウンロードしたRSSをLXMLで解析したいのですが、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プロログに基づいていることは明確であるため、おそらく最後の手段としてエンコードするキャラクターを定義しようとする必要があります(HTTPヘッダーによるものではない場合)。 etree.XMLParser
エンコーディングをオーバーライドしたい場合を除きます。したがって、それを取り除きます encoding
パラメーターと機能するはずです。
編集:さて、問題は実際にあるようです lxml
. 。何らかの理由で、次の作品:
parser = etree.XMLParser(ns_clean=True, recover=True)
etree.parse('http://wiadomosci.onet.pl/kraj/rss.xml', parser)
他のヒント
私は同様の問題に遭遇しましたが、これはエンコーディングとは何の関係もないことがわかりました。何が起こっているのかこれは、LXMLがあなたにまったく無関係なエラーを投げかけていることです。この場合、エラーは、.Parse関数がコンテンツ自体を持つ文字列ではなく、ファイル名またはURLを期待することです。ただし、エラーを印刷しようとすると、ASCII以外の文字を窒息させ、完全に混乱するエラーメッセージが表示されます。それは非常に不幸であり、他の人々はここでこの問題についてコメントしています:
https://mailman-mail5.webfaction.com/pipermail/lxml/2009-february/004393.html
幸いなことに、あなたはとても簡単な修正です。 .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)
これを私のマシンでテストしたばかりで、うまくいきました。それが役に立てば幸い!
LXML.etree.parse()関数に依存し、エンコードオプションを管理するのが難しい場合ではなく、最初に文字列をロードしてソートすることができ、次にfromStringを呼び出します。
この特定の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ści...']
lres = lxml.etree.tostring(tree, encoding="latin1")
print [lres]
# ["<?xml version='1.0' encoding='latin1'?>\n<feed xmlns=...<title>Wiadomoś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/#