如何用XPath获取第二个元素的文本?
<span class='python'>
<a>google</a>
<a>chrome</a>
</span>
我想要获取 chrome
,并且希望它能像这样正常工作。
q = item.findall('.//span[@class="python"]//a')
t = q[1].text # first element = 0
我想把它合并成一个单独的XPath表达式,这样就只获取一个项目,而不是一堆列表。
我试过这样做,但没有成功。
t = item.findtext('.//span[@class="python"]//a[2]') # first element = 1
而且实际的HTML内容,没有简化,长这样。
<span class='python'>
<span>
<span>
<img></img>
<a>google</a>
</span>
<a>chrome</a>
</span>
</span>
3 个回答
2
我不太确定问题出在哪里...
>>> d = """<span class='python'>
... <a>google</a>
... <a>chrome</a>
... </span>"""
>>> from lxml import etree
>>> d = etree.HTML(d)
>>> d.xpath('.//span[@class="python"]/a[2]/text()')
['chrome']
>>>
2
来自评论:
或者我发的实际HTML简化得太简单了。
你说得对。那么 .//span[@class="python"]//a[2]
这是什么意思呢?这段代码会被展开成:
self::node()
/descendant-or-self::node()
/child::span[attribute::class="python"]
/descendant-or-self::node()
/child::a[position()=2]
最终它会选择第二个 a
子元素(fn:position()
是指 child
轴)。所以,如果你的文档像这样:
<span class='python'>
<span>
<span>
<img></img>
<a>google</a><!-- This is the first "a" child of its parent -->
</span>
<a>chrome</a><!-- This is also the first "a" child of its parent -->
</span>
</span>
那么就什么都选不到。
如果你想选择所有后代中的第二个,可以使用:
descendant::span[@class="python"]/descendant::a[2]
42
我试过这个,但它不管用。
t = item.findtext('.//span[@class="python"]//a[2]')
这是关于 //
简写的常见问题解答。
.//a[2]
的意思是:选择当前节点下所有的 a
子节点中,第二个 a
的孩子。所以这可能会选择到多个元素,也可能一个都不选,这取决于具体的 XML 文档。
简单来说,[]
这个操作符的优先级比 //
高。
如果你只想要返回的所有节点中的一个(第二个),你需要用括号来强制你想要的优先级:
(.//a)[2]
这样就真的选择了当前节点的第二个 a
子节点。
对于问题中使用的实际表达式,请改成:
(.//span[@class="python"]//a)[2]
或者改成:
(.//span[@class="python"]//a)[2]/text()