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

时间:2010-09-10 10:51:59

标签: python html-parsing lxml elementtree

假设我有这种HTML,我需要使用lxml / ElementTree选择“text2”:

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

如果我已经将div元素作为mydiv,那么mydiv.text只返回“text1”。

使用itertext()似乎有问题或者说很麻烦,因为它遍历div下的整个树。

是否有任何简单/优雅的方法从元素中提取非第一个文本块?

4 个答案:

答案 0 :(得分:12)

嗯,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']

答案 1 :(得分:6)

此类文字将位于元素子元素的tail属性中。如果您的元素位于elem,那么:

elem[0].tail

会为您提供元素中第一个孩子的尾部文本,在您的情况下为您要找的"text2"

答案 2 :(得分: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]

我没有使用普通的旧stdlib ElementTree测试它,但它也应该使用它。 (只有在我看到Shane Holloway特定于lxml的解决方案后才出现的东西)我更喜欢LXML,因为它更好地支持HTML的同步性,我通常已经安装了lxml.html.clean

答案 3 :(得分:1)

使用node.text_content()将节点下的所有文本作为单个字符串。