我试图弄清楚我是否正确地使用了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')
,这糟透了,
我最初所做工作的全部思想是创建神话中的Unicode三明治,但是无论我做什么,我都会得到二进制字符串。我在这里错过了什么?
以下是你的概念证明:
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!
发布于 2015-07-29 17:00:44
嗯,就像经常发生的那样,我在发布了一个详细的问题后不久就找到了答案。lxml
返回字节字符串的原因--即使您仔细地将它交给unicode --是因为lxml
。从常见问题:
在Python 2中,lxml的API返回普通ASCII文本值的字节字符串,无论是标记名称还是元素内容中的文本。 其原因是,ASCII编码的字节字符串与Python 2中的Unicode字符串兼容,但占用的内存更少(通常是2或4倍),而且创建速度更快,因为它们不需要解码。普通的ASCII字符串值在XML中非常常见,因此这种优化通常是值得的。
然而,在Python 3中:
lxml总是返回文本和名称的Unicode字符串,ElementTree也是如此。自从Python3.3以来,Unicode字符串只包含可以用ASCII或拉丁文-1编码的字符,通常与字节字符串一样有效。在早期版本的Python 3中,上面提到的缺点也适用。
所以你就有了。这是lxml中的性能优化,增加了对字节和unicode字符串的混淆。
至少它是用Python 3修复的!该升级了。
https://stackoverflow.com/questions/31713444
复制相似问题