使用 XPath,select 没有文本兄弟的节点

Using XPath, select node without text sibling

我想用 python3 和 lxml 提供的 HTML 解析器提取一些 HTML 元素。

考虑这个 HTML:

<!DOCTYPE html>
<html>
  <body>
    <span class="foo">
      <span class="bar">bar</span>
      foo
    </span>
  </body>
</html>

考虑这个程序:

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from lxml import html
tree = html.fromstring('html from above')
bars = tree.xpath("//span[@class='bar']")
print(bars)
print(html.tostring(bars[0], encoding="unicode"))

在浏览器中,查询 select 或 "span.bar" select 只是 span 元素。这就是我想要的。但是,上述程序产生:

[<Element span at 0x7f5dd89a4048>]
<span class="bar">bar</span>foo

看起来我的 XPath 实际上并不像查询 selector 并且在 span 元素旁边拾取同级文本节点。如何将 XPath 调整为 select 只有栏元素,而不是文本 "foo"?

请注意 lxml(以及标准模块 xml.etree)中的 XML 树模型具有 tail 的概念。因此 位于 a.k.a following-sibling 之后 元素的文本节点将存储为该元素的 tail。所以你的 XPath 正确 return span 元素,但根据树模型,它有 tail 包含文本 'foo'.

作为解决方法,假设您不想进一步使用树模型,只需在打印前清除 tail

>>> bars[0].tail = ''
>>> print(html.tostring(bars[0], encoding="unicode"))
<span class="bar">bar</span>