为什么lxml有时会在Python中吐出错误(但不常见)?

时间:2013-05-27 01:23:56

标签: python web-scraping urllib2 lxml elementtree

我经常在Python中使用lxml模块从一些网站上抓取数据,我对这个模块感到很满意。但是,当我尝试刮擦时,有时我会在lxml.etree.XMLSyntaxError: AttValue: " or ' expected电话上遇到etree.fromstring()错误,但通常不会。我无法澄清我多长时间看到这个错误,但我认为有几千甚至几万次,我遇到了错误。当我在错误发生后立即运行完全相同的脚本并且脚本停止时,我没有看到错误并且脚本按预期运行良好。为什么吐出一个偶然的错误?有什么方法可以解决这个问题吗?我在实例化urllib2.urlopen()函数时遇到了类似的问题,但由于我最近没有看到urllib2的错误,我现在无法写出来自它的确切错误消息。

感谢。

2 个答案:

答案 0 :(得分:2)

网站是用(通常是无效的)HTML编写的,而不是XML。您不应该将HTML视为XML。

使用lxml's HTML parser,您的问题就会消失:

import urllib2
from lxml import etree

parser = etree.HTMLParser()
tree = etree.parse(urllib2.urlopen(url), parser)

如果在尝试读取无效的HTML时发现lxml仍然会窒息,则必须找到更宽松的解析器。使用BeautifulSoup的html5lib是Python中最宽松(也是最慢)的HTML解析器:

from bs4 import BeautifulSoup

soup = BeautifulSoup(urllib2.urlopen(url), 'html5lib')

答案 1 :(得分:1)

我还遇到了lxml的iterparse()偶尔会以非常不可预测的模式抛出AttValue: ' expected的问题。我知道我发送的XML是有效的,并且重新运行相同的脚本通常会使它工作(或者在完全不同的点上失败)。

最后,我设法创建了一个我可以重新运行的测试用例,它会立即在看似随机的结果中完成或引发AttValue错误。这就是我做错了:

我对iterparse()的输入是我自己编写的类似文件的对象(我正在处理来自请求的HTTP响应流,但必须先将其解压缩)。在编写read()方法时,我作弊并忽略了size参数。相反,我只需解压缩一大块固定大小的压缩字节,并返回解压缩的任何字节序列 - 通常比32k lxml请求多得多!
我怀疑这导致缓冲区溢出lxml内部,这导致了上述问题。一旦我停止返回比请求的lxml更多的字节,这些随机错误就会消失。