美文网首页
显式等待与隐式等待——元素等待

显式等待与隐式等待——元素等待

作者: 天花板上老蜥蜴 | 来源:发表于2020-06-02 16:16 被阅读0次

    首先,了解元素等待需要先知道浏览器的工作方式。浏览器在解析HTML文件时,需要从第一行按顺序往下解析。不仅仅解析HTML文件如此,解析JS文件也是这样,但是浏览器解析JS文件就比解析HTML文件要复杂地多的多。对于许多页面来说,页面需要加载数据来驱动视图,数据没加载完成,页面就不会显示对应的节点,又或者监听用户的行为,根据用户的行为添加、显示和删除页面相应的节点。页面加载数据的方式有很多种:加载本地文件、自定义AJAX、使用JQuery、或者是客户端请求数据库返回数据。在上述任何一种情况下当想要操纵的节点没有加载完成时,python脚本又已经开始执行,那么结果只能是报错。顺着这个问题往下想,还有许许多多地情况都会阻碍自动化脚本的执行。为了解决这样类似的问题,有人提出了元素等待的概念,简单的来说就是让脚本等待页面元素的出现

    元素等待的三种方式

    • 强制等待
    • 显式等待
    • 隐式等待

    强制等待sleep()

    强制等待是指让脚本等待一定的固定时间再执行,需要说明的是,强制等待sleep()方法由Python的time模块提供

    from time import sleep
    sleep(10)
    print('等待10秒之后执行')
    

    当脚本执行到第三行时,会等待10秒的事件,然后再往下执行,参数就是要等待的时间。
    比如下面的例子,在很多地方都需要使用到强制等待sleep()方法

    from time import sleep
    browser = webdriver.Chrome()
    browser.get('https://weibo.com/')
    sleep(10)
    

    微博的首页繁冗且杂长,需要等待一定的时间再去获取相应的元素,否则直接去查找还未加载出来或者需要特定操作才可以出现的元素,会抛出NoSuchElementException的异常。

    image-20200515151649311.png

    显式等待

    显式等待和隐式等待都是由WebDriver提供的,显式等待是在一段固定时间内,每隔一定的时间检测一次相应的元素是否存在,如果在这段固定时间内想要检测的元素依然不存在的话,会抛出TimeoutException的异常。

    image-20200515152510190.png

    显式等待WebDriverWait的使用

    WebDriverWait类是由WebDriver提供的方法,具体格式如下:

    WebDriverWait(driver,timeout,interval,err)
    
    • driver:浏览器的实例
    • timeout:设置等待的总时间
    • interval:设置间隔的时间
    • err:超时后的异常信息,上面已经提到了,默认抛出TimeoutException的异常。
      WebDriverWait()一般由until()或者until_not配合使用,具体格式如下:
    from selenium import webdriver
    #从selenium导入webdriver包
    from selenium.webdriver.common.by import By
    #从selenium.webdriver.common.by 导入By包进行元素定位
    from selenium.webdriver.support.wait import WebDriverWait
    #从selenium.webdriver.common.wait 导入WebDriverWait包进行显式等待
    from selenium.webdriver.support import expected_conditions as Ec
    #从selenium.webdriver.common.wait 导入expected_conditions类
    #并通过关键字as将expected_conditions重命名为Ec
    WebDriverWait(driver,timeout,interval,err).until(
        method,message=""
    )
    #或者
    WebDriverWait(driver,timeout,interval,err).until_not(
        method,message=""
    )
    #message=""可以忽略,但是忽略时method外是两层括号,下面会继续提到message
    #from selenium.webdriver.support.wait import WebDriverWait有的文档并不是这个写的
    #而是from selenium.webdriver.support.ui import WebDriverWait,其实ui和wait并没有什么差别,随心写就好
    

    上述代码中,untiluntil_not都是以method作为参数,直到until的返回值为true或者直到until_not的返回值为falsemethod方法是由expected_conditions类提供的内置方法,具体方法如下:

    内置方法示例前提条件:

    from selenium import webdriver
    from selenium.webdriver.common.by import By
    from selenium.webdriver.support.wait import WebDriverWait
    from selenium.webdriver.support import expected_conditions as Ec
    browser = webdriver.Chrome()
    browser.get('https://weibo.com/')
    sleep(10)
    
    • title_is 判断当前页面的标题是否等于预期
    element = WebDriverWait(browser,10,1).until(
        Ec.title_is(('微博随时随地发现新鲜事')),message='没有找到字符串'
    )
    

    值得注意的是,如果超时(until的返回值为false),脚本会抛出TimeoutException,同时将message传入异常,下面的很多种方法都是如此,下图就是将message传入异常并抛出的例子

    image-20200515213035913.png
    • title_contains判断当前页面的标题是否包含预期字符串
    element = WebDriverWait(browser,10,1).until(
        Ec.title_contains(('京东'))
    )
    
    • presence_of_element_located 判断元素是否被加在DOM树里,不代表该元素一定可见
    element = WebDriverWait(browser,10,1).until(
        Ec.presence_of_element_located((By.ID,'loginname'))
    )
    
    • visibility_of_element_located 判断元素是否可见(可见代表没有隐藏,并且宽高都不为0)
    element = WebDriverWait(browser,10,1).until(
        Ec.visibility_of_element_located((By.ID,'loginname'))
    )
    #可见返回true,不可见抛出TimeoutException异常
    
    • invisibility_of_element_located 判断某个元素是否不存在与DOM树中或者不可见
    element = WebDriverWait(browser,10,1).until(
        Ec.invisibility_of_element_located((By.ID,'loginname'))
    )
    #和上一个方法相反不可见返回true,可见抛出TimeoutException异常
    
    • visibility_of 与上一个方法相同,但是上一个方法的参数为定位,该方法的参数为定位后的元素
    loginModel = browser.find_element_by_id('loginname')
    element = WebDriverWait(browser,10,1).until(
        Ec.visibility_of((loginModel))
    )
    #值得注意的是,visibility_of的参数必须为一个经过定位之后找到的元素,而不是元素的定位
    
    • presence_of_all_elements_located 判断DOM树中是否存在这个元素,可以存在一个或多个,只要存在一个就返回true
    element = WebDriverWait(browser,10,1).until(
        Ec.presence_of_all_elements_located((By.ID,'loginname'))
    )
    
    • text_to_be_present_in_element 判断某个元素中的text是否包含了预期的字符串
    element = WebDriverWait(browser,10,1).until(
        Ec.text_to_be_present_in_element((By.CLASS_NAME,'enter_psw'),'密码')
    )
    #这个方法的使用格式和其他的方法有点不一样
    
    • text_to_be_present_in_element_value 判断某个元素中的value是否包含了预期的字符串
    element = WebDriverWait(browser,10,1).until(
        Ec.text_to_be_present_in_element_value((By.CLASS_NAME,'enter_psw'),'密码')
    )
    
    • element_to_be_clickableo 判断某个元素是否可见并且是可以点击的
    element = WebDriverWait(browser,10,1).until(
        Ec.element_to_be_clickable((By.ID,'login_form_savestate'))
    )
    
    • staleness_of 等待一个元素从DOM树中移除
    node = browser.find_element_by_id('loginname')
    element = WebDriverWait(browser,50,1).until(
        Ec.staleness_of((node))
    )
    
    • element_to_be_selected 判断某个元素是否被选中,一般用于下拉列表
    #因为微博首页没有下拉列表,所以此测试在12306的注册页面上
    browser.get('https://kyfw.12306.cn/otn/regist/init')
    sleep(10)
    node = browser.find_element_by_css_selector("[value='0']")
    element = WebDriverWait(browser,20,1).until(
        Ec.element_to_be_selected((node))
    )
    
    • element_selection_state_to_be 判断某个元素的选中状态是否符合预期
    #因为微博首页没有下拉列表,所以此测试在12306的注册页面上
    browser.get('https://kyfw.12306.cn/otn/regist/init')
    sleep(10)
    node = browser.find_element_by_id("idTypeCode_wgjzz")
    element = WebDriverWait(browser,20,1).until(
        Ec.element_selection_state_to_be(node,True)
    )
    # True表示预期选中,false表示预期不选中
    
    • element_located_selection_state_to_be 和上面一样判断元素的选中状态是否和预期一样,只不过仔细看就会发现,此方法的参数为定位,而上面的方法的参数是定位后的元素
    #因为微博首页没有下拉列表,所以此测试在12306的注册页面上
    browser.get('https://kyfw.12306.cn/otn/regist/init')
    sleep(10)
    element = WebDriverWait(browser,20,1).until(
        Ec.element_located_selection_state_to_be((By.ID,"idTypeCode_wgjzz"),True)
    )
    
    • alert_is_present() 判断页面上是否存在alert
    element = WebDriverWait(browser,10,1).until(
        Ec.alert_is_present()
    )
    

    至此,expected_conditions类提供的所有的方法的实例都已经举例完毕了

    隐式等待

    如果 WebDriver 没有在 DOM 中找到元素,将继续等待,超出设定时间后则抛出找不到元素的异常,
    换句话说,当查找元素或元素并没有立即出现的时候,隐式等待将等待一段时间再查找 DOM,默认的时间是 0

    implictly_wait()方法具体格式

    browser.implicitly_wait(10)
    #参数为秒数,默认为0
    

    实例:

    from selenium import webdriver
    browser = webdriver.Chrome()
    browser.implicitly_wait(10)
    browser.get('https://baidu.com/')
    browser.find_element_by_id("kw").send_keys('selenium')
    

    上述代码表示在脚本查找元素时,即使当前没有找到相应的元素也不会立即报错,而是等待10秒的时间继续查找相应的元素,如果依然未找到,则超时TimeoutException报错

    总结:显式等待和隐式等待的区别

    • 显式等待更节省时间
    • 显式等待有等待条件,而隐式等待没有
    • 隐式等待是一个全局等待,前面设置了隐式等待时间,那么后面的元素找不到的话也都会进行隐式等待
    • 显式等待可以针对特定的元素等待,而隐式等待不是,当隐式等待执行测试时,如果没有找到元素将继续等待,超出时间会抛出异常

    相关文章

      网友评论

          本文标题:显式等待与隐式等待——元素等待

          本文链接:https://www.haomeiwen.com/subject/zhbuzhtx.html