Playwright之初体验

news/2025/2/13 19:22:52/

参考文件

官方文档:https://playwright.dev/docs/intro
GitHub链接:https://github.com/microsoft/playwright-python

Playwright简介

Playwright Test是专门为满足端到端测试的需求而创建的。Playwright支持所有现代搜索引擎,包括Chrome、WebKit和Firefox。在Windows、Linux和macOS上测试,使用Android和mobile Safari的Google Chrome原生移动模拟进行测试。

环境安装

安装python环境
Playwright安装
使用pip install playwright命令进行安装
在这里插入图片描述
使用playwright install命令进行各种工具包和依赖,有报错,我们先不管,继续往下走
在这里插入图片描述
安装pytest插件:pip install pytest-playwright
在这里插入图片描述

简单跑一个demo,发现报错了,我们换一种执行方式
在这里插入图片描述

我们使用pytest命令执行发现没有报错
在这里插入图片描述

Playwright的自带工具

Playwright codegen
我们在pycharm中使用终端,输入该命令,之后,就会启用被测浏览器,并且启用inspector记录操作的脚本
在这里插入图片描述

Playwright inspector
在这里插入图片描述
之后我们可以将inspector里面的代码复制到pycharm里面自己编辑了

当然,我们也可以针对某个浏览器的网址,比如说https://www.baidu.com/

在这里插入图片描述

回车之后,浏览器自动启动一个标签,以及一个inspector来记录操作代码
在这里插入图片描述

也可以固定浏览器某个窗口的大小进行操作

Playwright codegen --viewport-size=800,600 www.baidu.com
在这里插入图片描述

在这里插入图片描述

访问移动端手机浏览器,比如说苹果13

Playwright codegen --device=“iPhone 13” www.baidu.com

在这里插入图片描述

在这里插入图片描述

帮助我们自动记录和管理cookie信息

首先我们使用如下命令Playwright codegen --save-storage=auth.json work-be.test.mi.com/main-buildstore/home/address:8000
然后浏览器启动一个窗口
在这里插入图片描述

接下来我们自动输入密码,如下:
在这里插入图片描述
之后,我们把启动的浏览器关掉
接下来,我们再次使用如下命令再次回车
Playwright codegen --load-storage=auth.json work-be.test.mi.com/main-buildstore/home/address:8000
在这里插入图片描述

浏览器会再次启动一个新窗口,但是此窗口浏览器的地址我们可以看到是登录状态的
在这里插入图片描述
Trace Viewer是Playwright的另一个神器,顾名思义就是痕迹查看,也就是我们后期可以查看我们之前都操作了哪些地方

Playwright架构技术介绍

Playwright是由Puppeteer-https://puppeteer.bootcss.com/改造过来的,Puppeteer 是一个 Node 库,它提供了一个高级 API 来通过 DevTools 协议控制 Chromium 或 Chrome。Puppeteer 默认以 headless 模式运行,但是可以通过修改配置文件运行“有头”模式。再加上,Playwright官方没有给出架构图,所以我们可以参考Puppeteer的架构图来学习Playwright
首先我们可以通过Puppeteer来控制浏览器的,他是通过谷歌开发者协议,简称CDP,该协议是建立在WebSocket协议之上
这里的Brower其实是一个浏览器实例,一个浏览器可以包含很多个上下文,也就是包含很多Context,通俗来讲,就跟我们打开了一个谷歌浏览器,又开启了一个无痕模式浏览器一样,Brower的Context具有独立的Session,cookie&cache
一个Context可以包含很多个Page页面,一个Page是一个独立页面
一个Page可以包含很多个Frame,一个Frame可以理解为是一个框架,可以包含多个子框架
再往下就是ExecutionContext,它是javascript的执行环境,每一个Frame都有一个默认的javascript的执行环境
在Playwright中,这些概念也是一样的
在这里插入图片描述

第一个Playwright脚本

