前言
在脚本中加入太多的sleep后会影响脚本的执行速度,虽然implicitly_wait()这种方式隐式等待方法一定程度上节省了很多时间。
但是一旦页面上某些js无法加载出来(其实界面元素已经出来了),左上角那个图标一直转圈,这时候会一直等待的。
一、WebDriverWait参数解释
1.WebDriverWait有4个参数:
WebDriverWait(driver,timeout,poll_frequency=0.5,ignored_exceptions=None)
需要通过 from selenium.webdriver.support.wait import WebDriverWait 导入模块
- driver:返回浏览器的一个实例,浏览器驱动
- timeout:超时的总时长,默认以秒为单位
- poll_frequency:循环去查询的间隙时间,默认0.5秒
- ignored_exceptions:超时后的抛出的异常信息,默认抛出NoSuchElementException异常
以下是源码的解释文档
class WebDriverWait(object):
def __init__(self, driver, timeout, poll_frequency=POLL_FREQUENCY, ignored_exceptions=None):
"""Constructor, takes a WebDriver instance and timeout in seconds.
:Args:
- driver - Instance of WebDriver (Ie, Firefox, Chrome or Remote)
- timeout - Number of seconds before timing out
- poll_frequency - sleep interval between calls
By default, it is 0.5 second.
- ignored_exceptions - iterable structure of exception classes ignored during calls.
By default, it contains NoSuchElementException only.
Example:
from selenium.webdriver.support.ui import WebDriverWait \n
element = WebDriverWait(driver, 10).until(lambda x: x.find_element_by_id("someId")) \n
is_disappeared = WebDriverWait(driver, 30, 1, (ElementNotVisibleException)).\ \n
until_not(lambda x: x.find_element_by_id("someId").is_displayed())
"""
self._driver = driver
self._timeout = timeout
self._poll = poll_frequency
# avoid the divide by zero
if self._poll == 0:
self._poll = POLL_FREQUENCY
exceptions = list(IGNORED_EXCEPTIONS)
if ignored_exceptions is not None:
try:
exceptions.extend(iter(ignored_exceptions))
except TypeError: # ignored_exceptions is not iterable
exceptions.append(ignored_exceptions)
self._ignored_exceptions = tuple(exceptions)
def __repr__(self):
return '<{0.__module__}.{0.__name__} (session="{1}")>'.format(
type(self), self._driver.session_id)
def until(self, method, message=''):
"""Calls the method provided with the driver as an argument until the \
return value is not False."""
screen = None
stacktrace = None
end_time = time.time() + self._timeout
while True:
try:
value = method(self._driver)
if value:
return value
except self._ignored_exceptions as exc:
screen = getattr(exc, 'screen', None)
stacktrace = getattr(exc, 'stacktrace', None)
time.sleep(self._poll)
if time.time() > end_time:
break
raise TimeoutException(message, screen, stacktrace)
def until_not(self, method, message=''):
"""Calls the method provided with the driver as an argument until the \
return value is False."""
end_time = time.time() + self._timeout
while True:
try:
value = method(self._driver)
if not value:
return value
except self._ignored_exceptions:
return True
time.sleep(self._poll)
if time.time() > end_time:
break
raise TimeoutException(message)
与until()或者until_not()方法结合使用
WebDriverWait(driver,10).until(method,message="")
#调用该方法提供的驱动程序作为参数,直到返回值为True
WebDriverWait(driver,10).until_not(method,message="")
#调用该方法提供的驱动程序作为参数,直到返回值为False
在设置时间(10s)内,等待后面的条件发生。如果超过设置时间未发生,则抛出异常。
在等待期间,每隔一定时间(默认0.5秒),调用until或until_not里的方法,直到它返回True或False。
WebDriverWait与expected_conditions结合使用
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
wait = WebDriverWait(driver,10,0.5)
element =waite.until(EC.presence_of_element_located((By.ID,"kw"),message=""))
# 此处注意,如果省略message=“”,则By.ID外面是两层()
如下实例,使用了匿名函数lambda、expected_condtions的presence_of_element_located方法(判断某个元素是否被加到了 dom 树里,并不代表该元素一定可见)
# coding:utf-8
from selenium import webdriver
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
driver = webdriver.Chrome()
driver.get("https://www.baidu.com")
WebDriverWait(driver, 10, 0.5).until(EC.presence_of_element_located((By.ID, "kw"))).send_keys("xixi")
WebDriverWait(driver,3).until(EC.presence_of_element_located(("id","kw"))).send_keys("_on_")
WebDriverWait(driver,5).until(lambda x: x.find_element("id","kw")).send_keys("_good_")
WebDriverWait(driver, 10, 0.5).until_not(lambda driver: driver.find_element_by_id("kw")).send_keys("hehe")
# a=lambda x:x+22
# print(a(5))
运行结果:
Traceback (most recent call last):
File "E:/study/selenium_study/a825.py", line 12, in
WebDriverWait(driver, 10, 0.5).until_not(lambda driver: driver.find_element_by_id("kw")).send_keys("hehe")
File "D:\Program Files\python37\lib\site-packages\selenium\webdriver\support\wait.py", line 96, in until_not
raise TimeoutException(message)
selenium.common.exceptions.TimeoutException: Message:
二、强制等待:sleep()
import time
sleep(5) #等待5秒
设置固定休眠时间,单位为秒。由python的time包提供,导入time包后就可以使用。
缺点:不智能,使用太多的sleep会影响脚本运行速度。
三、隐式等待:implicitly_wait()
driver.implicitly_wait(10) #隐式等待10秒
由webdriver提供的方法,一旦设置,这个隐式等待会在WebDriver对象实例的整个生命周期起作用,它不针对某一个元素,是全局元素等待,即在定位元素时,需要等待页面全部元素加载完成,才会执行下一个语句。如果超出 了设置时间的则抛出异常。
缺点:当页面某些js无法加载,但是想找的元素已经出来了,它还是会继续等待,知道页面加载完成(浏览器标签左上角圈圈不再转),才会执行下一句。某些情况下会影响脚本执行速度。