三种等待方式:sleep
- 强制等待, sleep,设置等待多长时间,就要等待多长时间。等待完成后,才会继续下一步:
from selenium import webdriver
# 导入sleep
from time import sleep
# 创建谷歌浏览器对象
chrome_driver = webdriver.Chrome()
# 访问百度
chrome_driver.get("http://www.baidu.com")
# 定位登录按钮并进行点击
chrome_driver.find_element_by_xpath('//*[@id="s-top-loginbtn"]').click()
# 设置等待时间,单位是秒
sleep(3)
- 相比较于sleep的强制等待,selenium中还有种等待,可以称之为智能等待:implicitly_wait。所谓智能等待,就是在我设置的等待时间范围内,只要满足了我的条件,就会立即结束等待,继续往下进行,如果超时,则抛出异常。
implicitly_wait也称之为隐性等待,不需要导入,直接使用webdriver对象调用。它主要执行两件事情,等待元素找到,执行命令。还以刚才的代码为例子,如果我们创建了webdriver对象之后,直接设置implicitly_wait等待,等待一旦设置,那么这个等会在浏览器对象的整个生命周期起作用:
# 创建谷歌浏览器对象
chrome_driver = webdriver.Chrome()
# 智能等待,在设置时间范围内,只要条件成立,马上结束等待, implicitly_wait
chrome_driver.implicitly_wait(5)
# 访问百度
chrome_driver.get("http://www.baidu.com")
# 定位登录按钮并进行点击,在5s之内,找到元素,会立即点击
chrome_driver.find_element_by_xpath('//*[@id="s-top-loginbtn"]').click()
# 设置一个找不到的元素,会进行等待,等待5s后,依旧找不带,会抛出异常
chrome_driver.find_element_by_xpath('//*[@id="s-top-loginbtn1"]').click()
效果:
- 最后一种等待,显性等待。相较于隐性等待,这个显性等待要明确等待条件和等待上限。比如隐性等待,只要元素存在,可找到就可以,但显性等待,我要明确条件是我的元素可见。而元素存在,并不一定是元素可见。
显性等待的场景:操作引起了页面的变化,而接下来要操作变化的元素的时候,就需要使用显性等待。
显性等待导入:
from selenium.webdriver.support.wait import WebDriverWait
WebDriverWait在创建对象时,需要传入三个参数:
WebDriverWait(driver,timeout,poll_frequency=0.5,ignored_exceptions=None)
driver:浏览器驱动
timeout:等待上限,单位是秒
poll_frequency:检测的轮询间隔,默认值是0.5秒
ignored_exceptions:超时后的抛出的异常信息,默认抛出NoSuchElementExeception异常。
创建WebDriverWait()对象后,要结合until()或者until_not()和expected_conditions类使用。
比如,等待元素id="TANGRAM__PSP_11__changeSmsCodeItem"加载到dom树中:
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
# 使用显性等待, 等待元素id="TANGRAM__PSP_11__changeSmsCodeItem"加载到dom树中,等待上限是10s,每0.8秒去验证一下条件是否成立.
WebDriverWait(chrome_driver, 10, 0.8).until(EC.presence_of_element_located((By.ID,
'TANGRAM__PSP_11__changeSmsCodeItem')))
还是以百度首页登录界面为例子,比如点击登录后,在登录界面点击短信登录进行切换:
当我们不点击登录时,发现在dom树中,根本没有短信登录的元素,所以,我们要想点击这个元素,那就需要等待这个元素加载到dom树中,可以找到才行:
用显性等待,代码:
from selenium import webdriver
from time import sleep
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
# 创建谷歌浏览器对象, 会话开始
chrome_driver = webdriver.Chrome()
# 访问百度
chrome_driver.get("http://www.baidu.com")
# 定位登录按钮并进行点击
chrome_driver.find_element_by_xpath('//*[@id="s-top-loginbtn"]').click()
sleep(5)
# 使用显性等待, 等待元素id="TANGRAM__PSP_11__changeSmsCodeItem"加载到dom树中,等待上限是10s,每0.8秒去验证一下条件是否成立.
WebDriverWait(chrome_driver, 10, 0.8).until(EC.presence_of_element_located((By.ID,
'TANGRAM__PSP_11__changeSmsCodeItem')))
chrome_driver.find_element_by_id('TANGRAM__PSP_11__changeSmsCodeItem').click()
效果:
下面继续基于这一行代码解释:
WebDriverWait(chrome_driver, 10, 0.8).until(EC.presence_of_element_located((By.ID,
'TANGRAM__PSP_11__changeSmsCodeItem')))
By.ID,By是webdriver定义好的一个类,这个类只有8个常量,定义了八种元素定位的方式,一般当我们要传入一个元素定位时,会使用到,比如上面的presence_of_element_located的方法,要传入的参数要求是一个定位:
presence_of_element_located是等待元素加载到dom树中的方法,属于expected_conditions类。expected_conditions还有提供了很多的条件判断方法:
方法 | 说明 |
---|---|
title_is | 判断当前页面的 title 是否完全等于(==)预期字符串,返回布尔值 |
title_contains | 判断当前页面的 title 是否包含预期字符串,返回布尔值 |
presence_of_element_located | 判断元素是否被加到了 dom 树里(注意,加载到dom树中,并不代表这个元素可见) |
visibility_of_element_located | 判断元素是否可见 |
visibility_of | 同visibility_of_element_located方法,只是visibility_of_element_located方法参数为locator,这个方法参数是 定位后的元素 |
presence_of_all_elements_located | 判断是否至少有 1 个元素存在于 dom 树中。举例:如果页面上有 n 个元素的 class 都是’wp’,那么只要有 1 个元素存在,这个方法就返回 True |
text_to_be_present_in_element | 判断某个元素中的 text 是否 包含 了预期的字符串 |
text_to_be_present_in_element_value | 判断某个元素中的 value 属性是否包含 了预期的字符串 |
frame_to_be_available_and_switch_to_it | 判断该 frame 是否可以 switch进去,如果可以的话,返回 True 并且 switch 进去,否则返回 False |
invisibility_of_element_located | 判断某个元素中是否不存在于dom树或不可见 |
element_to_be_clickable | 判断某个元素中是否可见并且可点击 |
staleness_of | 等某个元素从 dom 树中移除,注意,这个方法也是返回 True或 False |
element_to_be_selected | 判断某个元素是否被选中了,一般用在下拉列表 |
element_selection_state_to_be | 判断某个元素的选中状态是否符合预期 |
element_located_selection_state_to_be | 跟上面的方法作用一样,只是上面的方法传入定位到的 element,而这个方法传入 locator |
alert_is_present | 判断页面上是否存在 alert |