from playwright.sync_api import sync_playwrightdef test_pla():with sync_playwright() as p:#实例化一个浏览器,使用谷歌为例#代码运行默认是无头模式运行,如果要看运行效果,可以加入参数headlessbrowser = p.chromium.launch(headless=False)#实例化一个页面page = browser.new_page()#打开一个网站page.goto("https://www.bilibili.com")#打印网页标题print(page.title())#关闭浏览器browser.close()

运行之后:
在这里插入图片描述

Playwright浏览器控制

谷歌官方相关命令地址:https://peter.sh/experiments/chromium-command-line-switches/

from playwright.sync_api import sync_playwrightdef test_pla():with sync_playwright() as p:#实例化一个浏览器,使用谷歌为例#代码运行默认是无头模式运行,如果要看运行效果,可以加入参数headless#--start-maximized表示窗口最大化,no_viewport表示的是默认窗口大小失效#slow_mo表示的是每一步操作,默认等待3sbrowser = p.chromium.launch(headless=False,args=["--start-maximized"],slow_mo=3000)#实例化一个页面page = browser.new_page(no_viewport=True)#打开一个网站page.goto("https://www.zhihu.com")#打印网页标题print(page.title())#点击开通机构号page.get_by_text("开通机构号").click()#后退page.go_back()#前进page.go_forward()#刷新page.reload()#关闭浏览器browser.close()

Playwright浏览器启动参数详解

executable_path——数据路径
channel——指定使用哪种浏览器
args——参数数组
ignore_default_args——忽略默认参数,慎用,使用不当,脚本无法执行
timeout——等待浏览器实例启动的最长时间,单位毫秒,一般是30s,设置为0,功能失效
headless——有头和无头模式运行的设置
traces_dir——数据报错路径
chromium_sandbox——是否启动谷歌沙盒浏览器
等等,基本所有参数都是launch()函数里面的,可以自行查看
在这里插入图片描述

Playwright xpath元素定位

XML Path Language

from playwright.sync_api import sync_playwrightdef test_pla():with sync_playwright() as p:#实例化一个浏览器,使用谷歌为例#代码运行默认是无头模式运行,如果要看运行效果,可以加入参数headless#--start-maximized表示窗口最大化,no_viewport表示的是默认窗口大小失效#slow_mo表示的是每一步操作,默认等待3sbrowser = p.chromium.launch(headless=False,args=["--start-maximized"],slow_mo=3000)#实例化一个页面page = browser.new_page(no_viewport=True)#打开一个网站page.goto("https://www.baidu.com")"""/:从根节点选取//:从非根节点选取*:任意节点选取@:根据属性筛选text():根据文本筛选and:关联属性或者链接文本[]:可以防止下标/属性/链接文本.:选取当前节点..:选取当前节点的父节点contains:包含"""#使用单一属性定位,   点击百度首页设置按钮,使用text_content获取内容t_1 = page.locator("//span[@name='tj_settingicon']").text_content()print(t_1)#多属性定位t_2 = page.locator("//span[@id='s-usersetting-top' and @name='tj_settingicon']").text_content()print(t_2)#父节点定位t_3 = page.locator('//div[@id="u1"]/span').text_content()print(t_3)#通过下标进行定位,新闻这个按钮t_4 = page.locator('//div[@id="s-top-left"]/a[1]').text_content()print(t_4)#通过.和..来定位t_5= page.locator('//a[@name="tj_fanyi"]/div/../../../../../a[1]').text_content()print(t_5)#通过文本定位t_6 = page.locator('//a[text()="新闻"]').text_content()print(t_6)#通过模糊匹配定位t_7 = page.locator('//a[contains(text(),"hao")]').text_content()print(t_7)#关闭浏览器browser.close()

运行之后:
在这里插入图片描述

Playwright css定位

css定位方式有五种,分别是:
id选择器
class选择器
元素选择器
属性选择器
层级选择器

