Python编码ValueError消息

时间:2014-10-15 17:29:39

标签: python html lxml

我正在运行以下网络抓取器代码:

 25 # save source page and return xpath tree
 26 def scrape_Page(url, path):
 27     page = requests.get(url)
 28     tree = html.fromstring(page.text)
 29     # save html content
 30     file_name = url.split('/')[-1] + ".html"
 31     with open(os.path.join(path, file_name), 'wb') as srcFile:
 32         webPage = urllib.urlopen(url)
 33         wPageSrc = webPage.read()
 34         webPage.close()
 35         # write to text file
 36         srcFile.write(wPageSrc)
 37     return tree

这段代码适用于某些网址,但对其他网址却很失败,而且这里有我收到的错误消息:

tree = html.fromstring(page.text)
  File "/Library/Python/2.7/site-packages/lxml/html/__init__.py", line 669, in fromstring
    doc = document_fromstring(html, parser=parser, base_url=base_url, **kw)
  File "/Library/Python/2.7/site-packages/lxml/html/__init__.py", line 563, in document_fromstring
    value = etree.fromstring(html, parser, **kw)
  File "lxml.etree.pyx", line 2993, in lxml.etree.fromstring (src/lxml/lxml.etree.c:62433)
  File "parser.pxi", line 1584, in lxml.etree._parseMemoryDocument (src/lxml/lxml.etree.c:91750)
ValueError: Unicode strings with encoding declaration are not supported. Please use bytes input or XML fragments without declaration.

1 个答案:

答案 0 :(得分:0)

tl; dr:使用html.fromstring(r.content)

有关详细信息,请参阅Python unicode strings下的lxml文档:

  

... lxml.etree中的解析器可以直接处理unicode字符串...但是,这需要unicode字符串本身不指定冲突的编码,因此谎言他们的实际编码...同样,当你尝试时会出现错误与unicode字符串中的HTML数据相同,该字符串在标头的元标记中指定字符集。您通常应该避免在将XML / HTML数据传递到解析器之前将其转换为unicode。它既慢又容易出错。

同时,如果您查看requests文档,请Response Content下:

  

请求将自动解码服务器中的内容。大多数unicode字符集都是无缝解码的...当您发出请求时,Requests会根据HTTP标头对响应的编码进行有根据的猜测。访问r.text时会使用请求猜到的文本编码。

因此,将这些放在一起,你永远不应该调用html.fromstring(page.text),因为page.text会自动解码为Unicode,lxml不需要Unicode。 lxml想要的是原始的未解码字节。

如何从requests中获取原始未解码的字节?请查看requests文档的下一部分Binary Response Content

  

对于非文本请求,您还可以以字节形式访问响应正文... r.content

如果你不理解Unicode字符串和字节字符串之间的区别,以及所有这些解码废话的含义,那么文档中的Unicode HOWTO就有了很好的解释。但基本上:网络套接字(和文件,以及许多其他东西)只以字节为单位,这意味着它们只能处理256个不同的值,但是有数十万个字符。你怎么处理那件事呢?您选择一种编码,使用它将Unicode文本转换为字节序列,通过线路发送,然后在另一端解码。这意味着您需要某种方式来指定您选择的编码,以便另一方可以对其进行解码。网页通常在标题中指定它,尽管还有其他一些方法可以做到。 requests试图变得聪明并为您挖掘信息并负责解码,因此您不必考虑它,这通常非常酷。不幸的是,lxml 试图变得聪明并为你找出解码,如果他们都试图这样做,他们就会互相混淆。