如何让Selenium Web Driver等待元素可访问,而非仅仅存在?
我正在为一个网页应用写测试。有些命令会弹出对话框,里面有一些控件,这些控件虽然可见,但在几秒钟内是无法使用的。(它们是灰色的,但webdriver依然认为它们是可见的。)
我该如何让Selenium等到这些元素真正可以使用,而不仅仅是可见呢?
try:
print "about to look for element"
element = WebDriverWait(driver, 10).until(lambda driver : driver.find_element_by_id("createFolderCreateBtn"))
print "still looking?"
finally: print 'yowp'
这是我尝试过的代码,但它在按钮还不能用的时候就“看到了”这个按钮,结果直接跳过了应该“等待”的部分。
需要注意的是,我可以在代码里加一个十秒的暂停,这样代码就能正常工作,但这样做既不优雅,又不可靠,也不高效。不过,这确实证明了问题在于“点击”命令跑得太快,超过了控件可用的时间。
4 个回答
1
我觉得下面这样的代码也应该可以用:
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions
browser = webdriver.Firefox()
wait = WebDriverWait(browser, 30)
wait.until(expected_conditions.presence_of_element_located((By.XPATH, "//*[@id='createFolderCreateBrn' and not(@disabled)]")))
17
我假设事件的时间线是这样的:
- 页面上没有需要的元素。
- 需要的元素出现了,但它是禁用的:
<input type="button" id="createFolderCreateBtn" disabled="disabled" />
- 需要的元素变成可用的:
<input type="button" id="createFolderCreateBtn" />
目前你是通过ID来查找元素的,你在第二步找到了一个,但那是你不需要的。你需要做的是通过xpath来查找它:
//input[@id="createFolderCreateBtn" and not(@disabled)]
这里是它们之间的区别:
from lxml import etree
html = """
<input type="button" id="createFolderCreateBtn" disabled="disabled" />
<input type="button" id="createFolderCreateBtn" />
"""
tree = etree.fromstring(html, parser=etree.HTMLParser())
tree.xpath('//input[@id="createFolderCreateBtn"]')
# returns both elements:
# [<Element input at 102a73680>, <Element input at 102a73578>]
tree.xpath('//input[@id="createFolderCreateBtn" and not(@disabled)]')
# returns single element:
# [<Element input at 102a73578>]
总结一下,这就是你修正后的代码:
try:
print "about to look for element"
element_xpath = '//input[@id="createFolderCreateBtn" and not(@disabled)]'
element = WebDriverWait(driver, 10).until(
lambda driver : driver.find_element_by_xpath(element_xpath)
)
print "still looking?"
finally:
print 'yowp'
更新:
重新粘贴一下,使用实际的webdriver。
这是example.html
页面的代码:
<input type="button" id="createFolderCreateBtn" disabled="disabled" />
<input type="button" id="createFolderCreateBtn" />
这是ipython会话:
In [1]: from selenium.webdriver import Firefox
In [2]: browser = Firefox()
In [3]: browser.get('file:///tmp/example.html')
In [4]: browser.find_elements_by_xpath('//input[@id="createFolderCreateBtn"]')
Out[4]:
[<selenium.webdriver.remote.webelement.WebElement at 0x103f75110>,
<selenium.webdriver.remote.webelement.WebElement at 0x103f75150>]
In [5]: browser.find_elements_by_xpath('//input[@id="createFolderCreateBtn" and not(@disabled)]')
Out[5]:
[<selenium.webdriver.remote.webelement.WebElement at 0x103f75290>]
更新 2:
这个方法也可以用:
<input type="button" id="createFolderCreateBtn" disabled />
13
print time.time()
try:
print "about to look for element"
def find(driver):
e = driver.find_element_by_id("createFolderCreateBtn")
if (e.get_attribute("disabled")=='true'):
return False
return e
element = WebDriverWait(driver, 10).until(find)
print "still looking?"
finally: print 'yowp'
print "ok, left the loop"
print time.time()
这是我们最后得到的结果。(感谢lukeis和RossPatterson的帮助。)请注意,我们必须先通过ID找到所有的项目,然后再筛选出“禁用”的项目。我本来希望能有一个简单的搜索方式,但没办法,只能这样做。