selenium的三种等待方式

一、背景

UI自动化过程中,必然会遇到环境不稳定,网络慢情况,加载问题,如果不做任何处理就会因为没有找到元素而报错。另外一种情况就是页面使用了ajax异步加载机制(现在都是resetful,客户端和服务端都是分离的),不知道页面是什么时候到达的。这时我们就要用到wait,而在selenium 中,我们一共有三种等待。

固定等待、隐式等待和显式等待。

 

1、time.sleep(固定等待)  

本质:让当前的线程睡眠,实质是线程的阻塞(blocking),用wait 方式实现。

缺点:网络条件好浪费时间,严重影响项目的性能

好处:调试脚本可以用

 

2、implicitly_wait(隐式等待)

本质:在脚本的开始设置一个最长等待时间,如果在规定时间内网页加载完成,则执行下一步;否则可能抛出异常。隐式等待对整个driver周期都起作用,在最开始设置一次就可以了,不要当作固定等待使用。

缺点:javascript一般都是放在我们的body的最后进行加载,实际这时页面的元素都已经加载完毕,我们却还在等待全部页面加载结束。

 

3、WebDriverWait(显式等待)

本质:动态的等待,判断某一个元素是不是已经出现了,比如title是不是叫百度或百度搜索,根据动态的一些条件来轮询,它会不停的轮询去给我们检测,条件是成功还是失败,比如0.5s就检测一次这个元素在这个条件下是成功还是失败。同时设置轮询的超时时间。

 

如果同时设置了显式等待,和隐式等待,就看谁设置的等待时间长,谁的超时等待时间长,就用谁的执行。

二、WebDriverWait(显式等待)

1、模块

from selenium.webdriver.support.wait import WebDriverWait

2、WebDriverWait 的源码

# Licensed to the Software Freedom Conservancy (SFC) under one
# or more contributor license agreements.  See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership.  The SFC licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License.  You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied.  See the License for the
# specific language governing permissions and limitations
# under the License.

import time
from selenium.common.exceptions import NoSuchElementException
from selenium.common.exceptions import TimeoutException

