检查Python Selenium是否存在元素


73

我有一个问题-我正在使用Selenium(firefox)Web驱动程序打开网页,单击一些链接等,然后捕获屏幕截图。

我的脚本可以从CLI正常运行,但是通过cronjob运行时,它并没有通过第一个find_element()测试。我需要添加一些调试,或一些帮助我弄清为什么失败的东西。

基本上,我必须先单击“登录”锚点,然后才能进入登录页面。元素的构造为:

<a class="lnk" rel="nofollow" href="/login.jsp?destination=/secure/Dash.jspa">log in</a>

我正在通过LINK_TEXT方法使用find_element:

login = driver.find_element(By.LINK_TEXT, "log in").click()

我有点Python Noob,所以我在和这种语言作斗争...

A)如何检查链接是否已被python实际拾取?我应该使用try / catch块吗?

B)是否有比LINK_TEXT更好/更可靠的方法来定位DOM元素?例如,在JQuery中,可以使用更具体的选择器$('a.lnk:contains(login)')。do_something();


我已经解决了主要问题,这只是手指问题-我用错误的参数调用脚本-简单的错误。

我仍然想要一些有关如何检查元素是否存在的指针。同样,使用隐式/显式Waits的示例/解释,而不是使用糟糕的time.sleep()调用。

干杯,ns


您还可以通过CSS定位器或xpath查找元素。往往不如文本内容那么脆弱。
Silas Ray 2012年

我相信,使用内容文本和XPATH / CSS两者都对设计(而不是应用程序逻辑)的微小更改很脆弱。更好的办法是由要么找元素idclass_namename
Kshitij Saraogi'5

Answers:


57

A)是的。检查元素是否存在的最简单方法是find_element在内简单调用try/catch

B)是的,出于两个原因,我总是尝试不使用元素文本来标识元素:

  1. 文本更可能被更改;并且
  2. 如果这对您很重要,则您将无法针对本地化版本运行测试。

解决方案之一:

  1. 您可以使用xpath查找具有ID或其他唯一标识符的父元素或祖先元素,然后找到与或相匹配的子代/后代。
  2. 您可以请求链接本身的ID或名称或其他唯一标识符。

对于后续问题,使用try/catch可以确定一个元素是否存在,并在此处找到了很好的等待示例:http : //seleniumhq.org/docs/04_webdriver_advanced.html


查找文本的一种用途是查看是否显示成功/失败的Flash消息。不确定是否有更好的方法吗?
罗布·格兰特

这些绝对是避免按文本选择的极好理由
kevlarr

114

一种)

from selenium.common.exceptions import NoSuchElementException        
def check_exists_by_xpath(xpath):
    try:
        webdriver.find_element_by_xpath(xpath)
    except NoSuchElementException:
        return False
    return True

b)使用xpath-最可靠。此外,您可以在所有脚本中将xpath作为标准,并创建上述功能以通用。

更新:我在4年前写了最初的答案,当时我认为xpath是最好的选择。现在,我建议使用css选择器。我仍然建议不要混合使用“按​​ID”,“按名称”等,而是使用一种方法。


您还应该将对象:browser = webdriver.Firefox()传递给自定义函数
Spectral

总的来说,我很少碰到符合统一匹配思想的html页面。是否有办法解决此类页面上定位器方法的混合匹配问题?
Kshitij Saraogi'5

@KshitijSaraogi不确定是否完全理解您的问题。如果您留下来,那么在网络驱动程序测试中不可能只包含“ css选择器”,这实际上是有可能的。在过去的六年中,我一直在这样做。
Alex Okrushko'5

@AlexOkrushko您通过xpath推荐CSS选择器的原因是什么?
BoZenKhaa

1
@BoZenKhaa,至少有两个原因:css选择器对开发人员的熟悉,这有助于代码的可读性;xpath在IE中有一些糟糕的性能。
Alex Okrushko

71

提供的解决方案对我来说似乎都不是最简单的,因此我想添加自己的方法。

基本上,您将获得元素列表,而不只是元素列表,然后计算结果。如果为零,则不存在。例:

if driver.find_elements_by_css_selector('#element'):
    print "Element exists"

请注意其中的“ s”,find_elements_by_css_selector以确保其可计数。

编辑:我正在检查len(列表的,但最近我了解到一个空列表是错误的,因此您根本不需要获取列表的长度,只需要更简单的代码即可。

另外,另一个答案是说使用xpath更可靠,事实并非如此。请参阅css-selector和Xpath有什么区别?哪个更好(根据性能和跨浏览器测试)?


2
这比上面的异常处理方法快吗?
Gal Bracha

2
@GalBracha很好的问题,我认为它可能取决于版本和平台,因此,如果速度差异对您而言如此重要,我建议您在目标平台上对其进行测试以获得最佳结果。但是,在此有一点要注意的是预优化,在这种情况下,代码的可读性可能比可忽略的性能提高更为重要
Brian Leishman

很好的解决方案,但只是意识到尽管隐藏输入类型时这不起作用。因此,您实际上应该使用find_elements_by_idfind_element_by_xpath当元素不可用时,Btw引发错误
Raunak Thomas

find_element_by_xpath当它不是函数的复数形式时,由于找不到元素而引发错误
Brian Leishman

@RaunakThomasfind_elements_by_css_selector也不关心输入元素是否具有type="hidden",因为在我的一个用例中,我正正是出于此目的使用它
Brian Leishman

12

无需try&catch且无需新导入的解决方案:

if len(driver.find_elements_by_id('blah')) > 0: #pay attention: find_element*s*
    driver.find_element_by_id('blah').click #pay attention: find_element

1
您会发现它两次,肯定会更有效地存储馆藏,如果确实如此,请单击第一个,例如e = driver.find_elements_by_id('blah') if e: e[0].click
Brian Leishman

1
@BrianLeishman我同意您的方式,这种方式效率更高,但我认为我的方式更易于阅读和理解
超级马里奥

3
好的解决方案,但我同意Brian关于you're finding twice
ivanleoncz

我想:if len(driver.find_elements_by_id('blah')): #do something也应该做同样的事情。(> 0)不是必需的。
atb00ker'2

5

与Brian相同,但在tstempko中添加以下答案:

/sqa/3481/quicker-way-to-assert-that-an-element-does-not-exist

所以我试了一下,它很快就起作用了:

driver.implicitly_wait(0)

if driver.find_element_by_id("show_reflist"):        
 driver.find_element_by_id("show_reflist").find_element_by_tag_name("img").click()

在此之后,我恢复了默认值

driver.implicitly_wait(30)

是!如果您知道该页面已经加载,则您不希望等待30秒以获取“不存在回报”。这立即返回,正是我所需要的。
韦尔奇

3

您也可以使用以下方法更简洁地进行操作

driver.find_element_by_id("some_id").size != 0

这将返回错误。检查Lopi Dani以了解原因和正确的方法。
Sameh

1

driver.find_element_by_id("some_id").size() 是类方法。

我们需要的是:

driver.find_element_by_id("some_id").size 这是字典,所以:

if driver.find_element_by_id("some_id").size['width'] != 0 : print 'button exist'


这并不总是正确的,如果元素也存在,则宽度可以为零。el = driver.find_element_by_class_name('gNO89b')el.size这是google搜索页中的有效元素,但宽度为0
codelord

1

你可以像下面那样使用is_displayed()

res = driver.find_element_by_id("some_id").is_displayed()
assert res, 'element not displayed!'
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.