【问题标题】:Get second element text with XPath?使用 XPath 获取第二个元素文本?
【发布时间】:2010-11-07 13:39:09
【问题描述】:
<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>

【问题讨论】:

  • 你的表达 .//span[@class="python"]//a[2] 适合我。
  • 嗯,看来我在某处有错误,或者我发布的实际 HTML 的简化简单了。我会尝试然后修改问题。
  • @pdnsk:好问题,+1。请参阅我的答案以获取解释和简单的解决方案。 :)
  • 很高兴您发布了这个问题。大约一天来一直试图找出类似的问题。

标签: python xpath lxml


【解决方案1】:

我试过了,但它不起作用。

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()

【讨论】:

  • 感谢您的解释,但我有一个问题,或者实际上是两个。如果只有一个匹配元素,[2]会抛出异常还是返回None?你知道为什么这适用于xpath 而不是findtext
  • @pdnsk:我的答案是纯 XPath。我不懂 Python。
  • 我试过了,它只是不返回任何元素,这很好,因为我想避免使用列表并将其放在单个表达式中的一个原因是没有额外的检查。
  • 一整天都在试图找出类似的答案。非常感谢您的帮助!
【解决方案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']
>>>

【讨论】:

    【解决方案3】:

    来自评论:

    或实际的简化 我发布的 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]
    

    【讨论】:

    • 它适用于xpath,但不适用于findtext,并返回一个包含一项的列表。
    • @pdknsk:那是因为这个 XPath 表达式返回一个节点集结果:它可能是空的,它可能是一个单例,它可能是多个带有“python”类和第二个后代的跨度。 . 如果您想要第一个结果的字符串值,请使用string() 函数将此表达式作为参数。不知道什么样的数据类型可以返回你的xpath方法...
    • 它有效。我使用了上一个答案、/text() 和这个答案的组合,但我会接受这个答案,因为它详细说明了问题。我只有一个问题。 /descandant:: 的缩写是什么?
    • @pdknsk:首先,text() 将返回所有文本节点子节点。 string() 或字符串值的 DOM 方法将返回所有后代文本节点的连接。 不一样。其次,descendant axe 没有缩写形式。我的最后一个表达式等同于(.//span[@class="python"]//a)[2]?,因此position() 谓词应用于整个表达式,而不仅仅是最后一步。
    猜你喜欢
    • 2022-08-17
    • 2022-12-18
    • 1970-01-01
    • 2022-12-16
    • 2020-03-24
    • 2011-07-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多