from playwright.sync_api import Playwright, sync_playwright, expectplaywright = sync_playwright().start()
browser = playwright.chromium.launch(headless=False,slow_mo=2000)
page = browser.new_page()
page.goto("https://www.baidu.com/")#id属性定位
page.locator("#kw").fill("playwright")
page.locator("#su").click()page.go_back()
page.locator(".s_ipt").fill("playwright")
page.locator("#su").click()page.go_back()
page.locator("input#kw").fill("playwright")
page.locator("#su").click()page.go_back()
page.locator("div>form>span>input.s_ipt").fill("playwright")  #层级关系
page.locator("#su").click()browser.close()

Playwright特有定位方式

"""
特有元素定位方法
locator.get_by_alt_text(text,**kwargs),  alt属性
locator.get_by_label(text,**kwargs),label属性
locator.get_by_placeholder(text,**kwargs),placeholder属性
locator.get_by_role(role,**kwargs),role属性
locator.get_by_text(text,**kwargs)
locator.get_by_title(text,**kwargs)
"""

Playwright元素常用操作

我们以该网页为例子进行测试
登陆页面,我们输入用户名、密码、验证码,点击登录

同时,我们介绍怎么处理iframe进行上传文件以及自动化,在上传文件中,我们要注意,每一个图片都有一个随机的字符串

在这里插入图片描述
所以我们可以使用父节点定位方式进行定位处理
“//*[@id=‘filePicker’]/div[2]/input”
在这里插入图片描述
接下来是图片的上传,图片我们先使用set_input_files函数,绝对路径处理,前面添加r
r"C:\Users\jinlai\111.jpg"
具体代码如下:

from playwright.sync_api import Playwright, sync_playwright, expectplaywright = sync_playwright().start()
browser = playwright.chromium.launch(headless=False,slow_mo=2000)
context = browser.new_context()
page = browser.new_page()
page.goto("http://testingedu.com.cn:8000/Home/user/login.html")
#输入用户名
page.fill('//*[@id="username"]','13800138006')
#输入密码
page.fill('//*[@id="password"]','123456')
#输入验证码,这里做了处理
page.fill('//*[@id="verify_code"]','1111')
#点击登录
page.click('//*[@id="loginform"]/div/div[6]/a')#进入个人信息页面
page.goto("http://testingedu.com.cn:8000/Home/User/info.html")
#点击图片
page.click('//*[@id="preview"]')
#点击点击选择图片按钮
page.frame_locator('//*[@id="layui-layer-iframe1"]').locator("//*[@id='filePicker']/div[2]/input").set_input_files(r"C:\Users\jinlai\111.jpg")
#点击确认使用
page.frame_locator('//*[@id="layui-layer-iframe1"]').locator("//div[@class='saveBtn']").click()
#点击页面的确认保存
page.click("//input[@class='save']")#关闭浏览器
browser.close()

接下来我们看下拉框怎么处理

#下拉框收货地址处理,我们需要定位到要操作的输入框,然后根据内容属性处理即可

page.select_option('//*[@id="province"]',value='19280')
page.select_option('//*[@id="city"]',value='19281')
page.select_option('//*[@id="district"]',value='19283')
page.select_option('//*[@id="twon"]',value='19285')
from playwright.sync_api import Playwright, sync_playwright, expectplaywright = sync_playwright().start()
browser = playwright.chromium.launch(headless=False,slow_mo=2000)
context = browser.new_context()
page = browser.new_page()
page.goto("http://testingedu.com.cn:8000/Home/user/login.html")
#输入用户名
page.fill('//*[@id="username"]','13800138006')
#输入密码
page.fill('//*[@id="password"]','123456')
#输入验证码,这里做了处理
page.fill('//*[@id="verify_code"]','1111')
#点击登录
page.click('//*[@id="loginform"]/div/div[6]/a')#打开地址管理页面
page.goto("http://testingedu.com.cn:8000/Home/User/address_list.html")
#点击增加新地址
page.click("//*[@class='co_blue']")
#点击并输入收货人
page.fill("//*[@name='consignee']","ceshi")
#点击并输入手机或者电话
page.fill("//*[@name='mobile']","13176358824")#下拉框收货地址处理
page.select_option('//*[@id="province"]',value='19280')
page.select_option('//*[@id="city"]',value='19281')
page.select_option('//*[@id="district"]',value='19283')
page.select_option('//*[@id="twon"]',value='19285')#点击并输入详细地址
page.fill("//*[@name='address']","凯胜家园小区2号楼2单元802")
#点击报错按钮
page.click("//*[@id='address_submit']")#刷新页面
page.reload()
#删除新增的地址
page.click('//span[text()="ceshi"]/../..//a[text()="删除"]')
#关闭浏览器
browser.close()

