【问题标题】:How to find elements with two possible class names by XPath?如何通过 XPath 查找具有两个可能的类名的元素?
【发布时间】:2016-05-22 13:13:06
【问题描述】:

如何使用XPath 表达式查找具有两个可能类名的元素?

我正在使用 Selenium 使用 Python,我想找到 class 具有两个可能名称之一的所有元素。

  1. class="item ng-scope highlight"
  2. class="item ng-scope"

'//div[@class="list"]/div[@class="item ng-scope highlight"]//h3/a[@class="ng-binding"]'

当然,我可以进行两次单独的搜索并将结果合并到一个列表中。但是有一种更简单有效的方法。也许通过使用|。

【问题讨论】:

  • 好问题 +1。如果你有: class="ng-scope item" 怎么办?这与 class="item ng-scope" 基本相同。对于 class="item ng-scope highlight" 有 6 种可能的排列。您是否想要一个无论可能的排列如何都能选择具有所需类的元素的解决方案?请参阅我的答案以获得解决方案!

标签: python selenium xpath


【解决方案1】:

你可以使用or:

//div[@class="list"]/div[@class="item ng-scope highlight" or @class="item ng-scope"]//h3/a[@class="ng-binding"]

请注意,ng-scope 通常不是一个好依赖的类名,因为它是 Angular 元素所具有的“纯技术”AngularJS 特定类(实际上ng-binding 也是如此)。请查看使用 contains() 并仅检查 item 类是否足以涵盖用例:

//div[@class="list"]/div[contains(@class, "item")]//h3/a[@class="ng-binding"]

仅供参考,请注意 CSS 选择器在您的情况下是多么简洁:

div.list > div.item h3 a

【讨论】:

  • 第二个表达式将匹配“item”,但也将匹配“myitem3”——这是不想要的!第一个表达式只找到“item ng-scope”或“item ng-scope highlight”,不会找到任何排列/重新排序,或者如果class 属性的值中存在任何其他空格。
  • 如果是两个可能的ID而不是类,你必须使用//*[@id="one"] | //*[@id="two"]?
【解决方案2】:

接受的答案基本上不完整!

它的第二个表达式将匹配“item”,但也将匹配“myitem3”——这是不想要的!

它的第一个表达式只找到“item ng-scope”或“item ng-scope highlight”,如果有任何排列/重新排序,或者类属性的值中存在任何其他空格,则不会匹配。

进一步阅读以获得正确的解决方案:

我正在使用 Selenium 在 Python 中工作,我想查找所有元素 哪个类具有两个可能的名称之一。 1.class="item ng-scope 高亮" 2.class="项目范围"

我认为除了这两个之外,您还需要涵盖类属性的值,例如:

“ng-范围项目”

"项目突出显示 ng-scope"

“ng-scope 项目高亮”

“ng-scope 高亮项目”

"高亮项目 ng-scope"

"突出显示 ng-scope 项"

而且,如果在每个空白“部分”中,或者在字符串的左端或右端有可变数量的空格,那么您最终会得到无限的可能性。 . .

另一个松散点是:

类属性的值是否应该(仅)包含那些类名,或者它们是否还允许包含其他类名,除了想要的?

根据上述问题的答案,可以有两种不同的解决方案,提供如下:


我。 class 属性可以包含其他类名,除了想要的:

/div[contains(concat(' ', @class, ' '), ' list ')]
       /div[contains(concat(' ', @class, ' '), ' item ') 
          and contains(concat(' ', @class, ' '), ' ng-scope ')]

二。 class 属性正好/只包含想要的值:

//div[contains(normalize-space(@class) = 'list')]
       /div[contains(concat(' ', @class, ' '), ' item ') 
          and contains(concat(' ', @class, ' '), ' ng-scope ')
          and string-length(normalize-space(@class)) = 13
          or 
            contains(concat(' ', @class, ' '), ' item ') 
            and contains(concat(' ', @class, ' '), ' ng-scope ')
            and contains(concat(' ', @class, ' '), ' highlight ')
            and string-length(normalize-space(@class)) = 23
          ]   

这是一个使用 XSLT 的快速验证。转换计算 XPath 表达式并从每个表达式中输出选定的节点:

<xsl:stylesheet version="1.0" 
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>

  <xsl:template match="/">
Loose classes selection:
    <xsl:copy-of select=
     "//div[contains(concat(' ', @class, ' '), ' list ')]
       /div[contains(concat(' ', @class, ' '), ' item ') 
          and contains(concat(' ', @class, ' '), ' ng-scope ')]
     "/>
