Selenium Webdriver 的 wait.until 无效
我开始使用Selenium Webdriver,但遇到了一个问题,主要是关于selenium.webdriver.support.wait里的until方法。下面是我的代码:
from selenium import webdriver
import time
from selenium.webdriver.support.select import Select
from selenium.webdriver.support.wait import WebDriverWait
url = "http://shop.uclastore.com/courselistbuilder.aspx"
driver = webdriver.Firefox()
driver.get(url)
time.sleep(1)
departments = Select(driver.find_element_by_id('clDeptSelectBox'))
for department in departments.options:
# select department
departments.select_by_value(department.get_attribute('value'))
elem = driver.find_element_by_xpath("//select[@id='clCourseSelectBox']//option")
print elem
print elem.get_attribute('value')
wait = WebDriverWait(driver, 10, 1.0)
wait.until(lambda driver: driver.find_element_by_xpath("//select[@id='clCourseSelectBox']//option"))
# time.sleep(1)
elem = driver.find_element_by_xpath("//select[@id='clCourseSelectBox']//option")
print elem
print elem.get_attribute('value')
print
问题是,当我在代码前后打印一些信息时,结果是:
<selenium.webdriver.remote.webelement.WebElement object at 0x108a4af50>
0
<selenium.webdriver.remote.webelement.WebElement object at 0x108a4af90>
0
<selenium.webdriver.remote.webelement.WebElement object at 0x108a4afd0>
0
<selenium.webdriver.remote.webelement.WebElement object at 0x108a4af10>
0
而当我把wait.until的代码注释掉,改用time.sleep时,结果变成了:
<selenium.webdriver.remote.webelement.WebElement object at 0x10378de90>
0
<selenium.webdriver.remote.webelement.WebElement object at 0x10378de50>
84082
<selenium.webdriver.remote.webelement.WebElement object at 0x10378df90>
0
<selenium.webdriver.remote.webelement.WebElement object at 0x103767110>
87846
到目前为止,我想到的一个可能性是,wait已经找到了elem,这意味着我们在第二个打印语句中不应该得到零值。但实际上并不是这样。所以现在我不知道发生了什么,需要一些帮助来弄清楚。
1 个回答
问题
你的等待是等到 driver.find_element_by_xpath("//select[@id='clCourseSelectBox']//option")
找到一个元素。但这是错误的测试方式。
这个页面的写法是这样的:“校园”和“学期”的下拉框(<select>
)里有一些选项(<option>
),并且有一个选项是预先选中的。而“系别”的下拉框里也有选项,但没有预选的选项。“课程”和“节次”的下拉框则是空的。
当选择了一个“系别”后,“课程”的下拉框才会填充选项。但是在这个下拉框填充之前,它会有一个占位符选项,里面的文字是“加载中...”。所以每次你查找 //select[@id='clCourseSelectBox']//option
时,都会找到这个占位符。在你使用 wait.until
的代码版本中,你找到的是这个占位符选项,而不是页面上的 JavaScript 代码有机会替换成真实选项之前的内容。而在你使用 time.sleep(1)
的代码版本中,你给了 JavaScript 一些时间去完成它的工作。不过要注意的是,你使用的 wait.until
调用正好做了你要求的事情。
解决方案
你可以等到选项的值不为 0:
wait.until(lambda driver: driver.find_element_by_xpath(
"//select[@id='clCourseSelectBox']//option").get_attribute("value") != "0")
请注意,get_attribute
需要在你的脚本和浏览器之间进行一次往返,这还不包括 find_element...
的往返。下面的代码做了同样的事情,但只需要一次往返:
def cond(driver):
return driver.execute_script("""
var option = document.querySelector("select#clCourseSelectBox>option");
return option.value !== "0";
""")
wait.until(cond)
上面的代码已经过测试。