如何获取多个元素

比如说获取所有搜索商品的名字
我们可以使用query_selector_all方法

goods = page.query_selector_all('//div[@class="shop-list-splb p"]//div[@class="shop_name2"]')
for good in goods:print(good.text_content().strip())  #strip去除空格

具体代码如下:

from playwright.sync_api import Playwright, sync_playwright, expectplaywright = sync_playwright().start()
browser = playwright.chromium.launch(headless=False,slow_mo=2000)
context = browser.new_context()
page = browser.new_page()
page.goto("http://testingedu.com.cn:8000/Home/user/login.html")
#输入用户名
page.fill('//*[@id="username"]','13800138006')
#输入密码
page.fill('//*[@id="password"]','123456')
#输入验证码,这里做了处理
page.fill('//*[@id="verify_code"]','1111')
#点击登录
page.click('//*[@id="loginform"]/div/div[6]/a')#进入地址管理页面
page.goto("http://testingedu.com.cn:8000/Home/User/address_list.html")#点击搜索框输入内容
page.fill('//input[@class="search_usercenter_text"]','手机')
#点击搜索
page.click('//a[text()="搜索"]')
#query_selector_all方法获取所有元素
goods = page.query_selector_all('//div[@class="shop-list-splb p"]//div[@class="shop_name2"]')
for good in goods:print(good.text_content().strip())  #strip去除空格#关闭浏览器
browser.close()

运行结果之后:
在这里插入图片描述
页面上显示:
在这里插入图片描述
两者相对应。

Playwright元素常用操作

import refrom playwright.sync_api import Playwright, sync_playwright, expectplaywright = sync_playwright().start()
browser = playwright.chromium.launch(headless=False,slow_mo=5000)
context = browser.new_context()
page = browser.new_page()
page.goto("http://testingedu.com.cn:8000/Home/user/login.html")
#输入用户名
page.fill('//*[@id="username"]','13800138006')
#输入密码
page.fill('//*[@id="password"]','123456')
#输入验证码,这里做了处理
page.fill('//*[@id="verify_code"]','1111')
#点击登录
page.click('//*[@id="loginform"]/div/div[6]/a')#进入产品站
page.goto("http://testingedu.com.cn:8000/Home/Goods/goodsInfo/id/55.html")#点击加入购物车
page.click('//*[@id="join_cart"]')
#点击弹层叉号
page.click('//*[@class="layui-layer-ico layui-layer-close layui-layer-close1"]')#鼠标悬停,我的购物车按钮,以及点击去购物车结算
page.hover('//span[text()="我的购物车"]')
page.click('//a[@class="c-btn"]')#点击去结算
page.click('//a[text()="去结算"]')#点击提交订单
page.click('//button[@class="checkout-submit"]')#获取订单号,我们可以使用正则表达式获取
t = page.locator('//p[@class="succ-p"]').text_content()
print(t)
text = re.findall(r'\d{18}',t)[0]
print(text)"""
接下来,我们进入到我的订单页面,点击我的订单的时候,我们发现打开了一个新的网页,在selenium中,是通过切换句柄实现的,而在playwright中,我们可以使用新的写法
"""
print("444")
with context.expect_page() as new_page_info:page.click('a[target="_blank"]')   #点击我的订单
new_page = new_page_info.value
new_page.wait_for_load_state()
print(new_page.title())#点击取消订单,并格式化
new_page.click('//em[text()="{}"]/../..//a[text()="取消订单"]'.format(text))#点击弹层里面的确定按钮
new_page.click('//*[@class="layui-layer-btn layui-layer-btn-"]/a[text()="确定"]')
#刷新页面
new_page.reload()#关闭浏览器
browser.close()

