ui自动化

web自动化

元素定位(xpath、css)

为什么要学习xpath和css?

  1.如果标签没有(id\name\class)3个属性,也不是链接标签,只能使⽤tag_name定位,⽐较麻烦。

  2.⽅便在⼯作中查找元素,节点,使⽤xpath和css⽐较⽅便(⽀持任意属性、层级)来找元素

  • 简单定位需求: 如果只是简单的元素定位需求,可以优先选择CSS选择器,因为它简洁、易懂、性能较好。

  • 复杂定位需求: 如果需要进行复杂的元素定位,涉及到元素的层级关系、属性值等复杂条件,可以选择XPath,因为它更加灵活。

   节点 开始标签<div <script等 结束标签</div>等 <input自结束标签不显示结束标签

xpath

  说明:xpath是xml path简称,使⽤标签路径来定位。

  在控制台 $x{'/html/body/div'}回车定位到标签

  $x{'/html/body/div[1]'}#定位长度为1的div

  $x{'/html/body/div[1]/div[@id="head"]'}#精准定位id为head的div div可用通配符*代替查找所有id=head的标签

  $x{'//*[text()="贴吧"]'}#根目录下定位文本内容为贴吧的标签

  $x{'//*[@id="s-top-left"]//*[text()="贴吧"]'}#根目录下精准定位id="s-top-left",文本内容为贴吧的标签

  $x{'//*[@id="s-top-left"]//*[contains(text(),"贴")]'}#文本内容很多时使用contains包含方式定位也可以用在属性值id,name等

  $x{'/html/body/div[1]'/..}#定位长度为1的div的上一级

  $x{'/html/body/div[1]'/../a[下标]}#定位长度为1的div的上一级的第一个元素的标签

  绝对路径:从根⽬录开始,逐级查找标签。单反斜杠

  相对路径:从任意层级开始,查找标签。双反斜杠

css

单个属性定位

  $(".s_ipt")#定位class属性内容为s_ipt的标签不需要加class属性名

  $("#kw")#定位id属性内容为kw的标签不需要加id属性名

  $("*")#选择当前页面所有节点

  $('[name="wd"]')#其他属性定位

多个属性定位

$("#kw .s_ipt")#加空格多层级可以同级找也可跨级找

$("#kw > .s_ipt")#只能在子集中找

$("#kw > s_ipt:nth-child(1)")#定位到子集第一个s_ipt

selenium
环境搭建

所需环境: pthon解释器+pycharm+selenium+浏览器+浏览器驱动

selenium安装:pip install selenium

浏览器驱动

chrome: http://npm.taobao.org/mirrors/chromedriver/ 浏览器驱动⼤版本必须和浏览器版本⼀致。

使⽤: 1、解压下载的驱动,获取到chromedriver.exe 2、将chromedriver.exe复制到python.exe所在⽬录即可(避免再次将chromedrver.exe 添加path变量)

 

import time from selenium import webdriver driver = webdriver.Chrome(r"E:\beiyonglxz_11\chromedriver.exe")#获取浏览器驱动 time.sleep(3)#延时3秒 driver.get("http://www.baidu.com")#浏览器打开百度网站 time.sleep(3)#延时3秒 driver.close()#关闭浏览器

第三方浏览器驱动管理包 pip install webdriver-manager自动更新驱动

 

import time from selenium import webdriver from webdriver_manager.chrome import ChromeDriverManager driver = webdriver.Chrome(ChromeDriverHanager().install()) time.sleep(3) driver.get("http://www.baidu.com") time.sleep(3) driver.close()

浏览器操作
 

import time from selenium import webdriver from webdriver_manager.chrome import ChromeDriverManager driver = webdriver.Chrome(ChromeDriverHanager().install())#获取浏览器驱动 time.sleep(3)#延时3秒 driver.get("http://www.baidu.com")#浏览器打开百度网站 time.sleep(2) driver.get("http://t.zoukankan.com/yfacesclub-p-8482681.html") driver.back() #后退到上一个页面。 time.sleep(2) #再次等待2秒钟。 driver.forward()#前进到下一个页面。 time.sleep(2) #再次等待2秒钟。 driver.refresh() #刷新当前页面。 time.sleep(2) #再次等待2秒钟。 driver.minimize_window() #最小化浏览器窗口。 time.sleep(2) #再次等待2秒钟。 driver.set_window_size(600, 900) #设置浏览器窗口大小为宽600像素,高900像素。 print(driver.get_window_position()) #打印浏览器窗口的位置。 time.sleep(2) #再次等待2秒钟。 print(driver.get_window_size())#打印浏览器窗口的大小。 time.sleep(2) #再次等待2秒钟。 driver.maximize_window() #最大化浏览器窗口。 print(driver.title) #打印当前页面的标题。 print(driver.current_url)#打印当前页面的URL。 img1 = driver.get_screenshot_as_png()#获取当前页面的屏幕截图并保存为PNG格式。 with open("1.png", "wb") as f: f.write(img1) #将屏幕截图保存为文件"1.png"。 driver.get_screenshot_as_file("2.png") #获取当前页面的屏幕截图并保存为文件"2.png"。 print(driver.page_source) #打印当前页面的源代码。 time.sleep(3)#再次等待3秒钟。 driver.close()#退出浏览器并关闭所有相关窗口。 driver.quit()#关闭当前浏览器标签页。

八大定位方式By参数
 

ID = "id"#常用 XPATH = "xpath"#常用 LINK_TEXT = "link text" PARTIAL_LINK_TEXT ="partial link text" NANE = "name"#常用 TAG_NANE = "tag name" CLASS_NANE = "class name" CSS_SELECTOR = "css selector"#常用

