假设我有这种HTML,我需要使用lxml / ElementTree选择“text2”:
<div>text1<span>childtext1</span>text2<span>childtext2</span>text3</div>
如果我已经将div元素作为mydiv,那么mydiv.text只返回“text1”。
使用itertext()似乎有问题或者说很麻烦,因为它遍历div下的整个树。
是否有任何简单/优雅的方法从元素中提取非第一个文本块?
答案 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()
将节点下的所有文本作为单个字符串。