这一篇我们将继续深入探讨Selenium的相关使用方法与技巧。
延时方式
我们加载页面时通常会因为网络环境等各方面的客观因素而导致元素加载的速度各不相同,如果此时我们没有对业务操作进行一定的延时执行,那么大概率业务操作会出现各类的no such element报错。
那么我们就需要在页面元素加载完成之后再对相应的元素进行业务操作来规避上面说的这个问题。Selenium内可以使用三种延时的函数来进行对应的延时业务操作。
隐式等待
隐式等待的作用是在页面加载是隐性的进行特定时长的等待,如果在规定的等待时长内页面加载完毕,则会继续进入下一个业务操作,如果没有加载完毕,则会抛出一个超时的异常。
这里其实有两个问题:
-
第一,隐式等待是全局性质的,也就是说一旦你设置了个5秒,那整个程序都会使用这个等待时间类进行配置,灵活性较低;
-
第二,如果碰到了有些页面中的元素是局部加载的话,那整个页面的加载是否完成也就没有了其意义,隐式加载无法针对这样的情况作出调整,智能度较低。
所以一般来说只要是对于页面的整体加载要求不高或者元素的加载比较稳定的程序,都可以使用隐式等待来进行延时操作。
from selenium import webdriver
from selenium.webdriver.common.by import By
browser = webdriver.Chrome()
browser.get('https://www.baidu.com')
browser.implicitly_wait(5)
browser.find_element(By.XPATH, '//*[@id="kw"]').send_keys('selenium')
显式等待
显式等待的作用则是使用特定的等待时长来进行某些业务逻辑判断,如果判断(比如元素是或否加被定位)在时间完成那继续执行下一个业务操作,如果判断失败也会抛出no such element的异常,而显式等待的默认检查元素周期为0.5秒。
乍一看好像与隐式等待差不多,其实不然,首先显式等待是针对页面中某个或某组特定元素而执行的,隐式则是全局,对所有的元素都生效。
其二,显式等待可以通过自定义条件来进行元素的定位和选取,隐式则不行。
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://www.baidu.com')
ele = WebDriverWait(browser, 10, 0.5).until(EC.presence_of_element_located((By.XPATH, '//*[@id="kw"]')))
ele.send_keys('selenium')
强制等待
这个应该是平时大家代码中用的最多的等待方式了吧,sleep是针对线程进行挂起的一种等待方式,等待时长根据指定的参数来进行决定。最大的好处就是简单粗暴,无任何逻辑在里面,所以也被称为强制等待。
from selenium import webdriver
from selenium.webdriver.common.by import By
from time import sleep
browser = webdriver.Chrome()
browser.get('https://www.baidu.com')
sleep(2)
browser.find_element(By.XPATH, '//*[@id="kw"]').send_keys('selenium')
那么以上的三种等待方式其实各有各的特点与缺点,三者之间没有绝对的好用和不好用,而在我们的日常工作场景中也希望大家可以根据实际的情况有选择性的使用。
超时等待
元素加载超时我们可以使用以上三种延时方式来进行处理,那么页面超时了又该如何操作呢?
Selenium也为我们准备了两个函数来对应这样的局面。
页面加载超时
browser.set_page_load_timeout(30)
这里推荐将超时的时间有效的拉长,不宜过短。过短的超时时间容易导致整体页面出现未加载html代码情况下直接令驱动无法工作的情况。
页面异步js或ajax操作超时
browser.set_script_timeout(30)
这个函数是用于execute_async_script()相关的异步js操作超时报错,由于是异步操作,等待时间同理也不易过短。
键鼠操作
浏览器中键盘与鼠标的操作也是不可或缺的重要一环,在被测对象的业务要求中往往占有不少的戏份。
文字输入:
browser.find_element(By.ID, 'kw').send_keys('selenium')
点击:
browser.find_element(By.ID, 'kw').click()
点击并按住不放(左键长按),这些模拟鼠标操作需要导入ActionChains包:
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.action_chains import ActionChains
browser = webdriver.Chrome()
browser.get('https://www.baidu.com')
act = ActionChains(browser)
ele = browser.find_element(By.ID, 'kw')
act.click_and_hold(ele).perform()
右键点击:
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.action_chains import ActionChains
browser = webdriver.Chrome()
browser.get('https://www.baidu.com')
act = ActionChains(browser)
ele = browser.find_element(By.ID, 'kw')
act.context_click(ele).perform()
双击:
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.action_chains import ActionChains
browser = webdriver.Chrome()
browser.get('https://www.baidu.com')
act = ActionChains(browser)
ele = browser.find_element(By.ID, 'kw')
act.double_click(ele).perform()
拖拽元素至另一个元素处,ele_a 为source,ele_b 为target:
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.action_chains import ActionChains
browser = webdriver.Chrome()
browser.get('https://www.baidu.com')
act = ActionChains(browser)
ele_a = browser.find_element(By.ID, 'btn_a')
ele_b = browser.find_element(By.ID, 'btn_b')
act.drag_and_drop(ele_a, ele_b).perform()
拖拽元素至指定位置后松开,元素后为x,y坐标值p:
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.action_chains import ActionChains
browser = webdriver.Chrome()
browser.get('https://www.baidu.com')
act = ActionChains(browser)
ele = browser.find_element(By.ID, 'btn_a')
act.drag_and_drop_by_offset(ele, 200, 100).perform()
鼠标移动至指定元素:
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.action_chains import ActionChains
browser = webdriver.Chrome()
browser.get('https://www.baidu.com')
act = ActionChains(browser)
ele = browser.find_element(By.ID, 'btn_a')
act.move_to_element(ele).perform()
按下指定的键位(示例代码中是回车键):
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.by import By
from selenium.webdriver.common.action_chains import ActionChains
browser = webdriver.Chrome()
browser.get('https://www.baidu.com')
act = ActionChains(browser)
ele = browser.find_element(By.ID, 'kw').send_keys('selenium')
act.key_down(Keys.ENTER).perform()
松开指定的键位,这里也可以用链式写法:
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.by import By
from selenium.webdriver.common.action_chains import ActionChains
browser = webdriver.Chrome()
browser.get('https://www.baidu.com')
act = ActionChains(browser)
ele = browser.find_element(By.ID, 'kw').send_keys('selenium')
act.key_down(Keys.ENTER)
act.key_up(Keys.ENTER)
# 链式写法
act.key_down(Keys.ENTER).act.key_up(Keys.ENTER).perform()
移动鼠标到指定坐标位置:
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.action_chains import ActionChains
browser = webdriver.Chrome()
browser.get('https://www.baidu.com')
act = ActionChains(browser)
ele = browser.find_element(By.ID, 'kw').send_keys('selenium')
act.move_by_offset(100, 200).perform()
移动到距离指定元素多少距离的位置(从左上角0, 0开始计算):
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.action_chains import ActionChains
browser = webdriver.Chrome()
browser.get('https://www.baidu.com')
act = ActionChains(browser)
ele = browser.find_element(By.ID, 'kw').send_keys('selenium')
act.move_to_element_with_offset(ele, 100, 200).perform()
在指定元素位置松开鼠标:
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.action_chains import ActionChains
browser = webdriver.Chrome()
browser.get('https://www.baidu.com')
act = ActionChains(browser)
ele = browser.find_element(By.ID, 'kw').send_keys('selenium')
act.click_and_hold(ele).release(ele).perform()
发送指定的键或者内容至指定元素:
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.action_chains import ActionChains
browser = webdriver.Chrome()
browser.get('https://www.baidu.com')
act = ActionChains(browser)
ele = browser.find_element(By.ID, 'kw').send_keys('selenium')
act.send_keys_to_element(ele, 'selenium').perform()
暂停所有操作,默认单位为秒:
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.action_chains import ActionChains
browser = webdriver.Chrome()
browser.get('https://www.baidu.com')
act = ActionChains(browser)
ele = browser.find_element(By.ID, 'kw').send_keys('selenium')
act.context_click(ele).pause(5).double_click(ele).perform()
组件操作
页面中也存在着很多不同种类的组件,比如单选框、多选框、下拉列表、选项卡等。这些操作也可以通过Selenium提供的函数进行实现。
清除指定元素中的内容(输入框等):
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.action_chains import ActionChains
from time import sleep
browser = webdriver.Chrome()
browser.get('https://www.baidu.com')
act = ActionChains(browser)
ele = browser.find_element(By.ID, 'kw')
ele.send_keys('selenium')
sleep(2)
ele.clear()
提交确认(类似于Keys.ENTER的效果):
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.action_chains import ActionChains
from time import sleep
browser = webdriver.Chrome()
browser.get('https://www.baidu.com')
act = ActionChains(browser)
ele = browser.find_element(By.ID, 'kw')
ele.send_keys('selenium')
sleep(2)
ele.submit()
下拉列表,我们就可以使用Select方法来实现选取操作。使用Select方法需要从selenium.webdriver.support.select导入该方法,例如下图中某网站的下拉列表对象:
html构造如下:
select_by_index()方法:
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.select import Select
browser = webdriver.Chrome()
browser.get('https://www.xxxx.com')
ele = browser.find_element(By.ID, 'input_factor_gj_count')
# 需要注意下标要从0开始,选择1%那一项
Select(ele).select_by_index('0')
select_by_value()方法:
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.select import Select
browser = webdriver.Chrome()
browser.get('https://www.xxxx.com')
ele = browser.find_element(By.ID, 'input_factor_gj_count')
# 指定元素的value属性值,选择1%那一项
Select(ele).select_by_value('0.01')
select_by_value()方法:
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.select import Select
browser = webdriver.Chrome()
browser.get('https://www.xxxx.com')
ele = browser.find_element(By.ID, 'input_factor_gj_count')
# 指定元素的文本值,选择1%那一项
Select(ele).select_by_visible_text('1%')
框架切换(Frame)
如果在页面中定位某一个元素失败并检查其属性并没有问题时,就该考虑是否在祖先节点中是否存在frame或者iframe标签。
这样的页面就表名存在多层框架嵌套,这时我们就需要进行框架切换的操作,来准确定位到指定元素。
例如某页面存在两层frame嵌套,内部框架的xpath为://*[@id="mainDiv"]/iframe,此时如果定位某个输入框失败之后,我们就应该转而跳入该frame内进行元素定位。
from selenium import webdriver
from selenium.webdriver.common.by import By
browser = webdriver.Chrome()
browser.get('https://www.xxxx.com')
# 定位到指定的frame
path = browser.find_element(By.XPATH, '//*[@id="mainDiv"]/iframe')
# 切换至该frame内
browser.switch_to_frame(path)
ele = browser.find_element(By.CLASS_NAME, 'input')
ele.send_keys('selenium')
标签页切换
我们浏览器在使用中一般会打开多个浏览窗口,也就是多个标签页。此时我们就可以通过每个标签页的句柄来进行定位和互相切换。
-
switch_to_window()
我们利用浏览器窗口的句柄来进行标签页的切换:
from selenium import webdriver
from selenium.webdriver.common.by import By
browser = webdriver.Chrome()
browser.get('https://www.baidu.com')
# 第一个窗口的句柄下标为0,打开第二个就是1
browser.switch_to_window(browser.window_handles[1])
# 此时就会使用第二个标签页去访问淘宝
browser.get('https://www.taobao.com')
-
弹窗处理
页面中时常也存在着各类的弹窗,比如警告、确认、提示等等,那么对于这些弹窗我们也有着相应的业务处理方法。
首先我们需要明确的是每种类型的弹窗中元素也是各不相同,所以我们针对不同的弹窗使用不同的属性来定位和操作。
-
警告弹窗
一般来说就是告知到使用者执行某些操作与页面之后将要注意的事项,这种窗口只需确认。
from time import sleep
from selenium import webdriver
from selenium.webdriver.common.by import By
browser = webdriver.Chrome()
browser.get('https://www.xxxx.com')
browser.find_element(By.ID, 'btn_tg_title').click()
sleep(1)
# 在警告弹窗中点击确认按钮
browser.switch_to_alert().accept()
-
确认弹窗
多用于在用户执行提交操作后的动作确认,有确认和取消两个选项。
from time import sleep
from selenium import webdriver
from selenium.webdriver.common.by import By
browser = webdriver.Chrome()
browser.get('https://www.xxxx.com')
browser.find_element(By.ID, 'btn_submit').click()
sleep(1)
#确认二选一
browser.switch_to_alert().accept()
#取消二选一
browser.switch_to_alert().dismiss()
-
提示弹窗
这个通常用来处理用户信息交互的场景,用户可以通过弹窗输入一些文字信息,来传递与进行后续的业务处理。
from time import sleep
from selenium import webdriver
from selenium.webdriver.common.by import By
browser = webdriver.Chrome()
browser.get('https://www.xxxx.com')
browser.find_element(By.ID, 'btn_info_inquiry').click()
sleep(1)
# 这里传递信息到提示弹窗,警告与确认两类弹窗不可使用,会报错
browser.switch_to_alert().send_keys('20100909')
鉴权操作
既然是web自动化测试,那我们又怎么能少了Cookie的相关操作呢?用户的状态和业务请求都的需要用他来进行鉴权。
在Selenium中对Cookie进行操作其实也很简单,首先我们需要手动的登录被测网站一次,待网站Cookie存入本地后即可使用Selenium自带的函数对齐进行业务操作。
首先我们获取对应网站的Cookie值。
import json
from selenium import webdriver
browser = webdriver.Chrome()
browser.get('https://www.baidu.com')
# 写入保存为文件还是直接打印至控制台,各取所需
with open('cookies.txt', 'w') as f:
f.write(json.dumps(browser.get_cookies()))
cookies = browser.get_cookies()
print(cookies)
接下来我们简单的对获得的Cookie进行处理:
# 删除所有的cookies
browser.delete_all_cookies()
# 循环打印cookie中的name和value
for c in cookies:
# 查看打印出的cookie对应的键值对
print("%s : %s" % (c['name'], c['value']))
# 根据自己的业务需求进行cookie的增删改
cookie = {"name": "xxxx", "value": "xxxx"}
# 最后添加即可
driver.add_cookie(cookie)
js操作
Selenium也为我们提供了可执行js脚本相关的函数,他们的作用是在某些页面中模拟一些业务动作(画面滑动,选择日期等)。
在一些仅靠webdriver无法实现的业务场景中,我们就可以依靠此函数来辅助测试目的的达成。
js的查找元素方法(ID):
document.getElementById("id")
js的查找元素方法(name)
document.getElementsByName('name')
js的查找元素方法(class):
document.getElementsByClassName("class_name")
js的查找元素方法(tag):
document.getElementsByTagName('tag_name')
js的查找元素方法(css):
document.querySelector("css selector")
js的查找元素方法(css_list):
document.querySelectorAll("css selector")
-
execute_script()
从上可以看出其实js的定位元素方法和Selenium中的差不多,接下来我们就可以将需要执行的js语句放入到执行函数中使用。
from selenium import webdriver
browser = webdriver.Chrome()
browser.get('https://www.baidu.com')
# 定位后修改指定元素的value属性
js_script_exec = 'document.getElementById("form_motion").value="list_modify";'
browser.execute_script(js_script_exec)
注意点与小技巧
1、对于某些动态div标签(窗口),一般的方法不太奏效的情况下,可以尝试下switch_to_default_content()方法,跳转到最外层;
2、使用模拟键鼠操作的时候,无论是单独使用还是链式写法,记得在结尾加上perform()方法进行执行;
3、如果元素定位时报错element click intercepted,记得检查界面上是否有其他元素进行覆盖,元素有可能也是具有隐藏属性的;
4、元素过期报错element is not attached to the page document,可以尝试重新刷新页面,这里不推荐直接使用refresh方法,还是养成好习惯先怼上try…except…捕捉到异常后在进行刷新或重置操作;
5、对于属性值为动态的元素,墙裂推荐使用CSS selector或者xpath方法来进行元素定位,正则表达式也推荐大家最好能掌握;
6、如果前期对xpath的相对路径写法比较头疼,推荐使用F12调试工具自带的元素复制功能,在你想要复制的元素所在的标签对这行右键,选择copy —— Copy XPath选项即可;
7、输入框默认存在内容想要删除再输入信息的话,不推荐模拟键盘操作Ctrl+A,然后模拟退格键,试试clear()方法吧;
8、抓不到元素可以使用延时方法,输入文字也是一样的道理,业务场景中需要大量输入文字的,无论是从文件中还是提取又或者是遍历,出现少字漏字的话,同样也可以使用延时的方法,适当的放慢处理的速度;
9、在页面中总会有些不可见的元素,这种情况使用is_displayed()方法即可快速定位找到
10、有些被测页面需要验证码,无论是手机的还是图片验证,和开发同学沟通一下,留个万能的就行了,其本身的功能手工回归一下即可,不必太过纠结;
11、三方登录功能也是如此,不推荐直接使用web自动化去搞,三方的一般是不开源的,有这折腾的时间还不如跑跑接口和黑盒,自动化的话绕过去即可;
12、自动化测试用例这块的话博主还是推荐不要有依赖,和功能测试用例同理,每次的执行顺序或者数量都会根据需求与业务场景发生变化,一旦依赖了会大大增加测试同学的维护成本。
最后:下方这份完整的软件测试视频教程已经整理上传完成,需要的朋友们可以自行领取【保证100%免费】
软件测试面试文档
我们学习必然是为了找到高薪的工作,下面这些面试题是来自阿里、腾讯、字节等一线互联网大厂最新的面试资料,并且有字节大佬给出了权威的解答,刷完这一套面试资料相信大家都能找到满意的工作。