webdriver中的常见操作:
方法描述
send_keys()模拟输入指定内容
clear()清除文本内容
is_displayed()判断该元素是否可见
get_attribute()获取标签属性值
size返回元素的尺寸
text返回元素文本
 

driver.find_element(By.id,"kw")#定位返回第一个元素 driver.find_elements()#定位返回一个列表里面有查找的所有元素 driver.find_element(By.id,"kw").send_keys("测试")#定位之后搜索测试方式一 el = driver.find_element(By.id,"kw") el.send_keys("测试")#定位之后搜索测试方式二 el.submit()#模拟键盘回车 el = driver.find_element(By.id,"kw") el.clear()#清空定位里的内容 driver.find_element(By.XPATH,'/1*[@id="su"] ').click()#定位之后模拟鼠标点击 print(el1.get_attribute("value"))#获取value标签属性值 el2 = driver.find_element(By.XPATH,'//*[@id="s-top-left"]/a[4]')#通过xpath查找元素 print(el2.text)#返回元素文本 print(el2.size)#返回元素的尺寸宽高大小 print(el2.is_displayed())#判断该元素是否可见 #使用hidden属性,使用style属性设置display:none,使用style属性设置visibility:false属性不可见元素类型

常见问题元素定位不到检查一下定位表达式有无问题,若没问题可能是多表单

多表单/多框架切换

在网页中,表单嵌套是很常见的情况,尤其是在登录的场景

多表单就是使用iframe/frame,引用了其他页面的链接,真正的页面数据并没有出现在当前源码中,但是在浏览器中我们看到,简单理解可以使页面中开了一个窗口显示另一个页面

处理方法

 

#直接使用id值切换进表单driver.switch_to.frame(value) driver.switch_to_frame(value) #定位到表单元素,再切换进入 el = driver.find_element_by_xxx(value) driver.switch_to.frame(el)ldriver.switch_to_frame(el)

 

driver.get(url='https:// www.126.com/') driver.maximize_window() time.sleep(2) ele = driver.find_elements_by_xpath('//iframe')[0] driver.switch_to.frame(ele) driver.find_element_by_xpath('//input[@name="emai1"]').send_keys('123456') driver.find_element_by_xpath('//input[@name="password"]').send_keys ('123456') time.sleep(5)

多表单切换

 

#跳回最外层的页面 driver.switch_to.default_content() #跳回上层的页面 driver.switch_to.parent_frame()

自动化登录有道——多表单

 

from selenium import webdriver from selenium.webdriver.common.by import By driver = webdriver.Chrome() driver.maximize_window() driver.get("https:/ljianwai.youdao.com/") time.sleep(3) #先找到表单元素 element = driver.find_element(By.XPATH,"//iframe[@id]") #切换进入表单 driver.switch_to.frame(element) #输入邮箱 driver.find_element(By.XPATH,"//input[@name='email']").send_keys("974381044@qq.com") #输入密码 driver.find_element(By.XPATH,"//input[@name='password']").send_keys('zytc012310120') #点击登录 driver.find_element(By.CSS_SELECTOR,'#dologin').click() time.sleep(5) driver.quit()#退出

文件上传

input标签直接使用send_keys()上传文件路径

 

from selenium import webdriver from selenium.webdriver.common.by import By driver = webdriver.Chrome() driver.maximize_window() driver.get("https:/ljianwai.youdao.com/") time.sleep(3) #先找到表单元素 element = driver.find_element(By.XPATH,"//iframe[@id]") #切换进入表单 driver.switch_to.frame(element) #输入邮箱 driver.find_element(By.XPATH,"//input[@name='email']").send_keys("974381044@qq.com") #输入密码 driver.find_element(By.XPATH,"//input[@name='password']").send_keys('zytc012310120') #点击登录 driver.find_element(By.CSS_SELECTOR,'#dologin').click() time.sleep(3) #点击-新建项目 driver.find_element(By.XPATH,"//div[text()='新建项目']").cLick() #点击-图片翻译 driver.find_element(By.XPATH,"/ /div[text()='图片翻译']").click() # input标签直接使用send_keys()上传文件路径 drivers.find_element(By.XPATH,"//input[@class='file' ]").send_keys(r"c:\TT\习知N课件\我的课件\1624958787(1.png") time.sleep(5) driver.quit()#退出

非input标签,需要先安装pywinauto操作Windows系统的控件

 

from selenium import webdriver from selenium.webdriver.common.by import By import time import pywinauto driver =webdriver.chrome("c:/users/TT/.wdm/drivers/chromedriver/win32/72.0.3626.69/chromedriver.exe") driver.get('https://www.jq22.com/yanshi17984') time.sleep(3) #切换表单 ele=driver.find_element(By.CSS_SELECTOR,'#iframe') driver.switch_to.frame(ele) #点击加号上传 driver.find_element(By.XPATH,"//img[@class='addImg']").click() #driver.find_element_by_class_name('addImg').click()#点击加号上传 time.sleep(2) #通过窗口打开 app = pywinauto.Desktop() time.sleep(2) #通过弹框名称进入控件中 win = app['打开'] time.sleep(2) #输入上传图片的地址 win['Edit'].type_keys(r'C:\TT\习知\课件\我的课件\1624958787.png') time.sleep(2) #点击打开按钮 win['Button'].click() time.sleep(5) driver.quit()#退出

多标签/多窗口之间的切换

场景:有的时候点击一个链接,新页面并非由当前页面跳转过去,而是新开一个页面打开,这种情况下,计算机需要识别多标签或窗口的情况。

句柄:窗口的唯一标识符。句柄顺序根据打开顺序来排

获取所有窗口的句柄

handles = driver.window_handlers