Playwright自动化框架设计

Playwright作为一个新进的自动化特殊工具,在易用性方面做了很多工作。针对Playwright我们甚至可以不用做任何处理,把它当成一个封装好的第三方库去使用即可。
那么整体的框架又该怎么去设计呢?又该考虑哪些问题呢?
如果我们站在公司的角度上来说,公司层面需要打造一个通用性很强的自动化框架。也就是说a项目能用,b项目也能用。另外还需要将测试结果、测试过程等都完整的输出出来,这是基本条件。不然我们花了很多时间写代码,换一个项目就不能用了,几乎需要从头到尾的再写写一遍,那就没有任何意义。而测试人员都是拿结果的,画的结果越详细越好。除此之外,我们也应该考虑到,在一个公司写一个完整的框架和使用框架,不太可能是一个人去完成。我们需要考虑代码托管和持续集成等等问题。所以大体的思路呢便有了。我们也可以根据刚刚的这个思路细化出一个架构图来
我们可以将整体的架构,从上到下可以分成五个层次。一是数据层、服务层、对象层,用例层和输出层。
数据方面,为了拥有一定的适应性,我们可以设计框架,让它支持多种外部数据格式。如说新老版本的excel、yaml等等。
而服务层方面,因为需要针对excel文件的操作,所以需要自己去封装excel读写库等等。
对象层面,我们实际上是借助于PO思想进行设计就可以了。
用例方面主要是考虑用例该如何去组织,该如何去执行。
当然我们选择pytest,在用例执行的过程中,我们是需要进行日志和报告的输出的。所以我们需要封装日志,并且加入allure测试报告。最后我们需要考虑的是,在整个框架的实现过程中,可能某些第三方库有些人没有安装。为了让框架的执行更加简单一点,我们可以直接将整个框架打包到docker里面,这样去执行。就不用担心环境的问题了。框架设计好之后,我们可以打开pycharm,把目录结构呢大体的来设计一下。
我们新建一个工程。新建好之后呢,按照我们刚刚的设计思路,将整体的目录结构呢可以设置成下面这种样子。
首先我们新建一个python package,比如叫做common,在common中,我们要做的事情呢,一般就是把一些公共用的库在这儿。比如excel的读写啊、日志啊等等,
再新建一个package,比如叫做ddt。我们在利用外部文件来执行测试用例的时候呢,实际上就是一个数据驱动。那我们可以把数据驱动的一些执行的逻辑代码放到此处。
再接着我们需要存放文件。比如说我们的测试用例、日志结果等等,我们可以新建一个文件夹,叫做lib。在lib文件下我们可以再新建一个cases,用来存放用例,再新建一个日志的文件夹,log用于存放日志。
最后我们还可以将结果和报告单独的进行设计。result和report。为了运行方便,我们也可以在根目录下创建一个runner。运行入口,我们可以新建一个runner的文件。那么整体的结构呢我们就可以按照这种格式设计完成了
在这里插入图片描述

Playwright自动化框架之excel文件读取

直接上代码吧
在这里插入图片描述
在这里插入图片描述

