selenium三种等待方式

为什么需要设置元素等待?

因为,目前大多数Web应用程序都是使用Ajax和Javascript开发的;每次加载一个网页,就会加载各种HTML标签、JS文件
但是,加载肯定有加载顺序,大型网站很难说一秒内就把所有东西加载出来,不仅如此,加载速度也受网络波动影响
因此,当我们要在网页中做元素定位的时候,有可能我们打开了网页但元素未加载出来,这个时候就定位不到元素,就会报错
所以,我们需要设置元素等待,意思就是:等待指定元素已被加载出来之后,我们才去定位该元素,就不会出现定位失败的现象了

强制等待

sleep()
但是缺点就是:如果指定的时间过长,即使元素已被加载出来了,但还是要继续等,这样会浪费很多时间
强制等待的栗子

import time

from selenium import webdriver
from selenium.common.exceptions import ElementNotVisibleException
from selenium.webdriver.support.wait import WebDriverWait


class Test_Demo():
    def setup(self):
        self.driver=webdriver.Chrome()
        self.driver.maximize_window()

        self.driver.implicitly_wait(10)
    def teardown(self):
        self.driver.quit()


    def test_1(self):
        self.driver.get("https://testerhome.com/")

        self.driver.find_element_by_link_text('社团').click()
        self.driver.find_element_by_link_text('Appium 中文文档小组').click()
        # 强行等待3s
        time.sleep(3)
        self.driver.find_element_by_class_name('node').click()
        
        

WebDriver提供了两种类型的等待:显式等待和隐式等待

隐式等待

什么是隐式等待?
如果某些元素不是立即可用的,隐式等待是告诉WebDriver去等待一定的时间后去查找元素
默认等待时间是0秒,隐式等待对整个WebDriver的周期都起作用,所以只要设置一次即可
如何体现隐式等待?
如果在规定时间内,整个网页都加载完成,则执行下一步,否则会抛出异常

隐式等待的弊端
可以把隐式等待当做全局变量,它影响整个页面,所以程序需要等待整个页面加载完成(就是浏览器标签栏那个小圈不再转)时,才会执行下一步【页面加载完成,才能执行下一步】
但可能页面加载未完成的时候,需要定位的元素已经加载完成了,但受限于某些JS文件、图片加载特别慢,我们不能执行下一步,必须得等到网页所有东西都加载完了才能下一步【增加不必要的加载时间】

隐式等待的代码

import time

from selenium import webdriver
from selenium.common.exceptions import ElementNotVisibleException
from selenium.webdriver.support.wait import WebDriverWait


class Test_Demo():
    def setup(self):
        self.driver=webdriver.Chrome()
        self.driver.maximize_window()
        # 隐式等待
        self.driver.implicitly_wait(10)
    def teardown(self):
        self.driver.quit()


    def test_1(self):
        self.driver.get("https://testerhome.com/")

        self.driver.find_element_by_link_text('社团').click()
        self.driver.find_element_by_link_text('Appium 中文文档小组').click()
        ele=WebDriverWait(self.driver,10).until(lambda x:x.find_element_by_class_name('node'))
        ele.click()
显式等待

什么是显式等待?
需要定位某个元素的时候,但元素可能不可见,这个时候针对这个元素就可以使用显式等待了
显式等待和隐式等待最大的不同就是:你可以它看成是局部变量,作用于指定元素
显式等待的优势
相比隐式等待,显式等待只对指定元素生效,不再是在整个WebDriver生命周期内生效【仅对元素生效】

可以根据需要定位的元素来设置显式等待,无需等待页面完全加载,节省大量因加载无关紧要文件而浪费掉的时间【针对元素设置,无需等待页面加载完成,节省加载时间】
WebDriverWait,配合该类的until()和until_not()方法,就能够根据判断条件而进行灵活地等待了。它主要的意思就是:程序每隔xx秒看一眼,如果条件成立了,则执行下一步,否则继续等待,直到超过设置的最长时间,然后抛出TimeoutException。

显式等待的代码

from selenium.webdriver.common.by import By
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

driver = webdriver.Chrome()

# 访问网址
driver.get("http://www.baidu.com")

# ===显式等待===

# 设置元素等待实例,最多等10秒,每0.5秒查看条件是否成立
element = WebDriverWait(driver, 10, 0.5).until(
    # 条件:直到元素加载完成
    EC.presence_of_element_located((By.ID, "kw"))
)

WebDriverWait源码解读

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.

wait模块的WebDriverWait类是显性等待类,先看下它有哪些参数与方法:

selenium.webdriver.support.wait.WebDriverWait(类)
init
driver: 传入WebDriver实例,即我们上例中的driver
timeout: 超时时间,等待的最长时间(同时要考虑隐性等待时间)
poll_frequency: 调用until或until_not中的方法的间隔时间,默认是0.5秒
ignored_exceptions: 忽略的异常,如果在调用until或until_not的过程中抛出这个元组中的异常, 则不中断代码,继续等待,如果抛出的是这个元组外的异常,则中断代码,抛出异常。默认只有NoSuchElementException
**until(self, method, message=’’) **
作用:每隔一段时间(上面的poll_frequency)调用method,直到返回值不为False或不为空
method:需要执行的method
message:抛出异常时的文案,会返回 TimeoutException ,表示超时
注 意 : 这 个 才 是 常 用 的 , 如 : 定 位 元 素 直 到 不 返 回 空 \color{red}{注意:这个才是常用的,如:定位元素直到不返回空}
method: 在等待期间,每隔一段时间(__init__中的poll_frequency)调用这个传入的方法,直到返回值不是False
message: 如果超时,抛出TimeoutException,将message传入异常
举 个 栗 子 \color{red}{举个栗子}

import time

from selenium import webdriver
from selenium.webdriver.support.wait import WebDriverWait


class Test_Demo():
    def setup(self):
        self.driver=webdriver.Chrome()
        self.driver.maximize_window()
        self.driver.implicitly_wait(10)# 隐性等待和显性等待可以同时用,但要注意:等待的最长时间取两者之中的大者
    def teardown(self):
        self.driver.quit()


    def test_1(self):
    # 此处的形参x一定要有,用来接参的
        def wait(x):
            return len(self.driver.find_elements_by_class_name('ember-view'))>1
        self.driver.get("https://ceshiren.com/")
        WebDriverWait(self.driver,11).until(wait)

上面代码中wait(x)函数的形参一定要有,查看util的源码发现要有一个driver需要传参。
在这里插入图片描述

until_not
与until相反,until是当某元素出现或什么条件成立则继续执行,
until_not是当某元素消失或什么条件不成立则继续执行,参数也相同,不再赘述。

看了以上内容基本上很清楚了,调用方法如下(通俗易懂的 WebDriverWait):
WebDriverWait(driver实例, 超时时长, 调用频率, 忽略的异常).until(要调用的方法, 超时时返回的信息)

这里需要特别注意的是until或until_not中的可执行方法method参数,很多人传入了WebElement对象,如下:
WebDriverWait(driver, 10).until(driver.find_element_by_id(‘kw’)) # 错误
这是错误的用法,这里的参数一定要是可以调用的,即这个对象一定有 call() 方法,否则会抛出异常:TypeError: ‘xxx’ object is not callable


上面什么意思?就是让对象可以直接被调用
官方提供的两个小例子

element = WebDriverWait(driver, 10).until(lambda x: x.find_element_by_id("someId")) 
is_disappeared = WebDriverWait(driver, 30, 1, (ElementNotVisibleException)).until_not(lambda x: x.find_element_by_id("someId").is_displayed())

可以看到,通过匿名函数也是可以的,可以说比后面介绍的 expected_conditions 模块要方便多了

那么有哪些是包含 call() 的对象呢?

模块(接下来重点讲的)
expected_conditions
WebElement的 is_enabled() 、 is_selected() 、is_displayed()

expected_conditions模块
expected_conditions是selenium的一个模块,其中包含一系列可用于判断的条件:
在这里插入图片描述

 selenium.webdriver.support.expected_conditions(模块)

expected_conditions模块提供了多种定义好的前置条件,需要配合WebDriverWait使用。