调用该方法会得到一个列表,在selenium运行过程中的每一个窗口都有一个对应的值存放在里面。

通过窗口的句柄进入的窗口

driver.switch_to_window(handles[n])

driver.switch_to.window(handles[n])

 

from selenium import webdriver from selenium.webdriver.common.by import By import time driver = webdriver.Chrome() driver.maximize_window() driver.get("https://www.baidu.com/") #获取所有窗口句柄 handlers_1 = driver.window_handles print(handlers_1) elements = driver.find_elements(By.XPATH,"//*[@class='title-content c-link c-font-medium c-line-clamp1']") elements[0].click() #获取所有窗口句柄 handlers_2 = driver.window_handles print(handlers_2) #通过句柄,切换窗口 driver.switch_to.window(handlers_2[1]) #点击新闻标题 driver.find_element(By.XPATH,"//p[@aria-label='标题:全球首架C919自12y月26日起验证飞行']").click() #获取所有窗口句柄 handlers_3 = driver.window_handles print(handlers_3) #通过句柄,切换回百度首页 driver.switch_to.window(handlers_2[0]) elements[1].click() #获取所有窗口句柄 handlers_4 = driver.window_handles print(handlers_4) time.sleep(5) driver.quit()

鼠标和键盘操作

手动测试时键盘的操作在selenium页有实现,关于鼠标的操作由ActionChains()类来提供,关于键盘的操作由Key()类来提供

鼠标操作

导入动作链类,动作链可以储存鼠标的动作,并一起执行

from selenium.webdriver import Actionchains

#执行鼠标右击操作

Actionchains(driver).context_click(ele).perform()

#Actionchains操作driver,存储鼠标右击动作,perform执行

鼠标双击

el = driver.find_element_by_xxx(value)

Actionchains (driver).double_click(e1).perform()

鼠标悬停

el = driver.find_element_by_xxx(value)#定位元素

Actionchains (driver).move_to_element(e1).perform()

键盘操作

键盘操作使用的是Keys类,一般配合send_keys使用。

导入

from selenium.webdriver. common.keys import Keys

常用键盘操作

  send_keys (Keys . BACK_SPACE)删除键(BackSpace)

  send_keys (Keys . SPACE)空格键(Space)

  send_keys (Keys . TAB)制表键(Tab)

  send_keys (Keys . ESCAPE)回退键(ESc)

  send_keys (Keys .ENTER)回车键(Enter)

  send_keys (Keys . CONTROL, ' a')全选(Ctrl+A)

  send_keys (Keys . CONTROL, 'c')复制(ctrl+C)

  send_keys (Keys. CONTROL, 'x')剪切(ctrl+X)

  send_keys (Keys. CONTROL, 'v')粘贴(ctrl+V)

  send_keys (Keys.F1)键盘F1

  send_keys (Keys.F12)键盘F12

 

from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver import Actionchains import time from selenium.webdriver. common.keys import Keys driver = webdriver.Chrome() driver.maximize_window() driver.get("https://www.baidu.com/ ") ele = driver.find_element(By.ID,"su") #模拟鼠标右击 Actionchains(driver).context_click(ele).perform() #模拟鼠标双击 Actionchains(driver).double_click(e1e).perform() #定位【设置】元素 set_element = driver.find_element(By.ID,"s-usersetting-top") #鼠标悬停至-设置 Actionchains(driver).move_to_element(set_element).perform() time.sleep(3) #点击-搜索设置 driver.find_element(By.XPATH,"//span[text()='搜索设置']").click() #定位搜索输入框 search_element = driver.find_element(By.ID,"kw") time.sleep(2) #输入:坚果 search_element.send_keys("坚果") time.sleep(2) #删除:果 search_element.send_keys(Keys.BACK_SPACE) time.sleep(2) #输入空格 search_element.send_keys(Keys.SPACE) time.sleep(2) #输入:python search_element.send_keys("python") time.sleep(2) #全选 search_element.send_keys(Keys.cONTROL,"a") time.sleep(2) #剪切 search_element.send_keys(Keys.cONTROL,'X') time.sleep(2) #粘贴5次 for i in range(5): search_element.send_keys(Keys.cONTROL,'v ') time.sleep(2) time.sleep(5) driver.quit()

弹出框操作

driver.switch_to.alert.text#获取弹出框信息

driver.switch_to.alert.accept()#确认警告

driver.switch_to.alert.dismiss()#关闭警告

 

from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver import Actionchains import time driver = webdriver.Chrome() driver.maximize_window() driver.get("https://www.baidu.com/") set_ele = driver.find_element(By . XPATH,"//span[text()='设置']") Actionchains(driver).move_to_element(set_ele).perform() time.sleep(2) driver.find_element(By.XPATH,"//span[text()='搜索设置']").click() time.sleep(2) driver.find_element(By.XPATH," //a[text()='保存设置']").click() time.sleep(2) #获取弹出框信息 print(driver.switch_to.alert.text) #确认警告#关掉弹出框并刷新 driver.switch_to.alert.accept() #关闭警告#关掉弹出框并刷新 driver.switch_to.alert.dismiss() time.sleep(5) driver.quit()

下拉框操作

selenium关于下拉框的操作都交由Select类进行处理,一般获取到下拉框元素之后使用该类构建对象,调用对象的响应方法就能操作元素

导入select类

from selenium.webdriver.support.select import select

将定位到的下拉框元素传入Select类中

selobj = select(element)#下拉框元素已经定位到

调用响应方法选择下拉框中的选项

  select_by_index()#通过索引选择,index索引从0开始

  select_by_value()#通过值选择(option标签的一个属性值)

  select_by_visible_text()#通过文本选择(下拉框的值)

  a11_selected_options#查看所有已选,返回的是元素

  first_selected_option#查看第一个已选

  is_multiple#查看是否是多选

  options#查看选项元素列表

  取消选择

  deselect_by_index()

  deselect_by_value()

  deselect_by_visible_text()

 

