一、背景
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 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()) """ 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来更新。