通过 id 定位元素

Posted

技术标签:

【中文标题】通过 id 定位元素【英文标题】:Locating an element by id 【发布时间】:2016-04-03 22:49:17 【问题描述】:

以下定位技术有什么区别?

    element(by.id("id")); element(by.css("#id")); element(by.xpath("//*[@id='id']")); browser.executeScript("return document.querySelector('#id');"); browser.executeScript("return document.getElementById('id');");

并且,从性能的角度来看,哪种方法是的最快方法?

【问题讨论】:

我猜#1 是最快的。事实上,您很可能已经将它们按顺序排列(但将 #4 和 #5 颠倒了)。期待一些强有力的分析或实证答案。 这些是识别页面元素定位器的策略,By.id最好是快速的,不依赖于其他html标签。当您具有特定元素的任何唯一属性时,您可以使用 css 或 xpath 创建定位器。 css 比 xpath 快 @SadikAli 感谢您的意见。 “css 比 xpath 快” - 它不应该依赖于特定的浏览器吗?你有什么参考或基准可以提供吗?.. 它可能需要另外一两个赏金来奖励这里的详细答案。感谢大家的帮助! 【参考方案1】:

您的问题很难回答,当然要给出一个结论性的答案。事实上,我很想将这个问题标记为“太宽泛”,其他答案和 cmets 都支持这一点。

以您的element(by.id("id")); 为例。查看 Selenium 源代码,大多数 驱动程序只需获取您提供的任何 id,并将其传递给有线协议:

public WebElement findElementById(String using) 
  if (getW3CStandardComplianceLevel() == 0) 
    return findElement("id", using);
   else 
    return findElementByCssSelector("#" + cssEscape(using));
  

如您所知,每个浏览器供应商都在单独的二进制文件中实现自己的有线协议。随意深入代码,为自己挖一个更深的洞。

对于其他不支持有线协议的浏览器,例如 HtmlUnit,你只需要:

public List<WebElement> findElementsById(String id) 
  return findElementsByXPath("//*[@id='" + id + "']");

然后他们解析可用的 DOM。

至于你的表现问题,任何人给你的任何东西都是 1) 只是 感觉,或 2) 纯粹的废话!您已经可以从您获得的其他答案和 cmets 中看到。

要获得真实的答案(有实际数据支持),需要考虑的变量太多:

不同浏览器供应商实现的有线协议,以及不同版本中的各种优化。 由不同浏览器供应商实现的 DOM 引擎,以及不同版本中的各种优化。 不同浏览器供应商实现的 javascript 引擎,以及不同版本中的各种优化。

此外,由于用于构建该网站的框架存在差异,您为 Web 应用程序/网页获得的任何结果都最可能不适用于不同的 Web 应用程序/网页。

底线是:如果您关心性能测试,那么 Selenium 是错误的答案。 Selenium 是一个功能测试库,经过优化可以为您提供最佳的最终用户表示。性能是事后才想到的。

如果您的目标是让您的测试运行得更快,那么您最好花时间研究一下您的测试结构:

您打开/关闭浏览器的频率。这通常是测试中最耗时的活动。 您多久刷新一次元素缓存,您需要多久刷新一次?考虑将您的元素移动到 Page Factory 模型,该模型会为您延迟加载所有元素。 当然还有最大的加速因素:在多台机器上并行运行测试。

但我认为这与您最初的问题无关(有些人可能会建议“咆哮”)。

【讨论】:

是的,这个问题“很难回答”,但不,这些形式之间的差异不是“主要基于意见”,而且,不,性能既不是“只是一种感觉”,也不是“纯BS”。性能可能难以衡量或上下文敏感,但它仍然非常客观。从您的来源调查开始,您就有了一个不错的答案核心;很遗憾,你用这种毫无意义的咆哮包围了这个美好的开始。您为什么不对其进行编辑,删除咆哮,并进一步构建生产性部分? @kjhughes 我确实说过“......任何人给你的任何东西......”我明白获得真实性能指标是一种艺术形式。看看答案:“......我投票......”,“......根据我......”。甚至您自己的评论都带有“我猜……”我稍微修正了我的答案,如果您仍然对自己的立场感到强烈,请随时对我投反对票。 不需要反对票。感谢您所做的改进。【参考方案2】:

识别差异将非常困难。以下是我发现的几件事 -

executeScript() 调度命令以在当前选定的框架或窗口的上下文中以字符串形式执行 JavaScript。虽然速度很快,但代码的可读性很低。

element() 函数又解析为 findElement() 函数,该函数调度命令以在 DOM 上查找元素。提高了可读性。

在我看来,从性能的角度来看,这是从最快开始按升序排列的排名,所有排名都彼此接近,相差几毫秒 -

1 - browser.executeScript("return document.getElementById('id');");
2 - browser.executeScript("return document.querySelector('#id');");
3 - element(by.id("id"));
4 - element(by.css("#id"));
5 - element(by.xpath("//*[@id='id']"));

javascript executeScript() 如此之快的原因是该命令直接在 DOM 上执行而无需转换。 This link justifies their rankings between each other.

剩余的量角器特定element() 定位器很慢,因为量角器需要使用findElement() 函数转换命令以获取网络元素。通过id 获取元素比使用cssxpath 更快(这也取决于定位器的使用方式,并且通常可以根据使用情况进行更改)。

注意:上述性能分析是我在我的机器上本地运行的许多测试的平均值,但它可能会因内部影响运行测试脚本的系统任务而异。

希望对你有帮助。

【讨论】:

【参考方案3】:

如果有人试图回答它,这将是一个广泛的答案,所以我会尽量让它变得简单。

这些只是使用 selenium 查找元素的不同方法。我们有这么多选择元素的替代方案的原因是,我们并不总是会将 id 或 class 标记到元素。对于没有 id 或 class 或 name 的元素,我们剩下的唯一选项是 XPATH。

XPATH 可用于唯一标识 XML 中的任何元素,并且由于 HTML(准确地说是 HTML 5,如果根据标准编写)是 XML 的一个实例,我们可以使用 XPATH 唯一标识文件中的每个元素。

好的,为什么不一直使用 XPATH 呢?为什么有这么多替代品? 很简单,XPATH 很难写。例如,如果我们需要获取 'td' 的 XPATH,它属于嵌套在其他 2 个表中的表。 XPATH 会很长,而且大多数时候我们都会犯错误。

在 firefox 中查找 XPATH 非常简单,只需安装 firepath 或 firebug 并右键单击元素并选择 COPY XPATH。

selenium 中指标的详细说明:here(在 java 中提供,但总体上会有所帮助)

【讨论】:

“HTML 是 XML 的实例”并不总是正确的。可以编写 HTML 以符合 XML 规范,但大多数版本的 HTML(包括 HTML5)允许使用无效 XML 的内容。例如,&lt;br&gt; 在 HTML 中有效,但必须在 XML 中写成 &lt;br/&gt;&lt;input type="checkbox" checked&gt; 在 HTML 中有效,但在 XML 中无效。 是的@Matthew你是对的。 HTML 并不总是 XML 的一个实例,但 HTML 5 标准要求 HTML 与 XML 兼容。感谢您的评论。我将编辑回复。 实际上,HTML5 甚至都不是这样。该规范允许人们以符合 XML 的形式或不以符合 XML 的形式编写它。请注意,例如在 &lt;br&gt; tag 的定义中,规范不要求关闭标签,而对于 &lt;p&gt; tag,规范说明何时可以省略结束标签(即XML 中不允许)。 是的,规范允许人们以符合 XML 的格式或有点草率的格式编写,但 HTML 5 最重要的介绍是更像 XHTML 而不是 HTML 4。XHTML 更严格,如果根据 XHTML 编写,我们实际上是在编写符合 XML 的代码。但我确实接受您的评论,大多数开发人员大部分时间都让草率的 HTML 编写方法蔓延。【参考方案4】:

我只是从性能角度考虑并编写以下脚本来检查谷歌徽标。虽然结果令人困惑,但我们可以对结果进行统计估计。