POLL_FREQUENCY = 0.5  # How long to sleep inbetween calls to the method
IGNORED_EXCEPTIONS = (NoSuchElementException,)  # exceptions ignored during calls to the method


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.

           Example:
            from selenium.webdriver.support.ui import WebDriverWait \n
            element = WebDriverWait(driver, 10).until(lambda x: x.find_element_by_id("someId")) \n
            is_disappeared = WebDriverWait(driver, 30, 1, (ElementNotVisibleException)).\ \n
                        until_not(lambda x: x.find_element_by_id("someId").is_displayed())
        """
        self._driver = driver
        self._timeout = timeout
        self._poll = poll_frequency
        # avoid the divide by zero
        if self._poll == 0:
            self._poll = POLL_FREQUENCY
        exceptions = list(IGNORED_EXCEPTIONS)
        if ignored_exceptions is not None:
            try:
                exceptions.extend(iter(ignored_exceptions))
            except TypeError:  # ignored_exceptions is not iterable
                exceptions.append(ignored_exceptions)
        self._ignored_exceptions = tuple(exceptions)

    def __repr__(self):
        return '<{0.__module__}.{0.__name__} (session="{1}")>'.format(
            type(self), self._driver.session_id)

    def until(self, method, message=''):
        """Calls the method provided with the driver as an argument until the \
        return value is not False."""
        screen = None
        stacktrace = None

        end_time = time.time() + self._timeout
        while True:
            try:
                value = method(self._driver)
                if value:
                    return value
            except self._ignored_exceptions as exc:
                screen = getattr(exc, 'screen', None)
                stacktrace = getattr(exc, 'stacktrace', None)
            time.sleep(self._poll)
            if time.time() > end_time:
                break
        raise TimeoutException(message, screen, stacktrace)

    def until_not(self, method, message=''):
        """Calls the method provided with the driver as an argument until the \
        return value is False."""
        end_time = time.time() + self._timeout
        while True:
            try:
                value = method(self._driver)
                if not value:
                    return value
            except self._ignored_exceptions:
                return True
            time.sleep(self._poll)
            if time.time() > end_time:
                break
        raise TimeoutException(message)

参数

webDriverWait参数 含义
driver 传入WebDriver实例
timeout 超时时间,等待的最长时间
poll_frequency 调用util或util_not中的方法的间隔时间,默认是0.5s
ignored_exceptions 忽略的异常
方法:util、util_not的参数 说明
method 在等待期内,每隔一段时间调用这个传入的方法,直到返回值不是False
message 如果超时抛出TimeoutException,将message传入异常

 

 

 

 

 

 

 

 

 

 

三、三种等待方式的实例

from selenium import webdriver
from time import sleep
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

# 三种等待方法
class TestCase(object):
    def __init__(self):
        self.driver = webdriver.Chrome()
        self.driver.get('https://www.baidu.com')
        sleep(2)

    def test_sleep(self):
        self.driver.find_element_by_id('kw').send_keys("selenium")
        sleep(2) # 线程的阻塞 blocking wait 方式实现
        self.driver.find_element_by_id('su').click()
        sleep(3)
        self.driver.quit()

    def time_implicitly(self):
        self.driver.implicitly_wait(10)
        self.driver.find_element_by_id('kw').send_keys("webdriver")
        self.driver.find_element_by_id('su').click()
        # sleep(2)
        self.driver.quit()

    def time_wait(self):
        wait = WebDriverWait(self.driver,2,0.5)
        wait.until(EC.title_is('百度一下,你就知道'))
        self.driver.find_element_by_id('kw').send_keys("webdriver")
        self.driver.find_element_by_id('su').click()
        sleep(2)
        self.driver.quit()


if __name__=="__main__":
    case = TestCase()
    # case.test_sleep()
    # case.time_implicitly()
    case.time_wait()

 

题外话:

1、什么是restful:

https://blog.csdn.net/weixin_41229588/article/details/108219391

restful资源表现层状态转化

1)资源:比如一段文字,一张图片,一种服务,一首歌曲等

2)表现层:资源的表现形式。如文本可以用txt格式,html格式,json格式来表现。

3)状态转换:http是无状态协议,所有的状态都保存在服务器端,因此如果客户端想要操作服务层,必须通过某种手段,让服务器发生“状态转换”,而这种转化是建立在表现层之上的,所以就是“表现层状态转化”。

4)客户端用到的手段就是http协议。具体来说就是hppt协议的四种表现方式,如get,post,put,delete。Get 获取资源,post 用来新建资源(更新资源),put用来更新资源,delete 用来删除资源。

总结一下什么是restful架构:

每一个uri代表一种资源;客户端和服务器之间传递这种资源的某种表现层;客户端通过http的四种方法,对服务器资源进行操作,实现表现层状态转换。

 

2、什么是ajax:

https://blog.csdn.net/qq_40459545/article/details/111935158

谈到ajax,首先说ajax不是javaScript的规范,Asynchronous JavaScript and XML的缩写,意思就是用JavaScript执行异步网络请求,Ajax 是一种用于创建快速动态网页的技术,在无需重新加载整个网页的情况下,能够更新部分网页。

如果仔细观察一个Form的提交,你就会发现,一旦用户点击“Submit”按钮,表单开始提交,浏览器就会刷新页面,然后在新页面里告诉你操作是成功了还是失败了。如果不幸由于网络太慢或者其他原因,就会得到一个404页面。

这就是Web的运作原理:一次HTTP请求对应一个页面。

如果要让用户留在当前页面中,同时发出新的HTTP请求,就必须用JavaScript发送这个新请求,接收到数据后,再用JavaScript更新页面,这样一来,用户就感觉自己仍然停留在当前页面,但是数据却可以不断地更新。

最早大规模使用AJAX的就是Gmail,Gmail的页面在首次加载后,剩下的所有数据都依赖于AJAX来更新。

posted @ 2021-02-11 17:03  hqq的进阶日记  阅读(638)  评论(0编辑  收藏  举报