import osimport openpyxlclass Reader:"""pip install openpyxl读取excel数据文件"""def __init__(self):"""全局变量"""self.workbook = Noneself.sheet = Noneself.rows = 0self.r = 0  #表示当前读取到的行数def open_excel(self, srcfile):"""打开文件:param srcfile::return:"""if not os.path.isfile(srcfile):print("%s not exist" % (srcfile))return#设置读取文件使用编码openpyxl.Workbook.encoding = 'utf-8'self.workbook = openpyxl.load_workbook(filename=srcfile)#默认从第一个sheet文件读取self.sheet = self.workbook[self.workbook.sheetnames[0]]self.rows = self.sheet.max_rowself.r = 0returndef get_sheet(self):"""获取sheet名称:return:"""sheets = self.workbook.sheetnamesreturn sheetsdef set_sheet(self,name):"""切换sheet:param name::return:"""self.sheet = self.workbook[name]self.rows = self.sheet.max_rowself.r = 0returndef readline(self):"""逐行读取文件数据:return:"""lines = []for row in self.sheet.rows:line = []for cell in row:#如果是空行,添加一个空字符串if cell.value is None:line.append('')else:line.append(cell.value)lines.append(line)return lines
import osfrom common.Excel import NewExceldef get_reader(srcfile='') -> NewExcel.Reader:reader = Noneif not os.path.isfile(srcfile):print("%s not exist" % (srcfile))return readerif srcfile.endswith('.xlsx'):reader = NewExcel.Reader()reader.open_excel(srcfile)return reader

好了,先介绍这里吧~后面再更新哈哈


http://www.ppmy.cn/news/62034.html

相关文章

【面试】说说什么是 Java 内存模型(JMM)?

文章目录 一、 为什么要有内存模型?1.1. 硬件内存架构1.2. 缓存一致性问题1.3. 处理器优化和指令重排序 二、并发编程的问题三、Java 内存模型3.1. Java 运行时内存区域与硬件内存的关系3.2. Java 线程与主内存的关系3.3. 线程间通信 四、总结 一、 为什么要有内存模…

go-resiliency源码解析之-timeout

go-resiliency源码解析之-timeout 1.go-resiliency简介 ​ 今天看到项目里用到了go-resiliency这个库,库整体比较简单,代码量不大。主要实现go中几种常见的模式: 后面分析下这几种模式的实现 - circuit-breaker 熔断器 - semaphore …

Vue solt 插槽使用~

一、基本使用&#xff1a; 子组件&#xff1a; 在子组件中使用<slot></slot>给值留下位置&#xff0c; 可以得到父组件的值 <template> <div> <strong>ERROR:</strong> <slot></slot> </div> </template> …

Canal实战使用(集群部署)和原理解析

1.mysql数据同步工作原理 MySQL master将数据变更写入二进制日志(binary log&#xff0c;其中记录叫做二进制日志事件binary log events&#xff0c;可以通过 show binlog events 进行查看) MySQL slave将master的binary log events拷贝到它的中继日志(relay log) MySQL slav…

软考A计划-常用公式复习

点击跳转专栏>Unity3D特效百例点击跳转专栏>案例项目实战源码点击跳转专栏>游戏脚本-辅助自动化点击跳转专栏>Android控件全解手册点击跳转专栏>Scratch编程案例 &#x1f449;关于作者 专注于Android/Unity和各种游戏开发技巧&#xff0c;以及各种资源分享&am…

SQL知识汇总

什么时候用存储过程合适 当一个事务涉及到多个SQL语句时或者涉及到对多个表的操作时就要考虑用存储过程&#xff1b;当在一个事务的完成需要很复杂的商业逻辑时&#xff08;比如&#xff0c;对多个数据的操作&#xff0c;对多个状态的判断更改等&#xff09;要考虑&#xff1b…

Nmap安全工具使用手册

Nmap安全工具使用手册 什么是Nmap&#xff1f; Nmap(Network Mapper) 是一款自由、开源的网络探测和安全审核工具。它适用于Windows、Linux、UNIX等各种操作系统平台&#xff0c;可以帮助管理员或安全研究人员判断目标机器的状态和对应的服务程序&#xff0c;同时也能探查隐蔽…

【Linux网络】网络应用层的 http 和 https协议

文章目录 1、http协议1.1 认识URL1.2 http协议格式1.3 http的方法&#xff08;GET和POST&#xff09;1.4 状态码1.5 cookie1.6 短连接和长连接 2、https协议2.1 常见的加密方式2.2 探究https协议的加密2.3 CA证书 1、http协议 在之前学习序列化和反序列化的时候&#xff0c;认…