Selenium Webdriver 的 wait.until 无效

1 投票
1 回答
6469 浏览
提问于 2025-04-20 17:48

我开始使用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 个回答

2

问题

你的等待是等到 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)

上面的代码已经过测试。

撰写回答