Python 如何让SeleniumWeb驱动程序等待一个元素被访问,而不是仅仅出现?
我正在为一个web应用程序编写测试。某些命令会拉起对话框,其中的控件可见,但暂时不可用。(它们已灰显,但webdriver仍将它们视为可见) 我如何告诉Selenium等待元素真正可访问,而不仅仅是可见Python 如何让SeleniumWeb驱动程序等待一个元素被访问,而不是仅仅出现?,python,selenium,webdriver,Python,Selenium,Webdriver,我正在为一个web应用程序编写测试。某些命令会拉起对话框,其中的控件可见,但暂时不可用。(它们已灰显,但webdriver仍将它们视为可见) 我如何告诉Selenium等待元素真正可访问,而不仅仅是可见 try: print "about to look for element" element = WebDriverWait(driver, 10).until(lambda driver : driver.find_element_by_id("crea
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'
这是我尝试过的代码,但它在按钮可用之前“看到”了按钮,基本上在假定的“等待”之后充电
请注意,我可以在代码中填充10秒钟的睡眠时间,而不是这个时间,代码将正常工作,但这是丑陋的、不可靠的和低效的。但它确实证明了问题在于“单击”命令比控件的可用性快。我假设事件时间线是这样的:
//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>]
更新:
重新绘制与实际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>]
[1]中的:从selenium.webdriver导入Firefox
在[2]中:browser=Firefox()
在[3]:browser.get('file:///tmp/example.html')
在[4]:浏览器中。通过xpath('//input[@id=“createFolderCreateBtn”]'查找元素
出[4]:
[,
]
在[5]:浏览器中。通过xpath('//input[@id=“createFolderCreateBtn”而不是(@disabled)]查找元素
出[5]:
[]
更新2: 它也适用于此:
<input type="button" id="createFolderCreateBtn" disabled />
这就是我们的结局。(感谢lukeis和RossPatterson)注意,我们必须按id查找所有项目,然后按“disabled”过滤。我更喜欢单一的搜索模式,但是你能做什么呢?这里已经发布了一些很好的答案,但我想我会添加我的解决方案。显式等待等是用于硒测试的强大功能。然而,显式等待只执行只能设置一次的
Thread.Sleep()
函数。下面的功能是我用来“剃掉”几分钟的。它等待元素“可访问”
//THREAD.SLEEP的替代方案
公共静态类等待
{
//公共静态无效等待(此IWebDriver驱动程序,列表IWebElementLIst)
公共静态无效等待(此IWebDriver驱动程序由bylocator提供)
{
bool elementPresent=IsPresent.IsPresent(驱动程序、bylocator);
while(elementPresent!=真)
{
睡眠(1000);
elementPresent=IsPresent.IsPresent(驱动程序、bylocator);
}
}
}
这是C#,但要适应它并不难。希望这有帮助 我认为这方面的东西也应该奏效:
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)]")))
我认为这为我指明了正确的方向,但“残疾”似乎不是正确的属性。我想,当firebug不可用时,我需要用firebug抓住它。我希望我的电子游戏技能能达到速度挑战。@SkipHuffman,它也可以轻松成为css类。要捕获所需的页面状态,请执行以下操作:1。在找到元素后立即将
browser.page\u source
值存储在某个变量中。2.将该变量存储在.html
文件中。3.用chrome/firefox打开它,用firebug/developer console检查。css看起来可以做到type=“button”disabled=“disabled”id=“createFolderCreateBtn”在禁用时似乎是此控件的唯一属性。当按钮处于活动状态时,它将完全丢失“disabled”属性。(有道理。)现在我只需要重新设计css选择器来进行“这个,但不是那个”排序。(完成这项工作。也许我的思维过程会帮助其他人)。我可以找到元素为“\u css=”button[type=“button”][id=“createFolderCreateBtn”]”的按钮,这样它就可以搜索参数列表(一个类型为“button”、id为“createFolderCreateBtn”的按钮)。但是现在我需要添加一个否定搜索,如果属性包括'disabled=“disabled”',它应该会失败。我想现在我可以用编程的方式来做了,但我怀疑如果我对搜索字符串再聪明一点,我就能得到我所需要的东西了。@SkipHuffman仔细阅读了我最初的答案。我给了您有效的xpath选择器,该选择器与按钮匹配,按钮未被禁用://输入[@id=“createFolderCreateBtn”且未(@disabled)]
,请注意未(@disabled)
部分。毫无疑问,它工作正常。我正试图正确地定义它应该等待什么。在这种情况下,一个特定的元素,当它变得可用时,不仅仅是可见的。是的,对我来说是不精确的。我的意思是,当我想暂停的时候,我的测试马上就开始了。错误在于作为程序员的我,而不是作为工具的selenium。这个问题挽救了我的工作。只是澄清一下:我相信selenium中findElement的默认行为也是检查可见性。这与在DOM上检查“presence”不同,即使某些内容不可见,也可能返回true。您需要小心使用“isPresent”,因为当项目在DOM上但不可见时,它将返回true。在本线程中提出的问题的上下文中,您应该使用“isVisible”。此外,如果Selenium绑定允许,使用ExpectedCondition也是一个好主意。事实上,findElement的默认行为是(我认为是).isVisible而不是.isPresent。如果元素在1010毫秒或更长时间后被启用,该怎么办?你的考试会失败。如果加载的元素介于300毫秒到500毫秒之间,那么您的测试就是在浪费时间。时间不多,但是当您使用这个等待几个元素时,它可以加起来。
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()
//ALTERNATIVE FOR THREAD.SLEEP
public static class Wait
{
//public static void wait(this IWebDriver driver, List<IWebElement> IWebElementLIst)
public static void wait(this IWebDriver driver, By bylocator)
{
bool elementPresent = IsPresent.isPresent(driver, bylocator);
while (elementPresent != true)
{
Thread.Sleep(1000);
elementPresent = IsPresent.isPresent(driver, bylocator);
}
}
}
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)]")))