我们通过 WebDriver 查找控件或者操作控件的时候,如果被查找或被操作的控件不存在,就会报异常。其实很多种情况下由于网速问题,我们查找或操作的控件还没来得及出现,这时候 WebDriver 的代码就会误以为控件不存在而报异常。如果我们的代码能等待一段时间就好了,就是说在一定时间内能查找到或操作到这个控件是合理的,超越我们定的时间就认为控件不存在,然后报异常。
WebDriver 提供了两种类型的等待:显式等待和隐式等待。
WebDriverWait 是由 WebDirver 提供的显示等待类。在设置时间内,默认每隔一段时间检测一次当前页面元素是否存在,如果超过设置时间检测不到则抛出异常。
implicitly_wait() 是由 WebDriver 提供的隐式等待方法,默认设置为 0。它的用法相对来说要简单得多。
显式等待使 WebdDriver 等待某个条件成立时继续执行,否则在达到最大时长时抛出超时异常(TimeoutException)。
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.Chrome() driver.get("http://www.baidu.com") ''' 类: WebDriverWait(driver, timeout, poll_frequency=0.5, ignored_exceptions=None) 参数: driver :浏览器驱动。 timeout :最长超时时间,默认以秒为单位。 poll_frequency :检测的间隔(步长)时间,默认为0.5S。 ignored_exceptions :超时后的异常信息,默认情况下抛NoSuchElementException异常。 类和函数说明: WebDriverWait() 一般由 until() 或 until_not() 方法配合使用,下面是 until() 和 until_not() 方法的说明。 until(method, message=""):调用该方法提供的驱动程序作为一个参数,直到返回值为 True。 until_not(method, message=""):调用该方法提供的驱动程序作为一个参数,直到返回值为 False。 在本例中,通过 as 关键字将 expected_conditions 重命名为 EC,并调用 presence_of_element_located() 方法判断元素是否存在。 ''' element = WebDriverWait(driver, 5, 0.5).until(EC.presence_of_element_located((By.ID, "kw"))) element.send_keys('selenium') driver.quit()
implicitly_wait() 默认参数的单位为秒,我们下面的例子中设置等待时长为 10 秒。首先这 10 秒并非一个固定的等待时间,它并不影响脚本的执行速度。其次,它并不针对页面上的某一元素进行等待。当脚本执行到某个元素定位时,如果元素可以定位,则继续执行;如果元素定位不到,则它将以轮询的方式不断地判断元素是否被定位到。假设在第 6 秒定位到了元素则继续执行,若直到超出设置时长(10秒)还没有定位到元素,则抛出异常。
from selenium import webdriver from selenium.common.exceptions import NoSuchElementException from time import ctime driver = webdriver.Firefox() # 设置隐式等待为10秒 driver.implicitly_wait(10) driver.get("http://www.baidu.com") try: print(ctime()) driver.find_element_by_id("kw22").send_keys('selenium') except NoSuchElementException as e: print(e) finally: print(ctime()) driver.quit()
如果我们不想使用 selenium 自带的显示等待或隐式等待方法,我们完全可以自己写出等待的逻辑代码。
import time ''' 功能: securityfind 函数在规定时间查找到控件并返回该控件,否则返回 None,默认查找 30 次,每次查找后等待 1 秒。 参数说明: driver:控制浏览器的 webdriver。 tagname:要查找的控件名称,打印出来,给用户自己自己看的。 strtag:查找语法。 flag:查找方法,比如 by_id,by_class_name 等等。 intertime:查找一次等待多久,默认 1 秒。 count:总共查找多少次,默认 30 次。 ''' def securityfind(driver, tagname, strtag, flag, intertime = 1, count = 30): nowcount = 0 while nowcount < count: time.sleep(intertime) try: if flag == "by_id": result = driver.find_element_by_id(strtag) elif flag == "by_name": result = driver.find_element_by_name(strtag) elif flag == "by_class_name": result = driver.find_element_by_class_name(strtag) elif flag == "by_tag_name": result = driver.find_element_by_tag_name(strtag) elif flag == "by_link_text": result = driver.find_element_by_link_text(strtag) elif flag == "by_partial_link_text": result = driver.find_element_by_partial_link_text(strtag) elif flag == "by_xpath": result = driver.find_element_by_xpath(strtag) elif flag == "by_css_selector": result = driver.find_element_by_css_selector(strtag) print "规定时间内找到:" + tagname return result # 找到 tag 就返回 except: nowcount += 1 print("没找到" + tagname + str(nowcount) + "次") print("规定时间次数内没找到:" + tagname) return None
我们现在举例来使用上面我们自己写的查找等待函数。
from selenium import webdriver import securityfind # 导入我们自己写的函数 driver = webdriver.Chrome() driver.get("http://www.baidu.com") element = securityfind(driver, "百度搜索框", "kw", "by_id", 1, 10) if element != None: element.send_keys('selenium') else: print("控件不存在") driver.quit()
发现一个问题,想把91上的视频链接抓下来,但是必须在页面加载完毕后点击视频框中的play按钮,通过抓包拿的链接,想问一下,是否可以通过python或是seleium获取这个http请求
请问这个显示等待能判断ajax的数据回来与否么?元素一直都在只是ajax之后会改变元素的值。
显示等待和隐式等待到底什么区别啊?我查了半天也没明白。 比如都是10秒,隐式等待是及时找到元素了照样等待10秒,超过10秒还没找到就抛异常。显式等待是找到了就不等了,超过10秒还没找到就抛异常?求指教
博主牛逼,自己写的好用
自己写的等待方法很强大啊