querySelectorgetElementById 总是有更好的结果,除非试验次数超过 10K。如果我们比较这两种方法:getElementById 更好(29 比 21)。

如果我们比较这些,IDCSSXPATH,CSS 更好(29 比 18 和 4),其次是 ID最后一个 XPATH。

我的测试结果:getElementById、querySelector、CSS、ID、XPATH

查看表格、结果和脚本:

表格显示了 50 次尝试的总结结果:

1 2 3 4 5 编号 0 0 18 24 8 CSS 0 0 29 18 3 XPATH 0 0 4 12 34 查询选择器 21 29 0 0 0 getElementById 29 21 0 0 0

时差结果:

>>> for i in range(50):
...  test_time(1)
...
[('getElementById', 0.004777193069458008), ('querySelector', 0.006440162658691406), ('id', 0.015267133712768555), ('css', 0.015399932861328125), ('xpath', 0.015429019927978516)]
[('querySelector', 0.006442070007324219), ('getElementById', 0.00728607177734375), ('id', 0.013181924819946289), ('css', 0.014509916305541992), ('xpath', 0.015583992004394531)]
[('getElementById', 0.0063440799713134766), ('querySelector', 0.006493091583251953), ('css', 0.014523029327392578), ('id', 0.014902830123901367), ('xpath', 0.015790224075317383)]
[('getElementById', 0.007112026214599609), ('querySelector', 0.007357120513916016), ('id', 0.014781951904296875), ('css', 0.015780925750732422), ('xpath', 0.016005992889404297)]
[('getElementById', 0.006434917449951172), ('querySelector', 0.007117033004760742), ('id', 0.01497507095336914), ('css', 0.015005111694335938), ('xpath', 0.015393972396850586)]
[('querySelector', 0.00563812255859375), ('getElementById', 0.006503105163574219), ('css', 0.014302968978881836), ('id', 0.014812946319580078), ('xpath', 0.017061948776245117)]
[('querySelector', 0.0048770904541015625), ('getElementById', 0.006540060043334961), ('css', 0.014795064926147461), ('id', 0.015192985534667969), ('xpath', 0.016000986099243164)]
[('getElementById', 0.006265878677368164), ('querySelector', 0.006501913070678711), ('id', 0.014132022857666016), ('css', 0.01437997817993164), ('xpath', 0.014840841293334961)]
[('getElementById', 0.006368160247802734), ('querySelector', 0.006601095199584961), ('css', 0.01462101936340332), ('id', 0.014872074127197266), ('xpath', 0.016145944595336914)]
[('querySelector', 0.00642704963684082), ('getElementById', 0.006908893585205078), ('css', 0.014439105987548828), ('id', 0.014970064163208008), ('xpath', 0.015510082244873047)]
[('getElementById', 0.006404876708984375), ('querySelector', 0.006679058074951172), ('css', 0.014878988265991211), ('id', 0.01546788215637207), ('xpath', 0.015535116195678711)]
[('querySelector', 0.005848884582519531), ('getElementById', 0.008013010025024414), ('css', 0.014436006546020508), ('xpath', 0.01566910743713379), ('id', 0.015830039978027344)]
[('querySelector', 0.006299018859863281), ('getElementById', 0.006538867950439453), ('css', 0.014534950256347656), ('id', 0.014979124069213867), ('xpath', 0.01618194580078125)]
[('getElementById', 0.006415128707885742), ('querySelector', 0.006479978561401367), ('id', 0.014901876449584961), ('css', 0.014998912811279297), ('xpath', 0.01544499397277832)]
[('getElementById', 0.006515979766845703), ('querySelector', 0.006515979766845703), ('xpath', 0.014292001724243164), ('css', 0.014482975006103516), ('id', 0.015102863311767578)]
[('getElementById', 0.00574803352355957), ('querySelector', 0.006389141082763672), ('css', 0.014650821685791016), ('id', 0.014751911163330078), ('xpath', 0.01532888412475586)]
[('getElementById', 0.0063037872314453125), ('querySelector', 0.006974935531616211), ('id', 0.014775991439819336), ('css', 0.014935970306396484), ('xpath', 0.015460968017578125)]
[('getElementById', 0.0064661502838134766), ('querySelector', 0.0065021514892578125), ('id', 0.014723062515258789), ('css', 0.014946937561035156), ('xpath', 0.015508890151977539)]
[('getElementById', 0.006738901138305664), ('querySelector', 0.008143901824951172), ('css', 0.014575004577636719), ('xpath', 0.015228986740112305), ('id', 0.015702009201049805)]
[('getElementById', 0.006436824798583984), ('querySelector', 0.0064470767974853516), ('css', 0.014545917510986328), ('id', 0.014694929122924805), ('xpath', 0.015357017517089844)]
[('querySelector', 0.006292104721069336), ('getElementById', 0.006451845169067383), ('css', 0.014657020568847656), ('xpath', 0.01574397087097168), ('id', 0.016795873641967773)]
[('getElementById', 0.006443977355957031), ('querySelector', 0.006485939025878906), ('css', 0.013139009475708008), ('id', 0.014308929443359375), ('xpath', 0.015516042709350586)]
[('querySelector', 0.006464958190917969), ('getElementById', 0.006821870803833008), ('id', 0.016110897064208984), ('css', 0.01633286476135254), ('xpath', 0.017225980758666992)]
[('getElementById', 0.005715131759643555), ('querySelector', 0.008069992065429688), ('css', 0.014779090881347656), ('id', 0.01491093635559082), ('xpath', 0.015527963638305664)]
[('getElementById', 0.006309986114501953), ('querySelector', 0.006836891174316406), ('css', 0.01497507095336914), ('id', 0.015040159225463867), ('xpath', 0.02096104621887207)]
[('querySelector', 0.00616908073425293), ('getElementById', 0.007357120513916016), ('css', 0.014974832534790039), ('id', 0.015640974044799805), ('xpath', 0.016278982162475586)]
[('querySelector', 0.005301952362060547), ('getElementById', 0.0063440799713134766), ('id', 0.014526844024658203), ('css', 0.014657974243164062), ('xpath', 0.0162200927734375)]
[('querySelector', 0.005811929702758789), ('getElementById', 0.007221221923828125), ('css', 0.01259613037109375), ('xpath', 0.014851093292236328), ('id', 0.015043020248413086)]
[('getElementById', 0.006195068359375), ('querySelector', 0.007548093795776367), ('css', 0.01441502571105957), ('id', 0.01441812515258789), ('xpath', 0.016713857650756836)]
[('querySelector', 0.0050449371337890625), ('getElementById', 0.006323099136352539), ('id', 0.01497793197631836), ('css', 0.014984130859375), ('xpath', 0.015444040298461914)]
[('getElementById', 0.007039070129394531), ('querySelector', 0.008107900619506836), ('xpath', 0.015566825866699219), ('id', 0.015954017639160156), ('css', 0.01815509796142578)]
[('getElementById', 0.005831003189086914), ('querySelector', 0.007988214492797852), ('id', 0.014652013778686523), ('css', 0.014683008193969727), ('xpath', 0.01581597328186035)]
[('querySelector', 0.006363868713378906), ('getElementById', 0.006494998931884766), ('xpath', 0.01517796516418457), ('id', 0.016071796417236328), ('css', 0.017260074615478516)]
[('getElementById', 0.00633692741394043), ('querySelector', 0.007826089859008789), ('css', 0.014354944229125977), ('id', 0.015484809875488281), ('xpath', 0.017076969146728516)]
[('querySelector', 0.006349802017211914), ('getElementById', 0.006428956985473633), ('css', 0.01385188102722168), ('id', 0.014858007431030273), ('xpath', 0.016836166381835938)]
[('querySelector', 0.006417989730834961), ('getElementById', 0.007012844085693359), ('css', 0.01460719108581543), ('id', 0.014763832092285156), ('xpath', 0.015476226806640625)]
[('getElementById', 0.006266117095947266), ('querySelector', 0.0074520111083984375), ('id', 0.014987945556640625), ('css', 0.01515817642211914), ('xpath', 0.015646934509277344)]
[('getElementById', 0.006376981735229492), ('querySelector', 0.0064089298248291016), ('id', 0.01494598388671875), ('css', 0.015275001525878906), ('xpath', 0.01553201675415039)]
[('getElementById', 0.006357908248901367), ('querySelector', 0.006699085235595703), ('css', 0.014505147933959961), ('xpath', 0.015446186065673828), ('id', 0.019747018814086914)]
[('getElementById', 0.0063610076904296875), ('querySelector', 0.0064640045166015625), ('css', 0.014472007751464844), ('id', 0.014828205108642578), ('xpath', 0.01532888412475586)]
[('getElementById', 0.0063610076904296875), ('querySelector', 0.006580829620361328), ('css', 0.012439966201782227), ('id', 0.014935016632080078), ('xpath', 0.015373945236206055)]
[('querySelector', 0.006309032440185547), ('getElementById', 0.006561994552612305), ('id', 0.014923095703125), ('css', 0.015380859375), ('xpath', 0.01574110984802246)]
[('querySelector', 0.006357908248901367), ('getElementById', 0.006387948989868164), ('css', 0.01481485366821289), ('id', 0.015089988708496094), ('xpath', 0.015390872955322266)]
[('querySelector', 0.004536867141723633), ('getElementById', 0.00640416145324707), ('css', 0.014551877975463867), ('xpath', 0.014974117279052734), ('id', 0.014991998672485352)]
[('getElementById', 0.006387233734130859), ('querySelector', 0.00643610954284668), ('css', 0.014494895935058594), ('id', 0.014873981475830078), ('xpath', 0.015212059020996094)]
[('getElementById', 0.0063588619232177734), ('querySelector', 0.006443977355957031), ('css', 0.013200998306274414), ('id', 0.014631986618041992), ('xpath', 0.015624046325683594)]
[('getElementById', 0.0048558712005615234), ('querySelector', 0.005300045013427734), ('id', 0.014750003814697266), ('css', 0.014846086502075195), ('xpath', 0.015408992767333984)]
[('querySelector', 0.008347034454345703), ('getElementById', 0.008370161056518555), ('id', 0.014650106430053711), ('css', 0.014775991439819336), ('xpath', 0.015323877334594727)]
[('querySelector', 0.006309032440185547), ('getElementById', 0.007323026657104492), ('css', 0.014546871185302734), ('xpath', 0.015864133834838867), ('id', 0.02078390121459961)]
[('querySelector', 0.007790088653564453), ('getElementById', 0.010209083557128906), ('id', 0.015320062637329102), ('xpath', 0.01600193977355957), ('css', 0.01807403564453125)]

