使用 Python Selenium 检查元素是不是存在

Posted

技术标签:

【中文标题】使用 Python Selenium 检查元素是不是存在【英文标题】:Checking if element exists with Python Selenium使用 Python Selenium 检查元素是否存在 【发布时间】:2012-03-22 22:47:40 【问题描述】:

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

我的脚本在 CLI 中运行良好,但是当通过 cronjob 运行时,它没有通过第一个 find_element() 测试。我需要添加一些调试,或者一些东西来帮助我找出失败的原因。

基本上,在进入登录页面之前,我必须单击“登录”锚点。元素的构造是:

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

我正在使用 find_element By LINK_TEXT 方法:

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

我是一个 Python 菜鸟,所以我正在与这门语言进行一些斗争......

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

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


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

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

干杯,ns

【问题讨论】:

您还可以通过 CSS 定位器或 xpath 查找元素。往往不如文本内容那么脆弱。 我相信这两者 - 使用内容文本和 XPATH/CSS - 对于设计而不是应用程序逻辑的微小变化都是脆弱的。更好的方法是通过idclass_namename 查找元素。 【参考方案1】:

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

B) 是的,我总是尝试在不使用文本的情况下识别元素,原因有两个:

    文本更有可能发生变化; 如果它对您很重要,您将无法针对本地化构建运行测试。

解决方案:

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

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

【讨论】:

我查找文本的一个用途是查看是否显示成功/不成功的 Flash 消息。不确定是否有更好的方法? 这些绝对是避免通过文本选择的绝佳理由【参考方案2】:

一)

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 选择器。我仍然建议不要混合/使用“by id”、“by name”等,而是使用一种方法。

【讨论】:

您还应该将 object: browser = webdriver.Firefox() 传递给您的自定义函数 一般来说,我很少遇到符合统一匹配思想的html页面。有没有办法解决此类页面上定位器方法的混合匹配问题? @KshitijSaraogi 不确定是否完全理解您的问题。如果你坚持认为在你的 webdriver 测试中只有“css 选择器”是不可能的——这实际上是很有可能的。在过去的 6 年里,我一直在这样做。 @AlexOkrushko 您推荐 css 选择器而不是 xpath 的原因是什么? @BoZenKhaa,至少有两个原因:开发人员熟悉 css 选择器,这有助于代码的可读性; xpath 在 IE 中有一些糟糕的表现。【参考方案3】:

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

基本上,您会得到元素列表,而不仅仅是元素,然后计算结果;如果为零,则不存在。示例:

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

注意find_elements_by_css_selector 中的“s”以确保它是可数的。

编辑:我正在检查列表的len(,但我最近得知空列表是错误的,因此您根本不需要获取列表的长度,离开更简单的代码。

另外,另一个答案说使用 xpath 更可靠,这是不正确的。见What is the difference between css-selector & Xpath? which is better(according to performance & for cross browser testing)?

【讨论】:

这比上面的异常处理方法快吗? @GalBracha 好问题,我假设它可能取决于版本和平台,所以如果速度差异对你来说很重要,我建议在你的目标平台上测试它最好的结果。但是,这里有一点需要说明的是预优化,在这种情况下,代码可读性可能比可忽略的性能提升更重要 find-element(单数)形式在找不到元素时会抛出异常。查找元素(带有 's' 的复数)将返回一个空列表。在我看来,所有其他使用 try-catch 来查看元素是否存在的示例都是糟糕的编程风格。 Try-catch 应该只用于捕捉意外情况。如果您认为该元素可能不存在,则应编写代码来处理这种情况。 @BillWorthington 同意 100%。我不是 Python 开发人员,所以我不知道这里有什么正常的,但我不会用任何其他语言写东西 @BrianLeishman 我试图指出您的示例是正确的方法,而其他示例不是很好的编程风格。【参考方案4】:

与 Brian 相同,但从 tstempko 添加到此答案:

https://sqa.stackexchange.com/questions/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 秒来获得你的“不存在返回”。这会立即返回,正是我所需要的。【参考方案5】:

你也可以更简洁地使用

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

【讨论】:

这将返回一个错误。检查 Lopi Dani 的原因和正确的方法。 请注意size会返回元素的高度和宽度。【参考方案6】:

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 这是谷歌搜索页面中的有效元素,但宽度为 0【参考方案7】:

没有 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

【讨论】:

你找到了两次,存储集合肯定会更有效率,如果它是真实的,请单击第一个,例如e = driver.find_elements_by_id('blah') if e: e[0].click @BrianLeishman 我同意你的方式,它更有效,但我认为我的方式更容易阅读和理解 很好的解决方案,但我同意,Brian,关于you're finding twice 我想:if len(driver.find_elements_by_id('blah')): #do something 也应该做同样的事情。 (&gt; 0) 不是必需的。 @atb00ker 你也可以去掉len,因为Python中的空集是假的,非空集是真的,但这就是我回答的重点【参考方案8】:

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

res = driver.find_element_by_id("some_id").is_displayed()
assert res, 'element not displayed!'

【讨论】:

【参考方案9】:

您可以通过可用方法查找元素,如果数组长度等于0的元素不存在,则检查响应数组长度。

element_exist = False if len(driver.find_elements_by_css_selector('div.eiCW-')) > 0 else True

【讨论】:

【参考方案10】:

当您知道该元素不存在时,隐式等待可能是个问题。我创建了一个简单的上下文管理器来避免这些等待时间

class PauseExplicitWait(object):
    """
    Example usage:

    with PauseExplicitWait(driver, 0):
        driver.find_element(By.ID, 'element-that-might-not-be-there')
    """
    def __init__(self, driver, new_wait=0):
        self.driver = driver
        self.original_wait = driver.timeouts.implicit_wait
        self.new_wait = new_wait
      
    def __enter__(self):
        self.driver.implicitly_wait(self.new_wait)
  
    def __exit__(self, exc_type, exc_value, exc_tb):
        self.driver.implicitly_wait(self.original_wait)
  

【讨论】:

【参考方案11】:

你可以通过find_elements检查,如果结果为null,则该元素不存在

if driver.find_elements(By.SOMETHING, "#someselector") == []:
    continue   # that element is not exist

【讨论】:

以上是关于使用 Python Selenium 检查元素是不是存在的主要内容,如果未能解决你的问题,请参考以下文章

使用 selenium 和 python 检查是不是存在任何警报

如何使用 Selenium WebDriver 检查元素是不是可点击

检查 Selenium Java 中的元素是不是可点击

使用 Selenium 和 Python,如何检查按钮是不是仍然可点击?

如何检查网页元素是不是可见

如何使用 selenium webdriver 检查按钮是不是可点击