【问题标题】:Return utf-8 from XPath using lxml and requests使用 lxml 和请求从 XPath 返回 utf-8
【发布时间】:2015-10-21 04:49:32
【问题描述】:

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

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 来决定在调用r.text 时如何创建一个unicode 对象。伟大的。我们获取该 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!

【问题讨论】:

    标签: xpath unicode utf-8 lxml python-requests


    【解决方案1】:

    嗯,就像经常发生的那样,我在发布了一个长而详细的问题后不久就找到了答案。 lxml 的原因是即使你小心地给它 unicode 也返回字节字符串是因为 a performance optimization in lxml。来自常见问题解答:

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

    原因是 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 中已修复!是时候升级了。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-02-19
      • 2017-03-21
      • 1970-01-01
      • 1970-01-01
      • 2020-06-22
      • 1970-01-01
      • 2021-08-08
      • 1970-01-01
      相关资源
      最近更新 更多