用于硒的 cssSelector 与 XPath

Posted

技术标签:

【中文标题】用于硒的 cssSelector 与 XPath【英文标题】:cssSelector vs XPath for selenium 【发布时间】:2018-04-26 07:52:02 【问题描述】:

据我了解,CSS 选择器遍历 DOM。因为 CSS 文件没有关于元素位置的任何信息,所以为什么 cssSelectorXPath 更快(理论上)。

理论上 cssSelectorXPath 花费更少的时间,因为 XPath 需要遍历 html DOM。 XPath 我们可以在 DOM 层次结构中向后或向前搜索元素,而 CSS 只能向前搜索。

但如果 cssSelector 也遍历 HTML DOM,那么它如何使 cssSelector 更快。​​

换句话说,cssSelector 是如何在内部实际工作的,以及为什么它总是更喜欢/推荐给每个人使用,然后是 xpath

还请分享使用 cssSelector 而不是 XPath 的其他好处。

反之亦然,在哪个领域 XPathcssSelector 更好

【问题讨论】:

What is the difference between css-selector & Xpath? which is better(according to performance & for cross browser testing)?的可能重复 @Andersson Q 已经很老了,答案也不是那么准确。 XPath CSS 选择器引擎在每个浏览器中都不同,因此不会使它们在任何一方不一致或变慢。 XPath 难以阅读不是性能问题。 【参考方案1】:

cssSelectorXPath 之间的争论现在仍然是 Selenium 社区 中最激烈和最主观的对话之一。快速回顾一下到目前为止我们已经知道的内容可以总结为:

支持 cssSelector 的人说它更具可读性和更快(特别是在运行 Internet Explorer 时)。 虽然支持 XPath 的人吹捧它能够横穿页面(而 cssSelector 不能)。 在 IE8 等旧版浏览器中遍历 DOM 不适用于 cssSelector,但适用于 XPathXPath 可以向上遍历 DOM(例如从子节点到父节点),而 cssSelector 只能向下遍历 DOM(例如从父节点到子节点) 但是,在旧版浏览器中无法使用 cssSelector 遍历 DOM 并不一定是坏事,因为它更多地表明您的页面设计不佳,并且可以从一些有用的标记中受益.

Dave Haeffnera page with two HTML data tables 上执行了test,其中一个表没有有用的属性(IDClass),另一个和他们在一起。我已经在Why should I ever use CSS selectors as opposed to XPath for automated testing? 的讨论中详细分析了测试过程和这个实验的结果。虽然这个实验证明每个Locator Strategy 在浏览器中都是相当等价的,但它并没有为我们充分描绘出整个画面。


cssSelector vs XPath,在显微镜下

Dave Haeffner 在Css Vs. X Path, Under a Microscope 的讨论中提到,在端到端测试中,还有很多其他变量在起作用Sauce 启动浏览器启动,以及延迟到和来自被测应用程序。该实验的不幸结论可能是一个驱动程序可能比另一个驱动程序更快(例如 IEFirefox),而事实上,情况并非如此.要真正了解 cssSelectorXPath 之间的性能差异,我们需要深入挖掘。这可以通过在使用性能基准测试实用程序的同时从本地计算机运行所有内容来实现。重点是特定的 Selenium 操作,而不是整个测试运行,并多次运行。

为了演示这个详细的示例,设置了一个 Windows XP 虚拟机并安装了Ruby (1.9.3)。还安装了所有可用的浏览器及其等效的 Selenium 浏览器驱动程序。对于基准测试,使用了 Ruby 的标准库 benchmark


测试

为了获得足够的样本数据集,对每个浏览器进行了 100 次相同的测试。为了清除数据中的异常,使用了基准测试的预演功能,以便它运行完整的测试序列执行垃圾收集,然后再次运行。为了使事情具有可比性,一些定位器进行了更新,以便更好地相互比较。而我们衡量的具体行动是find_element


测试代码

require_relative 'base'
require 'benchmark'

