参考文件

官方文档: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

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

Playwright之初体验相关推荐

  1. 苹果电脑安装python3密码_mac系统安装Python3初体验

    前沿 对于iOS开发不要随便拆卸系统自带的Python,因为有很多 library 还是使用 Python2.7. 1 安装Xcode 1.1 App Store 搜索Xcode 并安装 1.2 安装 ...

  2. MapReduce编程初体验

    需求:在给定的文本文件中统计输出每一个单词出现的总次数 第一步: 准备一个aaa.txt文本文档 第二步: 在文本文档中随便写入一些测试数据,这里我写入的是 hello,world,hadoop he ...

  3. 小程序 缩放_缩放流星应用程序的初体验

    小程序 缩放 by Elie Steinbock 埃莉·斯坦博克(Elie Steinbock) 缩放流星应用程序的初体验 (First Experiences Scaling a Meteor Ap ...

  4. wxWidgets刚開始学习的人导引(3)——wxWidgets应用程序初体验

    wxWidgets刚開始学习的人导引全文件夹   PDF版及附件下载 1 前言 2 下载.安装wxWidgets 3 wxWidgets应用程序初体验 4 wxWidgets学习资料及利用方法指导 5 ...

  5. 用鸿蒙跑了个 “hello world”!鸿蒙开发初体验

    点击上方蓝色"方志朋",选择"设为星标" 回复"666"获取独家整理的学习资料! 来源 | https://my.oschina.net/u ...

  6. Windows Embedded Standard开发初体验(二)

    支持Silverlight的Windows Embedded Standard 好了,完成安装之后,我们就可以来做Windows Embedded Standard的第一个操作系统镜像了.在开始菜单中 ...

  7. 深度探索Hyperledger技术与应用之超级账本初体验(附部署代码)

    2019独角兽企业重金招聘Python工程师标准>>> 本章零基础地介绍了如何快速体验超级账本搭建的区块链网络,我们先绕过了比较复杂的初始化配置,用官方提供的fabric-sampl ...

  8. Spring环境搭建,IoC容器初体验~

    由于最近的任务是关于IoC配置文件格式的转换,所以需要从Spring的IoC容器开始学起,今天根据网上的介绍搭建了Spring环境,并对其IoC容器进行了初体验.文章中涉及到的软件以及推荐的一本关于S ...

  9. 来自新手Banana Pi香蕉派初体验

    2019独角兽企业重金招聘Python工程师标准>>> 一.前言 一段时间来对有强大的技术支持和完善的社区的Raspberry Pi很感兴趣,本想入一片学习学习,但转念一想Raspb ...

最新文章

  1. 图像配准----NCC
  2. T-SQL | 你需要了解的执行计划
  3. C#规范整理·异常与自定义异常
  4. 有关Accordion组件的研究——Silverlight学习笔记[27]
  5. 混凝土地坪机器人_地面整平机器人:精准又高效,轻松摆“平”混凝土
  6. python脚本去除文件名里的空格
  7. 随想录(easyx中的键盘输入和鼠标消息)
  8. OPENGL中的glViewport
  9. 此次边路调整系统推荐射手走哪路_王者荣耀:廉颇“史诗级”改动,成吉思汗等射手降温!...
  10. mysql 将select结果导出文件 linux
  11. OpenCV:旋转矩形(RotatedRect)
  12. 免费使用QQ邮箱“邮件短信通知”服务
  13. ipvs 导致syn 重传问题
  14. 关于对象的construct与destruct
  15. C中的 feof() 和 EOF
  16. Auto-Tuning with Reinforcement Learning for Permissioned Blockchain Systems
  17. 如何使用Delphi 10 Seattle的Android应用做Intent的发送和接收
  18. 华为 ACL与DHCP配置
  19. html里怎么计算梯形周长公式是什么,梯形的周长公式是什么
  20. nat123 登陆时提示【连接服务器失败】

热门文章

  1. 领英辅助工具领英精灵的下载安装的细节和方法
  2. (Django)Web网页导入pycharm时遇到的问题集合(备份)
  3. 各向异性渲染(一)基础理论
  4. C/C++指针的经典笔试面试题
  5. Kernel panic - not syncing: Attempted to kill init
  6. java 通用工具 POI XSSF导出.xls或者.xlsx
  7. nfs共享存储web项目集群的一次下载流为空FIleChannel空洞bug
  8. K3s - 安装部署
  9. 完整的境外、港澳台、电信、移动、联通、教育网、国内其他ISP的IPv4列表(数据整理日期2022年4月)-IP列表太长只能份2篇发布(1/2)
  10. vue移动端pdf在线预览,并实现手势缩放、移动