from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.support.select import selectimport time driver = webdriver.Chrome() driver.maximize_window() driver.get(r"C:\TT\习知\10\selenium-下\selectDemo.html") #定位下拉框元素 select_ele = driver.find_element(By.CSS_SELECTOR,"select") #初始化下拉框元素对象 select_obj = select(select_ele) #通过索引选择 for i in range(2,6): select_obj.select_by_index(i) time.sleep(2) #通过value属性选择 for value in ["chengdu","beijing","shandong","shanghai" ]: select_obj.select_by_value(value) time.sleep(2) #通过文本选择 for text in["成都","北京","山东","上海"]: select_obj.select_by_visible_text(text) time.sleep(2) driver.quit()

调用JS代码

什么是JS?

  JavaScript是世界上最流行的脚本语言,因为你在电脑、手机、平板上浏览的所有的网页,简单地说,JavaScript是一种运行在浏览器中的解释型的编程语言,用来给HTML网页增加动态功能。

  JavaScript是属于网络的脚本语言,被数百万计的网页用来改进设计、验证表单、检测浏览器、创建cookies,以及更多的应用。

为什么要执行js代码?

  因为selenium鞭长莫及,没有操作滚动条的方法,而一般操作滚动条都是使用js实现的。

下拉页面

  js = "window.scrollTo(x,y)"#x为水平拖动距离,y为垂直拖动距离

  js = "var q=document.documentElement.scrollTop=n"#将整个html页面拖动到距离顶端n的位置

  driver.execute_script(js)#执行js

 

from selenium import webdriver from selenium.webdriver.common.by import By import time driver = webdriver.Chrome() driver.maximize_window() driver.get("https:// www.baidu.com/") driver.find_element(By.ID,"kw" ).send_keys("坚果") driver.find_element(By. ID,"su").click() #js实现页面下拉 for i in range(1,6): js = f"window.scrollTo(0,{i*200})"#下拉5次 js = "var q=document.documentElement.scrollTop={i*200}"#将整个html页面拖动到距离顶端的位置 print(js) driver.execute_script(js) time.sleep(2) time.sleep(5) driver.quit()

等待

为什么要进行等待

  网速慢

  网站内容过多

  如果不进行等待而直接定位元素,可能会抛出异常

selenium中等待的分类

  固定等待

  显式等待

  隐式等待

固定等待//非必要不使用

  import time

  time.sleep(1)

显示等待

  显示等待是根据条件进行等待,等待条件出现

 

from selenium.webdriver. common.by import By from selenium.webdriver.support.ui import webDriverWait from selenium.webdriver.support import expected_conditions as EC #webDriverwait(driver,timeout,po11_frequency=0.5,ignored_exceptions=None) #十秒内每0.5秒检查一次条件,条件为移动到【高级搜索】 ele = webDriverwait(driver,10,0.5).until(EC.presence_of_element_located((By.XPATH,"//span[text()='高级搜索']"))) ele.click()

 