class SmallDOM < Base

  LOCATORS = 
    :id => 
      id: 'table2'
    ,
    :table_header_class => 
      class: 'dues'
    ,
    :table_header_id_and_class => 
      :css => "#table2 thead .dues",
      :xpath => "//table[@id='table2']//thead//*[@class='dues']"
    ,
    :table_header_id_class_and_direct_desc => 
      :css => "#table2 > thead .dues",
      :xpath => "//table[@id='table2']/thead//*[@class='dues']"
    ,
    :table_header_traversing => 
      :css => "#table2 thead tr th:nth-of-type(4)",
      :xpath => "//table[@id='table2']//thead//tr//th[4]"
    ,
    :table_header_traversing_and_direct_desc => 
      :css => "#table2 > thead > tr > th:nth-of-type(4)",
      :xpath => "//table[@id='table2']/thead/tr/th[4]"
    ,
    :table_cell_id_and_class => 
      :css => "#table2 tbody .dues",
      :xpath => "//table[@id='table2']//tbody//*[@class='dues']"
    ,
    :table_cell_id_class_and_direct_desc => 
      :css => "#table2 > tbody .dues",
      :xpath => "//table[@id='table2']/tbody//*[@class='dues']"
    ,
    :table_cell_traversing => 
      :css => "#table2 tbody tr td:nth-of-type(4)",
      :xpath => "//table[@id='table2']//tbody//tr//td[4]"
    ,
    :table_cell_traversing_and_direct_desc => 
      :css => "#table2 > tbody > tr > td:nth-of-type(4)",
      :xpath => "//table[@id='table2']/tbody/tr/td[4]"
    
  

  attr_reader :driver

  def initialize(driver)
    @driver = driver
    visit '/tables'
    super
  end

  # The benchmarking approach was borrowed from
  # http://rubylearning.com/blog/2013/06/19/how-do-i-benchmark-ruby-code/
  def benchmark
    Benchmark.bmbm(27) do |bm|
      LOCATORS.each do |example, data|
    data.each do |strategy, locator|
      bm.report(example.to_s + " using " + strategy.to_s) do
        begin
          ENV['iterations'].to_i.times do
         find(strategy => locator)
          end
        rescue Selenium::WebDriver::Error::NoSuchElementError
          puts "( 0.0 )"
        end
      end
    end
      end
    end
  end

end

结果

注意:输出以秒为单位,结果是 100 次执行的总运行时间。


分析结果

总的来说,Internet Explorer 比其他驱动程序慢,但在 CSS 和 XPath 之间,XPath 看起来实际上比 CSS 快。 Chrome 和 Opera 有一些差异,尽管要小得多,但它们会在两个方向上摇摆不定。 在某些情况下,CSS 更快,而在其他情况下,XPath 更快。 Firefox 看起来更针对 CSS 进行了优化,因为它的速度更快。

结尾

即使存在这些速度差异,它们之间也只有几秒(或几分之一秒)的间隔 - 即执行 100 次。当您考虑完成一次测试运行需要 30 秒或更长时间时,这种差异可以忽略不计。所以,css-selectors 和 xpath 之间的选择可能是一个艰难的选择。但现在您拥有足够多的数据来为自己做出选择。这实际上只是找到适合您和您的团队的方法,而不是被关于哪个更好的炒作和意见所拖累。

【讨论】:

【参考方案2】:

我总是使用 xpath。通过 xpath,我可以使用对象的任何属性,包括它的 ID 或名称。我可以使用它们的组合和子集,并在需要时调用 xpath 的强大语言。

根据我的经验,使用 xpath 导航 DOM 树是比使用 CSS 更好的定位对象的方法,毕竟 CSS 仅用于描述对象的显示方式。

至于速度比较,我认为这取决于表达式的复杂性。 find_element_by_id('myID')find_element_by_xpath(@id='myID')find_element_by_css_selector ('myID') 是否调用不同的引擎并产生不同的响应时间?

我听过和读过的关于 xpath 的很多坏消息都是因为人们使用硬编码的路径,比如//div[1]/div[2]/a[3],它很脆弱。可以编写更健壮的 xpath 表达式,例如 //div[@id='main']//a[@href='xpath_nodes.asp']

【讨论】:

如果你已经有一个 id 那么你为什么要使用 xpath 呢? @cruisepandy - 我喜欢坚持使用 xpath 以保持一致性。 id 只是对象的另一个属性。 XPath 和 CSS 在浏览器中使用不同的定位引擎。 CSS 得到更广泛和一致的支持,而且速度更快,语法更简单。我确实使用 XPath,但仅在需要通过包含的文本查找元素或进行 DOM 遍历时使用......但就是这样。 这里有一个快速参考,供以后的人参考...elementalselenium.com/tips/34-xpath-vs-css-revisited-2 我也喜欢 xpath,你可以找到 css 可以在 xpath 中找到的任何东西,加上一些。因此,我的代码库更加一致。此外,对我来说,XPath 语法看起来很简单直接。几毫秒的 css 速度边缘对我来说无关紧要。在现实世界的网络应用程序中,至少我曾经使用过的那些应用程序,并不是每个人都能为你想要指向和点击的所有元素设置一个唯一的 id。【参考方案3】:

我读过很多文章,也看到过一些像 this 和 this 这样的文章,其中的数据表明 CSS 选择器更快,我做了一些测试,得出了相同的结论. 2016 年 12 月,我与 elementalselenium.com 的作者 Dave Haeffner 进行了交谈,并向他询问了他网站上的性能数字(在我上面链接的帖子中),因为它们已经很老了。他在linked me a presentation(见 pp18-23)更新了测试,CSS 选择器仍然更快,但 XPath 在一些配置中赶上了。

所以我们可以看到证据证明这是真的,但我从未见过有人谈论为什么的技术细节。如果我猜的话,那将是因为不同的浏览器已经做了很多工作来优化页面渲染的速度。让 CSS 选择器快速工作可以使页面渲染速度更快,并且由于浏览器驱动程序利用了浏览器定位元素的能力,这意味着 CSS 选择器通常会胜出。我读过一些浏览器提高了它们的 XPath 定位器速度,但我认为它可能总是落后于 CSS 选择器,因为它比 CSS 选择器少得多。

CSS 选择器和 XPath 都必须遍历 DOM,因此除了执行遍历的引擎的速度之外,没有真正的区别。由于 CSS 选择器的广泛使用,CSS 选择器引擎在这一点上与 XPath 引擎相比可能是一款经过微调的机器。

我的一般定位器策略是 ID 优先,其他一切都是 CSS 选择器。当没有其他工作时,我使用 XPath。它会因站点而异,但根据我的经验,ID 可能占我定位器的 10%。 CSS 选择器大概有 80% 左右,最后 10% 是 XPath。当我需要通过包含的文本和很少的 DOM 遍历来定位元素时,我通常使用 XPath。我的 XPath 用法示例可能是我需要在 TABLE 中找到相对于行标签的元素,例如表格行中奶酪的价格,其中第一个单元格包含“奶酪”,第三个单元格包含价格。

我认为 XPath 因其易于访问而在 SO 和许多博客等网站上经常出现。我所要做的就是右键单击 devtools 中的一个元素并复制 XPath。这个问题很多时候会生成一个糟糕的、脆弱的 XPath。手工制作的 XPath 更好,但手工制作好的 XPath 或 CSS 选择器需要时间和经验。许多人不愿意投入时间。一个糟糕的 CSS 选择器或 XPath 也会让事情变慢。很多时候,可以通过多种方式定位元素,有些方式比其他方式更有效……这取决于定位器的效率以及您如何使用它。格式错误的 CSS 选择器不会自动比格式正确的 XPath 更快。

【讨论】:

感谢@JeffC .. 这是一个很好的解释。我必须知道很多事情。现在我保持这个问题开放并等待任何技术解释。将根据.. 批准答案,现在投票给你。感谢分享

以上是关于用于硒的 cssSelector 与 XPath的主要内容,如果未能解决你的问题,请参考以下文章

CssSelector 是我可以用于 shadowroot 的唯一方法吗? selenium.common.exceptions.InvalidArgumentException:消息:无效参数:无效

cssSelector 的 Selenium WebDriver 问题

python 硒的Python标头

如何从硒的跨度中获取文本

不能使用带有硒的镀铬按钮

如何维护硒的屏幕?