等待条件(前置条件)简单说明
以下条件判断元素是否可点击,传入locator
element_to_be_clickable(locator)
参数:locator,指一组(By,locator)例如:WebDriverWait(driver,10).until(expected_conditions.element_to_be_clickable((By.NAME,‘11’)))下面的都是以这种方式,只是前置条件不同,传的参数也可能不同WebDriverWait(driver,10).until()
等待查找的元素可见并且可用, 判断元素是否可见并且能被单击,条件满足返回页面元素对象,否则返回Flase
以下四个条件判断元素是否被选中,第一个条件传入WebElement对象,第二个传入locator元组,第三个传入WebElement对象以及状态,相等返回True,否则返回False,第四个传入locator以及状态,相等返回True,否则返回False
element_to_be_selected(object)等待直到元素被选中,传入参数是一个webdriver实例对象
result=WebDriverWait(driver,10).until(expected_conditions.element_to_be_selected(driver.find_element_by_id('kw')))
element_located_to_be_selected(locator)期望某个元素处于被选中状态
参数传入的是一个定位器locator是一个元组类型
result=WebDriverWait(driver,10).until(expected_conditions.element_located_to_be_selected((By.ID,'kw')))
element_selection_state_to_be(driverObject,state)判断给定的元素是否被选中
第一个传入参数是一个webdriver对象,第二个参数是期望的元素的状态,True表示选中状态,Flase表示未选中
result=WebDriverWait(driver,10).until(expected_conditions.element_selection_state_to_be((driver.find_element_by_id('kw')),True))
element_located_selection_state_to_be(locator,state)判断一个元素的状态是否是给定的选择状态
第一个传入参数是一个定位器,定位器是一个元组(by,path);第二个传入参数表示期望的元素状态,True表示选中状态,Flase表示未选中
result=WebDriverWait(driver,10).until(expected_conditions.element_located_selection_state_to_be((By.ID,'kw'),True))
以下两个条件验证元素是否出现,传入的参数都是元组类型的locator,如(By.ID, ‘kw’) 顾名思义,一个只要一个符合条件的元素加载出来就通过;另一个必须所有符合条件的元素都加载出来才行
presence_of_all_elements_located(locator)等待至少有一个定位器查找的元素出现在网页中,返回一组元素;判断页面至少有一个如果元素出现,如果满足条件,返回所有满足定位表达式的页面元素
如果用这个条件类,必须等所有匹配到的元素都加载出来才通过
result12=WebDriverWait(driver,10,0.2).until(EC.presence_of_all_elements_located((By.ID,'kw')))
presence_of_element_located(locator)
传入的参数是元组类型的locator,如(By.ID, ‘kw’)
等待定位器查找的元素出现在网页中,或者可以在DOM中找到,返回一个被定位到的元素 ;判断某个元素是否存在DOM中,不一定可见,存在返回该元素对象
result12=WebDriverWait(driver,10,0.2).until(EC.presence_of_element_located((By.ID,'kw')))
该条件验证元素是否出现,传入的参数都是元组类型的locator,如(By.ID, ‘kw’)
以下两个条件判断某段文本是否出现在某元素中,一个判断元素的text,一个判断元素的value
text_to_be_present_in_element_value(locator, text_)
参数:text,指定的文本
判断text是否出现在元素的value属性值中
result16=WebDriverWait(driver,10,0.2).until(EC.text_to_be_present_in_element_value((By.ID,'kw'),'随便'))
text_to_be_present_in_element(locator,text)
参数:text,指定的文本
等待元素能被定位,并且带有指定的文本信息;
判断文本内容test是否出现在某个元素中,判断的是元素的text
result15=WebDriverWait(driver,10,0.2).until(EC.text_to_be_present_in_element(By.TAG_NAME,"p"))
以下两个条件类验证title,验证传入的参数title是否等于或包含于driver.title
title_contains(title)
参数:title,指要校验标题包含的字符串
等待网页标题包含指定的字符串,成功时返回True,否则返回false;判断页面title标签的内容包含partial_title,只需要部分匹配即可
result17=WebDriverWait(driver,10,0.2).until(EC.title_contains("你就知道"))
title_is(title)
参数:title,指要校验的标题
等待网页标题与预期一致,成功时返回True,否则返回false;判断页面title内容是与传入的title_text内容完全匹配
result18=WebDriverWait(driver,10,0.2).until(EC.title_is("百度一下,你就知道"))
以下三个条件验证元素是否可见,前两个传入参数是元组类型的locator,第三个传入WebElement, 第一个和第三个其实质是一样的
visibility_of_element_located(locator)等待元素出现在DOM中,是可见的,并且宽和高都大于0,变为可见的,将返回一个元素;希望某个元素出现在DOM中并且可见,满足条件返回该元素的页面元素对象(同一个)
result9=WebDriverWait(driver,10,0.2).until(EC.visibility_of_element_located(driver.find_element_by_id('kw')))
invisibility_of_element_located(locator)等待一个元素在DOM中不可见 或不存在;希望某个元素不可见或者不存在DOM中;满足条件返回True,否则返回定位到的元素对象
result8=WebDriverWait(driver,10,0.2).until(EC.invisibility_of_element_located(By.ID,'kw'))
visibility_of(element)
参数:element,指一个元素
希望某个元素出现在页面的DOM中,并且可见,满足条件返回该元素的页面元素对象
result10=WebDriverWait(driver,10,0.2).until(EC.visibility_of(driver.find_element_by_id('kw'))
以下条件判断是否有alert出现
alert_is_present()判断是否存在警告窗口
以下条件判断frame是否可切入,可传入locator元组或者直接传入定位方式:id、name、index或WebElement
frame_to_be_available_and_switch_to_it(parm)判断frame是否可用
如果可用返回True并切入到该frame,参数parm可以是定位器locator(by,path)组成的元组,或者定位方式:id、name、index(frame在页面上索引号),或者webelement对象。
result1=WebDriverWait(driver,10,0.2).until(EC.frame_to_be_available_and_switch_to_it(By.ID,'kw')) #传入ID值‘kk’
result2=WebDriverWait(driver,10,0.2).until(EC.frame_to_be_available_and_switch_to_it(driver.find_element_by_id('kw'))) #传入frame的webelement对象
result3=WebDriverWait(driver,10,0.2).until(EC.frame_to_be_available_and_switch_to_it(1)) #传入frame在页面中索引号
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值