Waits

现在很多Web应用都在使用AJAX技术。浏览器载入一个页面时,页面内的元素可能是在不同的时间载入的,这会加大定位元素的困难程度,因为元素不在DOM里,会抛出ElementNotVisibleException异常,使用waits,我们就可以解决这个问题。Waiting给(页面)动作的执行提供了一些时间间隔-通常是元素定位或者其他对元素的操作。

Selenium WebDriver提供了两类waits- 隐式和显式。显式的waits会让WebDriver在更深一步的执行前等待一个确定的条件触发,隐式的waits则会让WebDriver试图定位元素的时候对DOM进行指定次数的轮询。

显式Waits

显式的waits等待一个确定的条件触发然后才进行更深一步的执行。最糟糕的的做法是time.sleep(),这指定的条件是等待一个指定的时间段。 这里提供一些便利的方法让你编写的代码只等待需要的时间,WebDriverWait结合ExpectedCondition是一种实现的方法:

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 as EC

driver = webdriver.Firefox()
driver.get("http://somedomain/url_that_delay_loading")
try:
    element = WebDriverWait(driver,10).until(
        EC.presence_of_element_located((By.ID,"myDynamicElement"))
    )
finally:
    driver.quit()

这段代码会等待10秒,如果10秒内找到元素则立即返回,否则会抛出TimeoutException异常,WebDriverWait默认每500毫秒调用一下ExpectedCondition直到它返回成功为止。ExpectedCondition类型是布尔的,成功的返回值就是true,其他类型的ExpectedCondition成功的返回值就是 not null

详细的ExpectedCondition可以参看 7.6 浏览器驱动

预期条件

自动化网页操作时,有许多频繁使用到的通用条件。下面列出的是每一个条件的实现。Selenium + Python 提供了许多方便的方法,因此你不需要自己编写expected_condition的类,或者创建你自己的通用包。

  • title_is
  • title_contains
  • presence_of_element_located
  • visibility_of_element_located
  • visibility_of
  • presence_of_all_elements_located
  • text_to_be_present_in_element
  • text_to_be_present_in_element_value
  • frame_to_be_available_and_switch_to_it
  • invisibility_of_element_located
  • element_to_be_clickable - 元素展示并且可用
  • staleness_of
  • element_to_be_selected
  • element_located_to_be_selected
  • element_selection_state_to_be
  • element_located_selection_state_to_be
  • alert_is_present
from selenium.webdriver.support import expected_conditions as EC

wait = WebDriverWait(driver,10)
element = wait.until(EC.element_to_be_clickable((By.ID,'someid')))

expected_conditions模块包含了一系列预定义的条件来和WebDriverWait使用

隐式Waits

当我们要找一个或者一些不能立即可用的元素的时候,隐式waits会告诉WebDriver轮询DOM指定的次数,默认设置是0次。一旦设定,WebDriver对象实例的整个生命周期的隐式调用也就设定好了。

from selenium import webdriver

driver = webdriver.Firefox()
driver.implicitly_wait(10) # seconds
driver.get("http://somedomain/url_that_delays_loading")
myDynamicElement = driver.find_element_by_id('myDynamicElement')

以下根据stackoverflow网友回答添加:原问题链接 推荐一直用显式的,忘记还有隐式吧(Always use explicit wait. Forget that implicit wait exists)

显示waits: 明确的行为表现 在本地的selenium运行(你选择的编程语言) 可以在任何你能想到的条件下工作 返回成功或者超时 可以定义元素的缺失为条件 可以定制重试间隔,可以忽略某些异常

隐式waits: 不明确的行为表现,同一个问题依赖于不同的操作系统,不同的浏览器,不同的selenium版本会有各种不同的表现 在远程的selenium上运行(控制浏览器的那部分). 只能在寻找元素的函数上工作 返回找到元素或者(在超时以后)没有找到 如果检查元素缺失那么总是会等待到超时 除了时间啥都不能指定