代码:

from timeit import default_timer as timer
import time, operator
from selenium import webdriver

def open_browser():
    dr = webdriver.Chrome()
    dr.get('http://www.google.com')
    time.sleep(5)
    return dr,timer()

def quit_browser(el, start, dr, result):
    diff = timer() - float(start)
    result[el] = diff
    dr.quit()

def test_time(tm):
    result = 
    
    dr, start = open_browser()
    for i in range(tm):
        dr.find_element_by_id('hplogo')
    quit_browser("id", start, dr, result)
    
    dr, start = open_browser()
    for i in range(tm):
        dr.find_element_by_css_selector('#hplogo')
    quit_browser("css", start, dr, result)
    
    dr, start = open_browser()
    for i in range(tm):
        dr.find_element_by_xpath("//*[@id='hplogo']")
    quit_browser("xpath", start, dr, result)
    
    dr, start = open_browser()
    for i in range(tm):
        dr.execute_script("return document.querySelector('#hplogo');")
    quit_browser("querySelector", start, dr, result)
    
    dr, start = open_browser()
    for i in range(tm):
        dr.execute_script("return document.getElementById('hplogo');")
    quit_browser("getElementById", start, dr, result)
    
    print sorted(result.items(), key=operator.itemgetter(1))

【讨论】:

