如何使用XPath选择特定的标签和文本?
比如说,有一个HTML块:
<p><b>text1</b> (<span><a href="#1">asdf</a>text2</span>)</p>
我需要选择所有的“a”标签,其他的内容就像我们在浏览器里看到的一样,都是普通文本:
result = ["text1", " (", <tag_a>, "text2", ")"]
或者类似这样的。
我试过:
hxs.select('.//a|text()')
在这种情况下,它找到了所有的“a”标签,但返回的文本只有直接子元素的内容。
同时:
hxs.select('.//text()|a')
获取了所有的文本,但“a”标签只有直接子元素的内容。
更新
elements = []
for i in hxs.select('.//node()'):
try:
tag_name = i.select('name()').extract()[0]
except TypeError:
tag_name = '_text'
if tag_name == 'a':
elements.append(i)
elif tag_name == '_text':
elements.append(i.extract())
有没有更好的方法呢?
3 个回答
1
这些相对的XPath表达式:
.//text()|.//a
或者
.//node()[self::text()|self::a]
意思:从当前节点开始,获取所有的文本节点或a
元素。
注意:节点集的结果是否按照文档顺序排列,取决于使用的语言或XPath引擎。根据定义,节点集是没有顺序的。
1
我觉得你可能已经超出了XPath的范围。XPath擅长从输入中选择内容,但不太适合构建输出。它最初是为了和XSLT一起使用而设计的,XSLT负责处理输出部分。我不太确定在Python中有什么类似的东西。
1
这就是你想要的东西吗?
你可以使用 etree.strip_tags
来去掉这个块里面的子标签。
from lxml import etree
d = etree.HTML('<html><body><p><b>text1</b> (<span><a href="#1">asdf</a>text2</span>)</p></body></html>')
block = d.xpath('/html/body/p')[0]
# etree.strip_tags apparently takes a list of tags to strip, but it wasn't working for me
for tag in set(x.tag for x in block.iterdescendants() if x.tag != 'a'):
etree.strip_tags(block,tag)
block.xpath('./text()|a')
结果是:
['text1', ' (', <Element a at fa4a48>, 'text2', ')']