如何使用XPath选择特定的标签和文本?

0 投票
3 回答
925 浏览
提问于 2025-04-16 15:32

比如说,有一个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', ')']

撰写回答