【参考方案5】:

TL;DR;性能按从快到慢的顺序排列。

element(by.id("id")); element(by.css("#id")); element(by.xpath("//*[@id='id']")); browser.executeScript("return document.getElementById('id');"); browser.executeScript("return document.querySelector('#id');");

我会试试这个。我将尝试解释它直到ProtractorWebdriverJS。因为我没有写Selenium 或浏览器的驱动程序(例如ChromedriverFirefoxdriver...等...),这是浏览器和Selenium 之间的通信。为此,我将在这一点上使用浏览器引擎的标准知识。因此,答案不是 100% 准确,而是大部分准确。

我将 5 种方法分成 2 组:

1。普通通讯

对于前3个方法:

元素(by.id("id"));

元素(by.css("#id"));

元素(by.xpath("//*[@id='id']"));

这些都是对 Selenium 服务器的单个 HTTP 请求的结果。这是: '/session/:sessionId/element/:id/element'

有2个参数:

using:id 的类型。示例:'css select''id'、'xpath''link text'...等。 value:id 的值。示例'element-id''.element-css &gt; .child'//*[@id='id']

此时Selenium 将根据通过ChromedriverFirefoxdriver...等中的任何一个请求的内容来响应请求...

在 Webdriver find-element-strategy.js 下。看起来方法与 javascript document 属性提供的浏览器映射。我们得到了tagidcss selectorxpath...等与document.elementByTagNamedocument.elementByIDdocument.querySelecotrdocument.evaluate...匹配。

