使用lxml和请求从XPath返回utf-8

米利斯纳

我试图弄清楚我xpath是否正确使用了lxml的功能。这是我当前的代码,包括我们在一个相当大的抓取库中逐渐积累的所有解决方法,该库处理可怕的,可怕的输入:

import certifi, requests
from lxml import html
s = requests.session()
r = s.get(
    url,
    verify=certifi.where(),
    **request_dict
)

# Throw an error if a bad status code is returned.
r.raise_for_status()

# If the encoding is iso-8859-1, switch it to cp1252 (a superset)
if r.encoding == 'ISO-8859-1':
    r.encoding = 'cp1252'

# Grab the content
text = r.text
html_tree = html.fromstring(text)

因此,如果这一切都正常工作,则requests可以r.encoding用来确定调用时如何创建unicode对象r.text伟大的。我们采用该unicode对象(text),然后将其发送到中ltml.html.fromstring(),它识别出它是unicode,并向我们返回ElementTree

一切似乎都工作正常,但令人烦恼的是,当我这样做时:

html_tree.xpath('//text()')[0]

这应该给我树中的第一个文本节点,我得到一个字符串,而不是一个unicode对象,并且我发现自己不得不写:

html_tree.xpath('//text()')[0].decode('utf8')

糟透了

一开始我所做的所有工作的全部想法是创建Mythical Unicode Sandwich,但是无论我做什么,我都会得到二进制字符串。我在这里想念什么?


这是为您提供的概念证明:

import certifi, requests
from lxml import html
s = requests.session()
r = s.get('https://www.google.com', verify=certifi.where())
print type(r.text)  # <type 'unicode'>, GREAT!
html_tree = html.fromstring(r.text)
first_node = html_tree.xpath('//text()', smart_strings=False)[0]
print type(first_node)  # <type 'str'>, TERRIBLE!
米利斯纳

好吧,就像经常发生的那样,我在发布了一个详尽的详细问题后不久就找到了答案。lxml即使您仔细地给它unicode,也返回字节字符串的原因是由于中的性能优化lxml从常见问题解答:

在Python 2中,lxml的API返回用于纯ASCII文本值的字节字符串,无论是用于标记名称还是Element内容中的文本。

原因是ASCII编码的字节字符串与Python 2中的Unicode字符串兼容,但消耗的内存更少(通常是2或4倍),并且由于不需要解码,因此创建速度更快。纯ASCII字符串值在XML中非常常见,因此这种优化通常是值得的。

但是在Python 3中:

lxml总是返回文本和名称的Unicode字符串,ElementTree也是如此。从Python 3.3开始,仅包含可以以ASCII或Latin-1编码的字符的Unicode字符串通常与字节字符串一样有效。在旧版本的Python 3中,存在上述缺点。

所以你有它。这是lxml中的性能优化,使字节和unicode字符串更加混乱。

至少它在Python 3中已修复!是时候升级了。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章