Background:
UI自动化过程中,必然会遇到环境不稳定,网络慢情况,加载问题,如果不做任何处理就会因为没有找到元素而报错。另外一种情况就是页面使用了ajax异步加载机制(现在都是resetful,客户端和服务端都是分离的),不知道页面是什么时候到达的。这时我们就要用到wait,而在selenium中,我们一共又三种等待。
1.time.sleep(固定等待)
- 本质:让当前的线程睡眠,实质是线程的阻塞(blocking),用wait方式实现。
- 缺点:网络条件好浪费时间,严重影响项目的性能
- 好处:调试脚本可以用
2.implicitly_wait(隐式等待)
- 本质:在脚本的开始设置一个最长等待时间,如果在规定时间内网页加载完成,则执行下一步;否则可能抛出异常。隐式等待对整个driver周期都起作用,在最开始设置一次就可以了,不要当作固定等待使用。
- 缺点:Javascript一般都是放在我们的body的最后进行加载,实际这时页面的元素都已经加载完毕,我们却还在等待全部页面加载结束。
3.WebDriverWait(显式等待)
-
本质:动态的等待,判断某一个元素是不是已经出现了,比如title是不是叫百度或百度搜索,根据动态的一些条件来轮询,它会不停的轮询去给我们检测,条件是成功还是失败,比如0.5s就检测一次这个元素在这个条件下是成功还是失败。同时设置轮询的超时时间。
-
WebDriverWait是Selenium提供得到显示等待模块引入路径
-
引入方式:
from selenium.webdriver.support.wait import WebdriveWait
-
WebdriveWait参数 | # | 参数 | 参数说明 | | --- | --- | --- | | 1 | driver | 传入WebDriver实例 | | 2 | timeout | 超出时间,等待的最长时间 | | 3 | poll_frequency | 调用until或until_not中的方法的间隔时间,默认是0.5s | | 4 | ignored_exceptions | 忽略的异常 |
-
两种方法
until
与until_not
: -
until()
调用该方法提供的驱动作为一个参数,直到返回值为True;
-
unitl_not()
调用该方法提供的驱动作为一个参数,直到返回值为False | # | 参数 | 参数说明 | | --- | --- | --- | | 1 | method | 在等待期间,每隔一段时间用这个传入的方法,直到返回值不是false | | 2 | message | 如果超时,抛出Timeoutexception,将message传入异常 |
-
注意事项:
WebDriverWait
的方法要传入几个参数,第一个是传入WebDriver的实例:driver,第二个是传入超时时间,timeout,就是比如传入3秒,3秒还没有成功就跑出超时异常- 如果既设置了隐式等待也设置了显式等待,那么程序会根据谁设置的超时时间越长来按照它的执行
特别注意的是until
或until_not
中的可执行方法method参数,不能传入了WebElement对象,如下:
# 错误
WebDriverWait(self.driver, 3).until(self.driver.find_element_by_id('kw'))
这是错误的用法,这里的参数一定要是可以调用的,即这个对象一定有_ _call__()
方法,否则会抛出异常: TypeError: 'xxx' object is not callable
。可以用Selenium提供的expected_conditions模块中的各种条件,也可以用WebElement的is_displayed()
、is_enabled()
、is_selected()
方法,或者用自己封装的方法。
显式等待和隐式等待的区别:
隐式等待只需设置一次,后面都会生效。显式等待根据条件设置,条件成立就执行,条件不成立就继续等待,如果到达时间了就会跑出timeout异常。
实例Code:
from selenium import webdriver
from time import sleep
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait
class TestCase(object):
def __init__(self):
self.driver = webdriver.Chrome()
self.driver.get('http://www.baidu.com')
# time.sleep(固定等待)
def test_sleep(self):
self.driver.find_element_by_id('kw').send_keys('Selenium')
# 线程阻塞 blocking wait 2s
sleep(2)
self.driver.find_element_by_id('su').click()
sleep(2)
self.driver.quit()
# implicitly_wait(隐形等待)
def test_implicitly(self):
# 全局最长等待10s
self.driver.implicitly_wait(10)
self.driver.find_element_by_id('kw').send_keys('Selenium')
self.driver.find_element_by_id('su').click()
self.driver.quit()
# WebDriverWait(显性等待)
def test_wait(self):
# 1.传入WebDriverWait的实例 2.传入超时时间,timeout
wait = WebDriverWait(self.driver, 2)
# 等待页面标题加载成功
wait.until(EC.title_is('百度一下,你就知道'))
# 传入driver参数,然后超时时间为2秒,再调用until方法,去获取标题是不是和设置的一样,如果是返回true,执行下一步,如果不是,就继续请求,每0.5秒请求一次,2秒结束后还没有成功,就抛出超时异常
self.driver.find_element_by_id('kw').send_keys('Selenium')
self.driver.find_element_by_id('su').click()
self.driver.quit()
if __name__ == '__main__':
case = TestCase()
# case.test_sleep()
# case.test_implicitly()
case.test_wait()