从逻辑上讲,从编码人员的角度来看,我会说无论这些驱动程序是如何编写的,资源都应该被重用。例如,id 的请求请求很可能会通过通信驱动程序在浏览器端触发类似getElementById 的内容。

=> SUMMARY 所以最后我们有:

css selector 相当于 querySelector id 相当于 getElementById xpath 相当于 evaluate

2。注入通信

最后两种方法:

browser.executeScript("return document.querySelector('#id');");

browser.executeScript("return document.getElementById('id');");

这些都是对 Selenium 服务器的单个 HTTP 请求的结果。这是: '/session/:sessionId/execute'

有2个参数:

script:javascript 文本 ('string') 或 function args :参数是 array

到此为止,我们都在讨论 JS 是如何注入浏览器的,因为我们都无法确定其行为(使用 devtools 或将 &lt;script&gt; 注入 HTML)。让我们假设它对于所有浏览器都是相同的。

=> SUMMARY 所以最后我们来分析一下:

querySelector getElementById

主要比较

1. element() vs browser.executeScript()

element() 原作定位元素。它通过浏览器及其通信驱动程序使用所有方法配置文件。这将提高性能 browser.executeScript() 是原始的不是用来定位元素的。但是要执行一个脚本,通过使用它,我们当然会得到相同的结果,但要通过更复杂的方式来实现相同的目标。因此,这将导致比使用元素查找器更复杂的计算。最终导致性能下降。

=>总结快到慢

element() browser.executeScript()

2. document.querySelector() vs document.getElementById() vs document.querySelector()

同样,每个浏览器都会产生细微的差异。但是已经有一些关于这个的研究。我只会使用找到的社区。​​p>

CSS selector 知道比xpath (source) 快

document.querySelector() > 更快 > document.evaluate()

(注意:IE 不支持 xpath,因此每当您在带有量角器的 IE 上使用 xpath 时,selenium 都会使用其自己的 xpath 引擎)

jsperf.com 我们得到this 测试那句话

document.getElementById() > 更快 > document.querySelector()

=>总结快到慢

document.getElementById() document.querySelector() document.evaluate()

3。从快到慢总结方法的性能

element(by.id("id")); element(by.css("#id")); element(by.xpath("//*[@id='id']")); browser.executeScript("return document.getElementById('id');"); browser.executeScript("return document.querySelector('#id');");

【讨论】:

以上是关于通过 id 定位元素的主要内容,如果未能解决你的问题,请参考以下文章

Appium元素定位

selenium IDE 如何定位页面变动元素

selenium.元素定位方式

Selenium用法详解定位页面元素JAVA爬虫

java+selenium元素定位和元素操作

java+selenium元素定位和元素操作