import time from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC driver = webdriver.Chrome( driver.maximize_window( driver.get("https: //www.baidu.com/") #element = driver.find_element(By.XPATH," //span[text()='搜索设置']") #显示等待 sart_time = time.time() element = WebDriverWait(driver,10,0.5).until(EC.presence_of_element_located((By.XPATH,"//span[text()='高级搜索']"))) end_time = time.time( print("元素定位耗时: ",end_time-start_time)

  WebDriverWait类是由WebDirver提供的等待方法。在设置时间内,默认每隔一段时间检测一次当前页面元素是否存在,如果超过设置时间检测不到则抛出异常。

隐式等待

  隐式等待是根据事件进行等待,等待特定时间

driver.implicitly_wait(n)

n的单位为秒,n为最大值,在这个最大值内只要元素定位到就结束等待

 

import time from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait ifrom selenium.webdriver . support import expected_conditions as EC driver = webdriver.Chrome() driver.maximize_window() driver.get("https://www.baidu.com/") #隐式等待 driver.implicitly_wait(10) start_time = time.time() #10秒内只要元素定位到就结束等待 element = driver.find_element(By.XPATH,"//span[text()='搜索设置']") end_time = time.time() print("元素定位耗时: ",end_time-start_time)

优先隐式等待,次之显式等待,最次固定等待

隐式等待对整个页面设置生效,显式等待对单次生效

cookies操作

cookie由服务器生成,存储在客户端的登录凭证

selenium对cookies的操作

  get_cookies()#获取所有cookies

  get_cookie(key)#获取key对应的值

  add_cookie(cookie_dict)#设置cookies

  delete_cookie(name)#删除指定名称的cookie

  delete_all_cookies()#删除所有cookie

 

from selenium import webdriver from selenium.webdriver.common.by import By import time driver = webdriver.Chrome() driver.maximize_window() driver.get("https://work.weixin.qq.com/") driver.implicitly_wait(5) #点击-企业登录 driver.find_element(By.XPATH,"//a[@class='index_top_operation_loginBtn' ]").click() time.sleep(20)#等待20秒扫码登录 #get_cookies() 获取所有cookies print(driver.get_cookies()) #设置cookies可以绕过登录 my_cookies = [{'domain': .wank.wreixin.g .com','expiny ': 1674485721.852195,'httpOnly : False,'name': 'wmwntx.i18n.l.an'}] for cookie in my_cookies: driver.add_cookie(cookie) driver.get("https://work.weixin.qq.com/wework_admin/frame") driver.quit()

web框架封装

POM设计模式,页面对象模型。是一种封装思想,旨在为每个待测页面创建一个页面对象,从而将繁琐的定位操作、操作细节封装到这个页面对象中,对外只提供必要的操作接口,在调用的时候只调用提供的接口,不用去调用操作细节,最终实现程序的高内聚低耦合,使程序模块的可重用性、移植性大大增强

PageObject六大原则
  • 用公共方法表示页面提供的服务,例如:登录页面,有用户名输入框、密码输入框、登录按钮,于是就可以用input_username()代表输入用户名、用input_password()代表输入密码、用click_submit()代表点击登录按钮

  • 尽量不要暴露页面的内部信息,将操作细节封装成方法,对外只提供对应的方法供调用

  • 一般不使用断言断言,要和Page代码分开,不要将断言写在PageObject层

  • 方法返回其他PageObjects。例如:首页有个方法是点击登录图标跳转到登录页面,因此这个方法应该返回login_page

  • 不需要表示整个页面不需要对页面中的每一个元素进行建模,只需要关注我们需要用到的元素。例如:登录页面除了账号密码登录,还有快捷登录、手机短信登录、扫码登录等

  • 同一行为的不同结果可以用不同的方法来模拟。例如:对一个页面进行操作,可能出现正确的结果或者错误的结果,可以为这两种不同的结果分别创建两个不同的方法

base:base_page,基类,定义项目所需的公共方法,对Selenium一些常用的api进行二次封装,如:find_element、click、send_keys、screenshot、调用JavaScript脚本的方法以及其他与浏览器相关的操作

  为什么要有基类?

    由于每个页面都会频繁使用这些方法,若单纯使用Selenium原始api,可能遇到一些问题,例如:某个按钮未加载完成,但已触发了点击事件,导致元素定位不到而报错。这时就可以对原始api进行二次封装,如:加入等待时间、对异常进行捕获并打印日志等,之后所有的PageObject都继承BasePage类,后续只需要调用这些封装好的方法,增强复用性

    假设以后不使用Selenium这个框架,就只需要修改BasePage中的方法,不用去修改具体的测试用例业务代码

pages:page_object,页面对象层,也是PO的核心层,继承BasePage,管理页面元素以及操作元素的方法(将操作元素的动作写成方法)

cases:测试用例层,用于管理测试用例,这里会用到单元测试框架,如:Pytest、Unittest。

data:测试数据层,用于测试数据的管理,数据与脚本分离,降低维护成本,提高可移植性,如:yml 文件数据

config:配置文件层,存放整个项目需要用到的配置项,如:URL、数据库信息等

utils:CommonUtil,公共模块,将一些公共函数、方法以及通用操作进行封装,如:日志模块、yaml 操作模块、时间模块等

run.py:批量执行测试用例的主程序,根据不同需求不同场景进行组装,遵循框架的灵活性和扩展性

logs:日志模块,用于记录和管理日志,针对不同情况,设置不同的日志级别,方便定位问题

reports:测试报告层,用于测试报告的生成和管理,如:基于 Allure 生成的定制化报告

企业微信成员添加案例

  不使用po封装

 

import time import yaml from selenium import webdriver from selenium.webdriver.common.by import By from webdriver_manager.chrome import ChromeDriverManager driver = webdriver.Chrome(ChromeDriverManager().install() time.sleep(3) driver.get("https: //work.weixin.qq.com/wework_admin/frame") #登录操作 root = os.path.dirname(__file__)#获取根目录 yaml_path = os.path.join(root,"cookies.yaml")#获取cookies文件 if os.path.exists(yaml_path): with open(yaml_path,"r",encoding="utf-8") as f:#打开cookies文件 cookies = yaml.safe_load(f) if cookies: for cookie in cookies:#写入cookies driver.add_cookie(cookie)] driver.refresh() page = driver.page_source if"退出" not in page : time.sleep(15)#等待扫码登录 cookies = driver.get_cookies() with open(yaml_path,"w",encoding="utf-8") as f:#保存cookies文件 yaml.safe_dump(cookies,f) driver.implicitly_wait(10)#隐式等待 #添加成员操作 driver.find_element(By.XPATH,"//*[text()=添加成员']").click()#定位添加成员元素点击 driver.find_element(By.ID,"username").send_keys(f"test{random. randint(0, 999999)}")#定位username元素输入随机用户名 driver.find_element(By.ID,"memberAdd_acctid").send_keys(f"test{(random.randint(0,999999)}")#定位memberAdd_acctid元素输入随机id phone = f"13466{random.randint(100000, 999999)}"#生成11位随机电话 driver.find_element(By.ID,"memberAdd_phone").send._keys(phone)#定位电话元素输入电话 driver.find_element(By.CSS_SELECTOR,".js_btn_save").click()#定位保存元素点击保存 while True: eles = driver.find_elements(By.XPATH,'//*[@id="member_list"]//tr/td[5]')#获取电话列表 if len(eles)>0:#判断是否获取全部电话列表 break phone_list =[] for ele in eles: phone_list.append(ele.text) assert phone in phone_list#电话断言判断电话是否添加成功 time.sleep(3) driver.close()

  使用po封装    main.py

 

import pytest if __name__ = " __main__': pytest.mian()

    优化base/base.py基础封装一些公共方法

 

import os.path import yaml from selenium import webdriver from webdriver_manager.chrome import ChromeDriverManager class Base: def __init__(self,driver=None): if driver is None: #实例化浏览器操作 self.driver = webdriver.Chrome(ChromeDriverHanager().install()) self.driver.implicitly wait(10) self.driver.maximize_windowO self.driver.get("https://work.weixin.qq.com/wework_adnin/frame") root = os.path.dirname(os.path.dirname(__file__)) path = os.path.join(root, "cookies.yaml") if os.path.exists(path) with open(path, amoning="utf-8") as f: cookies = yaml.safe_load(f) for cookie in cookies: self.driver.add_cookie(cookie) self.driver.refresh() if "退出" not in self.driver.page_source: time.sleep(15) with open(path,"w", aSn8ithg="utf-8" ) as f: yaml.safe_dump(self.driver.get_cookies(),f) else: self.driver = driver

    page/index_page.py

 

from selenium.webdriver.common.by import By from base.base import Base from page.edit_member_info_page import EditHemberIndoPage class IndexPaqe(Base): def goto_edit_member(self): self.driver.find_element(By.XPATH,'//*[text()="添加成员"]').click() return EditMemberIndoPage(self.driver)#传自身浏览器过去执行

    page/edit_member_info_page.py

 

from selenium.webdriver.common.by import By from base.base import Base from page.member_list_page import MemberListPage class EditMemberIndoPaqe(Base): def edit_member(self, name,username, phone): self.driver.find_element(By.ID,"username").send_keys(name) self.driver.find_element(By.ID,"memberAdd_acctid").send_keys(username) self.driver.find_element(By.ID,"memberAdd_phone").send_keys(phone) self.driver.find_element(By.CSS_SELECTOR,".js_btn_save").click() return MemberListPage()

    page/member_list_page.py

 

from selenium.webdriver.common.by import By from base.base import Base class MemberListPage(Base): def get_result(self): while True : eles = self.driver.find_elements(By.XPATH,'//*[@id="member_list"]//tr/td[5]') if len(eles) > 0: break phone_list =[] for ele in eles; phone_list.append(ele.text) return phone_list

    cases/add_member_test.py

 

import random from page .index_page import IndexPage class TestAddHember: def setup_class(self): self.index = IndexPage()#实例化index def teste1(self): phone =f"13466{random.randint(10008e,999999)}" name = f"test{random.randint(0,999999)}" username =f"test{random.randint(0,999999)}" phone_list = self.index.goto_edit_member().edit_member(name,username,phone).get_result() assert phone in phone_list

    继续优化,不暴露页面内部信息      page/index_page.py

 

from selenium.webdriver.common.by import By from base.base import Base from page.edit_member_info_page import EditHemberIndoPage class IndexPaqe(Base): __add_member_btn =(By. XPATH,'//*[text()=添加成员"]') def goto_edit_member(self): self.driver.find_element(*self.__add_member_btn).click() return EditMemberIndoPage(self.driver)#传自身浏览器过去执行

      page/edit_member_info_page.py

 

from selenium.webdriver.common.by import By from base.base import Base from page.member_list_page import MemberListPage class EditMemberIndoPaqe(Base): __name_input =(By.ID,"username") __username_input = (By.ID,"memberAdd_acctid") __phone_input =(By.ID,"memberAdd_phone") __save_btn =(By.css_SELECTOR,".js_btn_save") def edit_member(self, name,username,phone) self.driver.find_element(*self.__name_input).send_keys(name) self.driver.find_element(*self.__username_input).send_keys(username) self.driver.find_element(*self.__phone_input).send_keys(phone) self.driver.find_element(*self.__save_btn).click() return MemberListPage(self.driver)

      page/member_list_page.py

 

from selenium.webdriver.common.by import By from base.base import Base class MemberListPage(Base): __phones_list=(By.XPATH,'//*[@id="member_list"]//tr/td[5]') def get_result(self): while True : eles = self.driver.find_elements(*self.__phones_list) if len(eles) > 0: break phone_list =[] for ele in eles; phone_list.append(ele.text) return phone_list

      base/base.py基础封装一些公共方法

 

import os.path import yaml from selenium import webdriver from webdriver_manager.chrome import ChromeDriverManager class Base: _url="https://work.weixin.qq.com/wework_adnin/frame"#子类可以自己改写地址 def __init__(self,driver=None): if driver is None: #实例化浏览器操作 self.driver = webdriver.Chrome(ChromeDriverHanager().install()) self.driver.implicitly wait(10) self.driver.maximize_windowO self.driver.get(self._url) root = os.path.dirname(os.path.dirname(__file__)) path = os.path.join(root, "cookies.yaml") if os.path.exists(path) with open(path, amoning="utf-8") as f: cookies = yaml.safe_load(f) for cookie in cookies: self.driver.add_cookie(cookie) self.driver.refresh() if "退出" not in self.driver.page_source: time.sleep(15) with open(path,"w", aSn8ithg="utf-8" ) as f: yaml.safe_dump(self.driver.get_cookies(),f) else: self.driver = driver

      同一行为的不同结果用不同的方法来模拟        page/edit_member_info_page.py

 

from selenium.webdriver.common.by import By from base.base import Base from page.member_list_page import MemberListPage class EditMemberIndoPaqe(Base): __name_input =(By.ID,"username") __username_input = (By.ID,"memberAdd_acctid") __phone_input =(By.ID,"memberAdd_phone") __save_btn =(By.css_SELECTOR,".js_btn_save") def edit_member(self, name,username,phone) self.driver.find_element(*self.__name_input).send_keys(name) self.driver.find_element(*self.__username_input).send_keys(username) self.driver.find_element(*self.__phone_input).send_keys(phone) self.driver.find_element(*self.__save_btn).click() return MemberListPage(self.driver) def edit_member_fsil(self, name,username,phone) self.driver.find_element(*self.__name_input).send_keys(name) self.driver.find_element(*self.__username_input).send_keys(username) self.driver.find_element(*self.__phone_input).send_keys(phone) self.driver.find_element(*self.__save_btn).click() res = self.driver.find_element(By.ID."xxx").text()#示例代码返回手机号已注册报错信息 return res

        cases/add_member_test.py

 

import random from page .index_page import IndexPage class TestAddHember: def setup_class(self): self.index = IndexPage()#实例化index def teste1(self): phone =f"13466{random.randint(10008e,999999)}" name = f"test{random.randint(0,999999)}" username =f"test{random.randint(0,999999)}" phone_list = self.index.goto_edit_member().edit_member(name,username,phone).get_result() assert phone in phone_list def teste2(self):#另一个方法 phone =f"13466{random.randint(10008e,999999)}" name = f"test{random.randint(0,999999)}" username =f"test{random.randint(0,999999)}" res = self.index.goto_edit_member().edit_member_fail(name,username,phone) assert res =="手机号已注册"

  base层封装方法

  base/base.py基础封装一些公共方法

 

import os.path import time import yaml from selenium import webdriver from selenium.webdriver.remote.webdriver import WebDriver from webdriver_manager.chrome import ChromeDriverManager from base.handle import warpper class Base: _url="https://work.weixin.qq.com/wework_adnin/frame"#子类可以自己改写地址 def __init__(self,driver=None): if driver is None: #实例化浏览器操作 self.driver = webdriver.Chrome(ChromeDriverHanager().install()) self.driver.implicitly wait(10) self.driver.maximize_windowO self.driver.get(self._url) root = os.path.dirname(os.path.dirname(__file__)) path = os.path.join(root, "cookies.yaml") if os.path.exists(path) with open(path, amoning="utf-8") as f: cookies = yaml.safe_load(f) for cookie in cookies: self.driver.add_cookie(cookie) self.driver.refresh() if "退出" not in self.driver.page_source: time.sleep(15) with open(path,"w", aSn8ithg="utf-8" ) as f: yaml.safe_dump(self.driver.get_cookies(),f) else: self.driver = driver def find(self, by,loc=None) if loc is None : return self.driver.find_element(*by) else: return self.driver.find_element(by,loc) def finds(self, by, loc=None): if loc is None : return self.driver.find_elements(*by) else: return self.driver.find_elements(by,loc) def click(self, by,loc=None): ele = self.find(by,loc) ele.click() def send(self, by,loc=None,text=None): ele = self.find(by,loc) ele.clear() ele.send_keys(text) def texts(self, by, loc=None) : while True: eles = self.finds(by,loc) if len(eles) > 0: break text_list = [] for ele in eles: text_list.append(ele.text) return text_list

  page/index_page.py

 

from selenium.webdriver.common.by import By from base.base import Base from page.edit_member_info_page import EditHemberIndoPage class IndexPaqe(Base): _url = "https: //work.weixin.qq.com/wework_admin/frame" __add_member_btn = (By.XPATH,'//*[text()="添加成员"]') def goto_edit_member(self): self.click(*self.__add_member_btn) return EditMemberIndoPage(self.driver)#传自身浏览器过去执行

  page/edit_member_info_page.py

 

from selenium.webdriver.common.by import By from base.base import Base from page.member_list_page import MemberListPage class EditMemberIndoPaqe(Base): __name_input =(By.ID,"username") __username_input = (By.ID,"memberAdd_acctid") __phone_input =(By.ID,"memberAdd_phone") __save_btn =(By.css_SELECTOR,".js_btn_save") def edit_member(self, name,username,phone): self.send(*self.__name_input,text=name) self.send(*self.__username_input,text=username) self.send(*self.__phone_input,text=phone) self.click(*self.__save_btn) return MemberListPage(self.driver)

  page/member_list_page.py

 

from selenium.webdriver.common.by import By from base.base import Base class MemberListPage(Base): __phones_list=(By.XPATH,'//*[@id="member_list"]//tr/td[5]') def get_result(self): phone_list = self.texts(self.__phones_list) return phone_list

  利用装饰器

  base/handle.py

 

import allure def warpper(fun): def inner(*args,**kwargs) : from base.base import Base s:Base = args[0] try: return fun(*args,**kwargs) except: #s.save_img("1.png")保存 #出错后截图添加到测试报告中 allure.attach(s.driver.get_screenshot_as_png(),attachment_type=allure.attachment.type.PNG) return inner

  base/base.py基础封装一些公共方法

 

import os.path import time import yaml from selenium import webdriver from selenium.webdriver.remote.webdriver import WebDriver from webdriver_manager.chrome import ChromeDriverManager from base.handle import warpper class Base: _url="https://work.weixin.qq.com/wework_adnin/frame"#子类可以自己改写地址 def __init__(self,driver=None): if driver is None: #实例化浏览器操作 self.driver = webdriver.Chrome(ChromeDriverHanager().install()) self.driver.implicitly wait(10) self.driver.maximize_windowO self.driver.get(self._url) root = os.path.dirname(os.path.dirname(__file__)) path = os.path.join(root, "cookies.yaml") if os.path.exists(path) with open(path, amoning="utf-8") as f: cookies = yaml.safe_load(f) for cookie in cookies: self.driver.add_cookie(cookie) self.driver.refresh() if "退出" not in self.driver.page_source: time.sleep(15) with open(path,"w", aSn8ithg="utf-8" ) as f: yaml.safe_dump(self.driver.get_cookies(),f) else: self.driver = driver @warpper def find(self, by,loc=None) if loc is None : return self.driver.find_element(*by) else: return self.driver.find_element(by,loc) def finds(self, by, loc=None): if loc is None : return self.driver.find_elements(*by) else: return self.driver.find_elements(by,loc) def click(self, by,loc=None): ele = self.find(by,loc) ele.click() def send(self, by,loc=None,text=None): ele = self.find(by,loc) ele.clear() ele.send_keys(text) def texts(self, by, loc=None) : while True: eles = self.finds(by,loc) if len(eles) > 0: break text_list = [] for ele in eles: text_list.append(ele.text) return text_list #截图保存功能 #def save_img(self, img_name) : #self.driver.save_screenshot(img_name)

  元素,操作步骤封装到文件然后通过文件读取调用

  locator/edit_member_info_page.yaml

 

-find:username by:id action:send text:name -find: memberAdd_acctid by: id action: send text: user_id -find: memberAdd_phone by: id action: send text: phone -find: ".js_btn_save" by: "css selector" action: click

  base/base.py基础封装一些公共方法

 

import os.path import time import yaml from selenium import webdriver from selenium.webdriver.remote.webdriver import WebDriver from webdriver_manager.chrome import ChromeDriverManager from base.handle import warpper class Base: _url="https://work.weixin.qq.com/wework_adnin/frame"#子类可以自己改写地址 def __init__(self,driver=None): if driver is None: #实例化浏览器操作 self.driver = webdriver.Chrome(ChromeDriverHanager().install()) self.driver.implicitly wait(10) self.driver.maximize_windowO self.driver.get(self._url) root = os.path.dirname(os.path.dirname(__file__)) path = os.path.join(root, "cookies.yaml") if os.path.exists(path) with open(path, amoning="utf-8") as f: cookies = yaml.safe_load(f) for cookie in cookies: self.driver.add_cookie(cookie) self.driver.refresh() if "退出" not in self.driver.page_source: time.sleep(15) with open(path,"w", aSn8ithg="utf-8" ) as f: yaml.safe_dump(self.driver.get_cookies(),f) else: self.driver = driver @warpper def find(self, by,loc=None) if loc is None : return self.driver.find_element(*by) else: return self.driver.find_element(by,loc) def finds(self, by, loc=None): if loc is None : return self.driver.find_elements(*by) else: return self.driver.find_elements(by,loc) def click(self, by,loc=None): ele = self.find(by,loc) ele.click() def send(self, by,loc=None,text=None): ele = self.find(by,loc) ele.clear() ele.send_keys(text) def texts(self, by, loc=None) : while True: eles = self.finds(by,loc) if len(eles) > 0: break text_list = [] for ele in eles: text_list.append(ele.text) return text_list #截图保存功能 #def save_img(self, img_name) : #self.driver.save_screenshot(img_name) #文件读取功能 def load(self,yaml_file,data=None): root = os.path.dirname(os.path.dirname(__file__)) locator = os.path.join(root,"locator",yaml_file) with open(locator,encoding="utf-8") as f: steps = yaml.safe_load(f) for step in steps: expr = step.get("find") action = step.get("action") by = step.get("by") if action == "send" : if data is not None : if step.get("text") in data.keys(): self.send(by, expr,data[step.get("text")]) else: self.send(by, expr,step.get("text")) else: self.send(by,expr, step.get("text")) else: getattr(self, action)(by,expr)

  page/edit_member_info_page.py

 

from selenium.webdriver.common.by import By from base.base import Base from page.member_list_page import MemberListPage class EditMemberIndoPaqe(Base): __name_input =(By.ID,"username") __username_input = (By.ID,"memberAdd_acctid") __phone_input =(By.ID,"memberAdd_phone") __save_btn =(By.css_SELECTOR,".js_btn_save") def edit_member(self,data=None): self.load("edit_member_info_page.yaml",data) return MemberListPage(self.driver)

  cases/add_member_test.py

 

import random from page .index_page import IndexPage class TestAddHember: def setup_class(self): self.index = IndexPage()#实例化index def teste1(self): data = { "name": f"test{random.randint(0,999999)}", "username" : f"test{random.randint(0,999999)}", "phone": f"13466{random.randint(100000,999999)}" } phone_list = self.index.goto_edit_member().edit_member(data).get_result() assert data["phone"] in phone_list

  • 19
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
您可以使用 Python 中的 OpenCV 库来捕获视频流,并使用 Tkinter 或 PyQt5 等 UI 库创建 UI 界面。 以下是一个简单的示例代码,使用 OpenCV 和 Tkinter 来实现一个 UI 界面,可以捕获视频流并将其显示在窗口中: ```python import cv2 import tkinter as tk from PIL import Image, ImageTk class VideoCapture: def __init__(self, video_source=0): self.video_capture = cv2.VideoCapture(video_source) if not self.video_capture.isOpened(): raise ValueError("Unable to open video source", video_source) self.width = self.video_capture.get(cv2.CAP_PROP_FRAME_WIDTH) self.height = self.video_capture.get(cv2.CAP_PROP_FRAME_HEIGHT) def get_frame(self): _, frame = self.video_capture.read() return cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) class App: def __init__(self, window, window_title): self.window = window self.window.title(window_title) self.video_capture = VideoCapture() self.canvas = tk.Canvas(window, width=self.video_capture.width, height=self.video_capture.height) self.canvas.pack() self.delay = 15 self.update() self.window.mainloop() def update(self): frame = self.video_capture.get_frame() self.photo = ImageTk.PhotoImage(image=Image.fromarray(frame)) self.canvas.create_image(0, 0, image=self.photo, anchor=tk.NW) self.window.after(self.delay, self.update) App(tk.Tk(), "Video Stream") ``` 这个示例代码创建了一个 UI 界面,其中包含一个 Canvas 组件,用于显示视频流,以及一个 VideoCapture 类,用于捕获视频流。update() 方法会不断地从 VideoCapture 类中获取帧,并将其显示在 Canvas 组件中。您可以将此代码作为起点,并根据自己的需求进行修改和扩展。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值