使用lxml / ElementTree获取不连续文本

4 投票
4 回答
4386 浏览
提问于 2025-04-16 03:57

假设我有这样的HTML代码,我需要用lxml / ElementTree来选择“text2”:

<div>text1<span>childtext1</span>text2<span>childtext2</span>text3</div>

如果我已经有了这个div元素,叫做mydiv,那么mydiv.text只会返回“text1”。

使用itertext()方法似乎有点麻烦,因为它会遍历这个div下面的整个树状结构。

有没有什么简单优雅的方法可以从一个元素中提取不是第一个的文本部分呢?

4 个回答

4

正如llasram所说,任何不在text属性中的文本都会出现在子节点的tail属性里。

举个例子,这里有一种最简单的方法来提取一个节点中所有的文本片段(包括第一个和其他的):

html = '<div>text1<span>childtext1</span>text2<span>childtext2</span>text3</div>'

import lxml.html    # ...or lxml.etree as appropriate
div = lxml.html.fromstring(html)

texts = [div.text] + [child.tail for child in div]
# Result: texts == ['text1', 'text2', 'text3']
# ...and you are guaranteed that div[x].tail == texts[x+1]
# (which can be useful if you need to access or modify the DOM)

如果你宁愿牺牲这种关系,以防止texts可能包含空字符串,你可以用这个方法:

texts = [div.text] + [child.tail for child in div if child.tail]

我还没有用普通的标准库ElementTree测试过这个,但它应该也能用。(这是我看到Shane Holloway的lxml特定解决方案后才想到的)我更喜欢LXML,因为它对HTML的一些特殊情况支持得更好,而且我通常已经安装了lxml.html.clean

6

这样的文本会出现在你元素的子元素的 tail 属性中。如果你的元素在 elem 里,那么:

elem[0].tail

这段代码会让你得到该元素第一个子元素的尾部文本,也就是你想要的 "text2"

14

好的,lxml.etree 提供了完整的 XPath 支持,这样你就可以方便地找到文本内容了:

>>> import lxml.etree
>>> fragment = '<div>text1<span>childtext1</span>text2<span>childtext2</span>text3</div>'
>>> div = lxml.etree.fromstring(fragment)
>>> div.xpath('./text()')
['text1', 'text2', 'text3']

撰写回答