赞
踩
在selenium中,当我们定位的元素由于网络原因还没加载出来,浏览器找不到我们要定位的元素就会报错。等待方式的设置是保证脚本稳定有效运行的一个非常重要的手段,常用的等待方法有:
sleep() ——————————强制等待
implicitly_wait() —————— 隐式等待
WebDriverWait() —————— 显示等待
Python本身的函数,包含在time包中,使用前需要导入time包。执行 sleep()后线程休眠,而另外两种线程不休眠。固定的等待,常用于演示,调试,初学者观察效果。实际项目中不建议使用这种等待,由于网络的好坏导致等待时间不确定,如果设置的等待时间不足够长,元素找不到会报错,如果设置的等待时间过长,保证元素可以找到,但其实可能用不了这么久。这种等待方法十分笨拙,无论页面加载得如何,都必须等待n秒,可以说是十分不智能了。
但是强制等待也不是一无是处,比如界面操作完要关闭,但是最后你提交了一些数据,如果非常快的退出浏览器会丢失请求。那就需要强制等待一定时间,这个跟隐式等待还是显示等待都无关。再比如当我们没有找到元素而报错,定位问题时,可以先用sleep()来尝试一下,确定是否是由于等待时间的问题没有找到元素,如果是的话就可以用显示等待来代替。
from selenium import webdriver
from time import sleep
driver = webdriver.Chrome()
driver.get('https://www.baidu.com')
sleep(5)
ele = driver.find_element_by_id('kw')
ele.clear()
sleep(5)
ele.send_keys('淘宝官网')
sleep(5)
driver.quit()
原理:隐式等待,就是在创建driver时,为浏览器对象创建一个等待时间,这个方法是得不到某个元素就等待一段时间,直到拿到某个元素位置。注意:在使用隐式等待的时候,实际上浏览器会在你自己设定的时间内不断的刷新页面去寻找我们需要的元素 他是全局等待。是对页面中的所有元素设置加载时间。隐式等待可以理解成在规定的时间范围内,浏览器在不停的刷新页面,直到找到相关元素提前结束等待。如果超出了设置时间还未找到定位元素则抛出异常。但如果页面本身包含一个超大视频之类的文件,就算我们需要定位的元素在最开始已经加载出来,却依旧要等待所有文件加载结束之后,脚本才能继续执行,依旧算是有些弊端。implicitly_wait(最大等待时长)默认参数的单位为秒。如果在代码中你设置了隐式等待时长为10秒,首先这10秒并非一个固定的等待时间,它并不影响脚本的执行速度。其次,它并不针对页面上的某一元素进行等待。当脚本执行到某个元素定位时,如果元素可以定位,则继续执行,如果元素定位不到,则它将以轮询的方式不断地判断元素是否被定位到。假设在第六秒定位到了元素则继续执行,若直到超出设置的时长10秒还没有定位到元素,则抛出异常。用的时候直接用,不需要导入任何包。比如:driver.implicitly_wait(10)这样子,具体所有的会在下面的代码中有的。
缺点:隐式等待对于有些条件无法生效,比如url的改变,窗口的延迟新增,动态属性延迟加载……
显示等待是Selenium客户可以使用的命令式过程语言。主要思想是最长等待n秒,n秒内每隔一段时间去检查需要定位的元素是否存在(默认检测频率为0.5s),若存在则提前结束等待。若超时未找到则报错。默认抛出异常为:NoSuchElementException。这种等待比隐性等待更智能了一些,无视整个页面的加载,只要需要的元素存在了,就结束等待。显示等待不仅针对元素定位有效,而且可以针对某种行为(url的改变,属性的延迟加载)看它是否具备了一定的特征,就开始有所动作了。
用的时候需要导入WebDriverWait包。from selenium.webdriver.support.wait import WebDriverWait。函数详细介绍:WebDriverWait(driver,timeout,poll_frequency=0.5,ignored_exceptions=None)
driver:浏览器驱动
timeout:最长等待时间,默认以秒为单位
poll_frequency:监测的时间间隔,默认为0.5秒
ignored_exceptions:超时后的异常信息,默认情况下抛NoSuchElementException异常
WebDriverWait一般有until和until_not方法配合使用
until(method,message)
until_not(method ,message)
一般在实际工作脚本中我们要隐式等待+显示等待配合一起使用。至于为什么还要感谢我有一次使用了显示等待来代替隐式等待查找元素,结果就报错了。原因在于我只管了“登录”按钮(下面的例子里自己体会一下)以最有效的方式找到使用了显示等待,忽略其他要查找元素没有了隐式等待。所以在查找下一个按钮“账号登录”时候就报错了。正确的方式应该是隐式等待和显示等待一起用。隐式等待作用于全局,确保每一个你查找的元素都能够有足够的load时长,以便找到它使脚本正常运行。显示等待作用于你当前使用函数查找的这个元素,确保它快速高效的找到,显示等待不会管其他你要查找的元素的。
from selenium import webdriver import time from selenium.webdriver.common.action_chains import ActionChains from selenium.webdriver.support.ui import WebDriverWait url = 'https://www.csdn.net/' login_text = '登录' account_login = '账号登录' account = '自己注册一个' pwd = '自己注册一个' # 显式等待 得到这个元素在多长时间内 # 想要查找哪一个元素就可以将它抽象成一个函数 def get_ele_time(driver, times, func): return WebDriverWait(driver, times).until(func) def login_test(): # 实例化浏览器对象 打开浏览器 d = webdriver.Firefox() # 打开项目URL d.get('https://www.csdn.net/') # 将浏览器窗口最大化 d.maximize_window() # 隐式等待作用于全局 d.implicitly_wait(15) # 找到元素登录按钮login_text = '登录' # d.find_element_by_link_text(login_text).click() # 调用显示等待的函数 ele_login = get_ele_time(d, 5, lambda d: d.find_element_by_link_text(login_text)) ele_login.click() # time.sleep(10) # 由于网页重新跳转了页面,driver需要切换作用域 d.switch_to.window(d.window_handles[-1]) # 找到元素账号登录超链接account_login = ‘账号登录’ d.find_element_by_link_text(account_login).click() account_ele = d.find_element_by_id('all') account_ele.send_keys('') account_ele.clear() account_ele.send_keys(account) pwd_ele = d.find_element_by_id('password-number') pwd_ele.clear() pwd_ele.send_keys(pwd) d.find_element_by_class_name('btn-primary').click() time.sleep(5) try: text_err = d.find_element_by_id('js_err_dom').text if text_err == '用户名或密码错误': print(text_err) except: print('Account and Pwd Right!') d.quit() if __name__ == '__main__': login_test()
不要害怕显式等待的函数难,你就记住这两行代码就可以了。
# 得到某一个元素需要的时间
def get_ele_time(driver, times, func):
return WebDriverWait(driver, times).until(func)
# 在你想用显式等待查找元素时候调用这个函数,
ele_login是你要查找的这个元素。里面的driver, times, 自己对应写。
func照搬,只需要把后面的d.find_element_by_link_text(login_text)变一下,
你自己用什么方法查找元素的就行了。
ele_login = get_ele_time(d, 5, lambda d: d.find_element_by_link_text(login_text))
好了,我也是体会好久才理解到这样子,写的不对的还请给我指正。希望对大家有所帮助~~
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。