==============================
Exact number of classes selection:
    <xsl:copy-of select=
     "//div[contains(concat(' ', @class, ' '), ' list ')
          and string-length(normalize-space(@class)) = 4
          ]
         /div[contains(concat(' ', @class, ' '), ' item ') 
            and contains(concat(' ', @class, ' '), ' ng-scope ')
            and string-length(normalize-space(@class)) = 13
          or 
            contains(concat(' ', @class, ' '), ' item ') 
            and contains(concat(' ', @class, ' '), ' ng-scope ')
            and contains(concat(' ', @class, ' '), ' highlight ')
            and string-length(normalize-space(@class)) = 23
          ]
          "/>
  </xsl:template>
</xsl:stylesheet>

当此转换应用于以下文档时:

<html>
  <div class=" list   class2 ">
    <div class ="   item ng-scope  class3  "/>
    <div class ="item   ng-scope  class4  "/>
    <div class ="item   ng-scope class5  "/>
    <div class ="item   ng-scope  highlight class6 "/>
    <div class =" highlight item  class7   ng-scope  "/>
  </div>
  <div class=" list    ">
    <div class ="   item ng-scope  "/>
    <div class ="item   ng-scope  class4  "/>
    <div class ="  ng-scope item  "/>
    <div class ="item   ng-scope  highlight  "/>
    <div class =" highligh item    ng-scope  "/>
  </div>
</html>

在这两种情况下都会产生想要的正确结果:

Loose classes selection:
    <div class="   item ng-scope  class3  "/>
<div class="item   ng-scope  class4  "/>
<div class="item   ng-scope class5  "/>
<div class="item   ng-scope  highlight class6 "/>
<div class=" highlight item  class7   ng-scope  "/>
<div class="   item ng-scope  "/>
<div class="item   ng-scope  class4  "/>
<div class="  ng-scope item  "/>
<div class="item   ng-scope  highlight  "/>
<div class=" highligh item    ng-scope  "/>
==============================
Exact number of classes selection:
    <div class="   item ng-scope  "/>
<div class="  ng-scope item  "/>
<div class="item   ng-scope  highlight  "/>

XPath 2.0 解决方案:

使用这两个 XPath 2.0 表达式:

“松散”表达:

//div[contains(concat(' ', @class, ' '), ' list ')]
   /div[every $token in ('item', 'ng-scope') satisfies $token = tokenize(@class, '\s+')[.]]

“精确”表达式:

//div[normalize-space(@class) = 'list']
    /div[every $token in ('item', 'ng-scope') satisfies $token = tokenize(@class, '\s+')[.]
            and not(tokenize(@class, '\s+')[.][3])
          or 
            (every $token in ('item', 'ng-scope', 'highlight') 
               satisfies $token = tokenize(@class, '\s+')[.]
            and not(tokenize(@class, '\s+')[.][4]))
          ]

【讨论】:

  • 如果是两个可能的ID而不是类,你必须使用//*[@id="one"] | //*[@id="two"]?
  • @Anthony,有一个 id 属性是完全不同的,实际上更简单的情况——可以使用 XPath id() 函数,如果该属性在 XML 文档的 DTD 中声明为 IDREF,或者可以使用 XSLT 键,或者在 XPath 2.0 或更高版本中,可以使用 //div[@id = ('one', 'two')] 您评论中提供的表达式可能没有经过 XPath 引擎优化,效率会相当低。如果想使用类似但更高效的表达式来评估表达式,请使用:`//div[@id = 'one' 或 @id = 'two']
  • 啊,好吧,所以你把实际的 ID 括起来。我已经尝试过你的最后一个表达式,尽管我使用的是driver.find_element(By.ID, 'xpath/here'),但由于某种原因它无法正常工作,这是为什么呢?
  • 我也刚试过//*[@id = ('one', 'two')],它告诉我这个表达是不合法的。我也试过//*[@id=("priceblock_saleprice" or "priceblock_ourprice")],虽然它没有产生任何错误或异常.text是空白的??
  • @Anthony,你的问题的答案很简单——你有一个不符合 XPath 1.0 规范的 XPath 引擎——而且它绝对不是 XPath 2.0 或更高版本
猜你喜欢
  • 1970-01-01
  • 2021-03-17
  • 1970-01-01
  • 1970-01-01
  • 2014-03-21
  • 2010-12-08
  • 2020-05-03
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多