【Python】高效的Web自动化测试利器—Python+Playwright快速上手自动化实战指南(限时开放)

文章目录

  • 前言
  • 一.playwright是什么
  • 二.python引入playwright
    • 1.安装
    • 2.playwright命令行参数
    • 3.playwright codegen自动生成代码
    • 4.Chrome和Chromium有什么关系?
  • 三.基本概念
    • 1. 无头浏览器(Headless Browser)
    • 2.同步和异步模式操作playwright
      • 2.1.同步(Sync)模式
        • 同步方式代码模板
      • 2.2.异步(Async)模式
        • 异步方式代码模板
    • 3.Browser(浏览器驱动)
    • 4.Context(浏览器上下文)
    • 5.Page页面(浏览器标签页)
  • 四.页面元素定位
    • 1.locator选择器
      • 1.文本选择器
      • 2.css选择器和Xpath 定位
      • 3.组合定位:text、css、xpath三者可以两组合定位
    • 2.playwright推荐的内置定位——get_by
    • 3.html5的role属性与get_by_role
  • 五.浏览器操作
    • 1.Text input文本输入
    • 2.Checkboxes and radio buttons 单选和多选
    • 3.Select options下拉选择
    • 4.Click鼠标单击和双击
    • 5.Press按下指定的键
    • 6.Focus聚焦
    • 7.Darg and Drop拖拉
    • 8.鼠标移动到指定的locator上
    • 9.运行JS脚本
    • 10.文件上传
    • 11.页面事件监听
    • 12.获取元素文本
  • 六.断言
  • 七.浏览器常见配置
    • 1.截图
      • 1.1. 截图整个页面
      • 1.2. 截取整个页面并裁剪
      • 2. 设置窗口(Viewport)大小
      • 4.截取特定元素并调整大小
      • 5. 捕获截图为字节流
    • 2.自定义Header
    • 3.自定义UserAgent
    • 4.设置浏览器代理
      • 1. 启动时设置全局代理
      • 2. 上下文设置代理
    • 5.自动等待机制
      • 1.自动等待和##可操作性校验(Auto-waiting)
      • 2.显式等待API(Explicit Waiting)
      • 3.全局设置等待超时时间
    • 6.处理新的窗口、弹窗,iframe
    • 7.支持Pytest框架
    • 8.移动端浏览器支持
  • 八.playwright如何绕过反爬虫检测
    • 1 防止webdriver属性被检测
    • 2 headless=True无头浏览器如何绕过反爬虫
    • 3.stealth.min.js作用
    • 4.防止爬虫检测的方式
  • 九.通过CDP(Chrome DevTools Protocol)连接现有浏览器
    • 1.CDP(Chrome DevTools Protocol)和WDP (WebDriver Protocol)协议
    • 2.WebDriver Protocol
    • 3.Chrome DevTools Protocol
    • 4.WebDriver Protocol和Chrome DevTools Protocol对比
  • 十.拓展知识
    • 屏幕坐标系,世界坐标系
  • 十一.Playwright 和 Selenium 的区别

前言

本教程旨在引导读者从零开始,逐步掌握使用Python和Playwright进行Web自动化测试的技能。无论你是初涉自动化测试的开发者,还是希望提升现有测试框架效能的资深测试工程师,本教程都将为你提供丰富的实战案例、详细的步骤解析以及最佳实践分享。

一.playwright是什么

:Python+Playwright自动化测试实战指南"
“解锁Web自动化新纪元:Python与Playwright的强强联合教程”
“Python+Playwright:构建高效、稳定的Web自动化测试框架”
“自动化测试不再难!Python结合Playwright快速上手教程”

Playwright是微软在2020 年初开源自动化测试工具,功能和 selenium 类似,都可以驱动浏览器进行各种自动化操作。

  • 支持主流浏览器,如Chrome、Firefox、Safari 等,同时支持以无头模式、有头模式运行,并提供了同步、异步的 API,可以结合 主流测试框架使用,并且支持浏览器端的自动化脚本录制等功能。

特点:

  • 跨浏览器:Playwright 支持所有现代渲染引擎,包括Chromium、WebKit 和 Firefox;
  • 跨平台:在 Windows、Linux 和 MacOS 上进行本地或 CI、无头或有头测试;
  • 跨语言:在 TypeScript、JavaScript、Python、.NET、Java 中使用Playwright API;
  • 测试移动网络:适用于 Android 和 Mobile Safari 的 Google Chrome 原生移动仿真。相同的渲染引擎适用于您的桌面和云端。
  • 官网:https://playwright.dev/
    官方文档
    • github项目地址:https://github.com/microsoft/playwright-python
    • Python文档
    • PythonAPI文档

其他鼎鼎大名的selenium、Pyppeteer、DrissionPage等

推荐原因:

  1. 运行 playwright codegen命令 可自动自动生成代码,降低编写爬虫代码的门槛和难度,不用自己逐个去分析页面代码结构
  2. playwright微软是从2020年开始创建的项目,更新稳定且频率不低,可长期使用一个库或框架
  3. 代码结构清晰,功能齐全,门槛低
  4. 支持多个语言版本:python、Node.js、Java、.net,原生支持同步异步两种方式**
  5. 自动等待 pw在做某个操作之前需要有一个前提条件成立才进行,系统会自动等待检查通过,直到超时
    比如我要系统自动点击某个元素,那么playwright会自动:
    1. 等待指定选择器的元素出现在 DOM 中 (不用自己去写轮询等待了)
    2. 等待它显示出来,即不为空,不为display:none,不为visibility:hidden (这个太人性化了,不用去判断元素是否隐藏)
    3. 等待它停止移动,例如,直到 css 转换完成
    4. 将元素滚动到视图中 (这个太人性化了,不用自己去滚动了)
    5. 等待它在动作点接收指针事件,例如,等待直到元素变得不被其他元素遮挡
    如果元素检测到上述任何场景,则重试

二.python引入playwright

1.安装

  1. 安装 playwright-python 依赖库 (需要注意的是,playwright库需要依赖 Python3.7+以上)

    • 可在https://pypi.org/project/playwright/查看它的依赖版本信息。
    pip install playwright
    
    • 官网推荐pip install pytest-playwright来安装,但没必要,会安装playwright及其他一堆测试所用的库,如果只是使用playwright,那么就没必要这样去安装。
  2. 自动下载使用的浏览器

    playwright install
    
    • 执行命令以后,会自动下载chromium、firefox以及webkit三种浏览器,存放文件夹路径为(windows环境):

      c:\Users\YOURUSERNAME\AppData\Local\ms-playwright\
      
      • 以上三种浏览器分别对应三种不同内核的浏览器,在爬虫过程中可以自定义选择任意一种浏览器

2.playwright命令行参数

想查看Playwright支持的功能, 可在命令行输入:

playwright help
Usage: index [options] [command]Options:-V, --version                          output the version number-b, --browser <browserType>            browser to use, one of cr, chromium, ff, firefox, wk,webkit (default: "chromium")--color-scheme <scheme>                emulate preferred color scheme, "light" or "dark"--device <deviceName>                  emulate device, for example  "iPhone 11"--geolocation <coordinates>            specify geolocation coordinates, for example"37.819722,-122.478611"--lang <language>                      specify language / locale, for example "en-GB"#设置代理--proxy-server <proxy>                 specify proxy server, for example "http://myproxy:3128" or"socks5://myproxy:8080"--timezone <time zone>                 time zone to emulate, for example "Europe/Rome"--timeout <timeout>                    timeout for Playwright actions in milliseconds (default:"10000")#设置user-agent--user-agent <ua string>               specify user agent string#设置浏览器打开窗口的大小--viewport-size <size>                 specify browser viewport size in pixels, for example "1280,  720"-h, --help                             display help for commandCommands:open [url]                             open page in browser specified via -b, --browsercr [url]                               open page in Chromiumff [url]                               open page in Firefoxwk [url]                               open page in WebKitcodegen [options] [url]                open page and generate code for user actionsscreenshot [options] <url> <filename>  capture a page screenshotpdf [options] <url> <filename>         save page as pdfinstall                                Ensure browsers necessary for this version of Playwrightare installedhelp [command]                         display help for command

3.playwright codegen自动生成代码

在命令行输入下面代码会自动弹出一个浏览器和一个代码编辑器 在该浏览器上每一步操作都会自动生成到代码编辑器上,可复制使用

playwright codegen https://www.baidu.com/ -o script.py

查看录制脚本的命令说明

playwright codegen --help
Usage: index codegen [options] [url]open page and generate code for user actionsOptions:#生成自动化脚本路径-o, --output <file name>  saves the generated script to a file# –target 脚本语言,包含 JS 和 Python,分别对应值为:python 和 javascript--target <language>       language to use, one of javascript, python, python-async, csharp (default: "python")#帮助文档-h, --help                display help for commandExamples:$ codegen$ codegen --target=python#指定浏览器驱动$ -b webkit codegen https://example.com
  1. 如要在baidu.com搜索,用chromium驱动,将结果保存为mikezhou.py的python文件。

    playwright codegen --target python -o 'mikezhou.py' -b chromium https://www.baidu.com
    

    命令行输入后会自动打开浏览器,然后可以看见在浏览器上的一举一动都会被自动翻译成代码,如下所示:
    在这里插入图片描述
    最后,自动化脚本会自动生成,保存到文件中mikezhou.py, 且上述所有的人工操作,都会被自动转化成代码:

from playwright import sync_playwrightdef run(playwright):browser = playwright.chromium.launch(headless=False)context = browser.newContext()# Open new pagepage = context.newPage()# Go to https://www.baidu.com/page.goto("https://www.baidu.com/")# Click input[name="wd"]page.click("input[name=\"wd\"]")# Fill input[name="wd"]page.fill("input[name=\"wd\"]", "禾目大")# Press CapsLockpage.press("input[name=\"wd\"]", "CapsLock")# Fill input[name="wd"]page.fill("input[name=\"wd\"]", "自动化测试实战宝典 ")# Press Enterpage.press("input[name=\"wd\"]", "Enter")# assert page.url() == "https://www.baidu.com/s?ie=utf-8&f=8&rsv_bp=1&rsv_idx=1&tn=baidu&wd=%E8%87%AA%E5%8A%A8%E5%8C%96%E6%B5%8B%E8%AF%95%E5%AE%9E%E6%88%98%E5%AE%9D%E5%85%B8%20&fenlei=256&rsv_pq=af40e9aa00012d5a&rsv_t=c659gpz2%2Fjri1SAoIXdT9gP%2BmrqufXzRtMSSAL0n0fv7GSoLF5vaiNVPA3U&rqlang=cn&rsv_enter=1&rsv_dl=tb&rsv_sug3=38&rsv_sug1=22&rsv_sug7=100&rsv_sug2=0&rsv_btype=i&inputT=8034&rsv_sug4=9153"# Close pagepage.close()# ---------------------context.close()browser.close()with sync_playwright() as playwright:run(playwright)

4.Chrome和Chromium有什么关系?

可看做同一个项目下的两个分支,chromium是测试开源版,所有的功能都会先在其身上测试,确定稳定运行后再移植到chrome上,而chrome是Google正式商业版浏览器,两者由Google官方和chromium社区进行维护

三.基本概念

在这里插入图片描述

1. 无头浏览器(Headless Browser)

HeadlessBrowser 俗称的无头浏览器, 实际上就是没有图形界面的浏览器, 因为省去了视觉渲染的工作, 性能和开销有较大优化, 粗略估计, 原本只能启动十个浏览器的内存, 使用 Headless 模式可以至少启动三倍的数量

无头浏览器应用场景

  • 无浏览器 UI,运行速度较快,常用于自动化运行
  • 有浏览器 UI,常用于调试代码

Playwright 支持以无头模式(Headless Browser )执行自动化测试,这样就不会实际打开可见的浏览器窗口。无头模式对于持续集成(CI)、后台执行测试或在没有图形界面的服务器环境中运行测试非常有用

在使用Playwright的无头浏览器模式(‌headless=True)‌时遇到找不到元素的问题**

  1. 可能是网站反爬虫机制或User-agent参数问题导致的。‌

    • 常见的反爬虫手段是通过检测当前user-agent是否为真实浏览器来区分当前请求是否来自真实用户。爬虫使用的常见user-agent类型为:
      • user-agent为空。没有设置user-agent。
      • user-agent中包含特殊字符。如:python,java,bot,spider,headless等。

而使用Playwright的Chrome无头浏览器访问网站时,user-agent中会自动添加Headless字段。当网站检测到user-agent包含Headless时判定为非真实请求时,可能会返回空页面,所以导致无头浏览器找不到元素。

  • 用浏览器到https://www.useragentstring.com/index.php 查看当前浏览器使用的User Agent String,在Playwright配置中设置自定义的User-agent
    #通过args设置
    browser = playwright.chromium.launch(headless=True, args=['--user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36'])
    #通过上下文设置
    context = browser.new_context(no_viewport=True,user_agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36")
    

2.同步和异步模式操作playwright

2.1.同步(Sync)模式

在同步模式下,代码按照从上到下的顺序执行。每个操作都会阻塞直到完成,然后再执行下一行代码。这意味着在等待某个操作(如页面加载)完成之前,程序不会继续往下执行。

  • 关键字:sync_playwright
  • 对于初学者或习惯于同步编程模型的开发者来说,同步模式可能更加直观和易于理解,因为它遵循了传统的线性编程逻辑。
# 导入Playwright类和sync_palywright 同步类
from playwright.sync_api import sync_playwright# -------------------------写法1
with sync_playwright() as playwright:browser = playwright.chromium.launch(headless=False)  # 启动 chromium 浏览器context = browser.new_context()  # 打开一个上下文page = context.new_page()  # 打开一个标签页page.goto("https://www.baidu.com")  # 打开百度地址print(page.title())  # 打印当前页面titlecontext.close()browser.close()  # 关闭浏览器对象# -------------------------写法2
# 如果不习惯with语句,也可以用start() 和stop() 的方式:
def main(playwright):browser = playwright.chromium.launch(headless=False)context = browser.new_context()page = context.new_page()page.goto("https://www.baidu.com/")print(page.title())context.close()browser.close()with sync_playwright() as playwright:main(playwright)
同步方式代码模板
from playwright.sync_api import Playwright, sync_playwright, expectdef main(playwright: Playwright) -> None:"""这是一个名为main的函数定义,它接受一个名为playwright的参数,该参数被类型注解为Playwright(这表明playwright应该是一个Playwright实例,但注意Python本身不强制类型注解,这是为了代码可读性和工具支持)。函数没有返回值(-> None表示返回类型为None)。"""browser = playwright.chromium.launch(headless=False)context = browser.new_context()page = context.new_page()###################这里将是操作页面的代码块###################**完整的playwright流程**#1. 创建browser(浏览器实例)#2. 创建context(共cookie、session)#3. 创建page(具体选项卡页面),然后用页面去模拟操作#4. 完成所有的操作后关闭之前创建的三种对象。pass#############################################################    page.close()context.close()browser.close()with sync_playwright() as playwright:main(playwright)

2.2.异步(Async)模式

异步模式利用Python的asyncio库允许非阻塞的并发操作。可以在等待某个耗时操作(如网络请求)的同时,程序可以继续执行其他任务。你需要使用await关键字来等待异步操作的结果

  • 关键字为:async_playwright,异步操作可结合asyncio同时进行三个浏览器操作。

  • 效率: 异步模式能显著提高脚本的执行效率,特别是在进行大量网络请求或需要同时管理多个页面/浏览器实例的场景下。因为它能够更好地利用系统资源,减少闲置时间。

    • 比我想爬取300章小说,如果用单线程去爬,那么时间是线性的,爬取每一章节所使用的时间积累起来就是最终所用的总时间;如果用多线程,比如说同时用10个线程去爬,那么理论上总时间就是单线程所用时间的1/10
      相反,如果我只是想获取某一个页面的内容,那么直接单线程就完事
  • 复杂度: 相比同步模式,异步编程模型引入了额外的概念,如协程(coroutine)、事件循环(event loop)等,这可能会增加代码的复杂度,尤其是对于不熟悉异步编程的开发者而言。

import asyncio
from playwright.async_api import Playwright, async_playwright# 写法1
with async_playwright() as playwright:browser = await  playwright.chromium.launch(headless=False)  # 启动 chromium 浏览器context = await  browser.new_context()  # 打开一个上下文page = await context.new_page()  # 打开一个标签页await  page.goto("https://www.baidu.com")  # 打开百度地址print(await  page.title())  # 打印当前页面titleawait context.close()await browser.close()# 写法2 如果不习惯with语句,也可以用start() 和stop() 的方式:
async def main():async with async_playwright() as playwright:browser = await playwright.chromium.launch(headless=False)context = await browser.new_context()page = await context.new_page()await page.goto("https://www.baidu.com/")print(await page.title())await context.close()await browser.close()
asyncio.run(main())

例如:

import asyncio
from playwright import async_playwright# 异步执行
async def main():async with async_playwright() as p:for browser_type in [p.chromium, p.firefox, p.webkit]:# 指定为有头模式,方便查看browser = await browser_type.launch(headless=False)page = await browser.new_page()await page.goto('http://baidu.com')# 执行一次搜索操作await page.fill("input[name=\"wd\"]", "自动化测试实战宝典")await page.press("input[name=\"wd\"]", "Enter")# 等待页面加载完全await page.wait_for_selector("text=搜索工具")# 截图await page.screenshot(path=f'test-{browser_type.name}.png')await browser.close()asyncio.get_event_loop().run_until_complete(main())
异步方式代码模板
import asyncio
from playwright.async_api import Playwright, async_playwright, expectasync def run(playwright: Playwright) -> None:browser = await playwright.chromium.launch(headless=False)context = await browser.new_context()page = await context.new_page()#########################操作页面的代码块##############**完整的playwright流程**#1. 创建browser(浏览器实例)#2. 创建context(共cookie、session)#3. 创建page(具体选项卡页面),然后用页面去模拟操作#4. 完成所有的操作后关闭之前创建的三种对象。pass####################################################await page.close()await context.close()await browser.close()async def main() -> None:async with async_playwright() as playwright:await run(playwright)asyncio.run(main())

3.Browser(浏览器驱动)

  • 对应一个浏览器实例(Chromium、Firefox或WebKit) 支持多种浏览器:Chromium(chrome、edge)、Firefox、WebKit(Safari),一般每一种浏览器只需要创建一个 browser 实例。示例:
#launch()方法是Playwright中用于启动浏览器的函数。它接受一个可选参数,该参数可以是一个字典,用于配置浏览器的选项。
#1.创建浏览器:(这里创建的是谷歌浏览器)
browser = playwright.chromium.launch(headless=False) # headless=False 是有头模式,也就是代码运行时候,需要浏览器页面
#(创建的是火狐浏览器)
browser = playwright.firefox.launch()#关闭浏览器
browser.close()

browser对象常用配置项

1.是否无头模式(即是否隐藏浏览器界面): headless = False # 显示界面,为True时隐藏界面2.打开时最大化窗口:args = ['--start-maximized'] # 还要配合context中设置 no_viewport = True3.网络代理:
proxy = {
"server": "http://127.0.0.1:8080", # 代理服务器的地址
"bypass": "*.http://bing.com", # 不使用代理的域名
"username": "Mike", # 代理服务器的用户名
"password": "123456" # 代理服务器的密码
}4.指定下载保存路径:downloads_path = r"d:\"5.viewport: 字典,用于指定浏览器窗口的大小和位置。例如:{'width': 800, 'height': 600}6.slow_mo: 浮点数,默认为0。如果设置为大于0的值,则会增加浏览器操作的延迟时间(单位为毫秒)。
7.ignore_https_errors: 默认为False。如果设置为True,则在访问HTTPS网站时不会检查证书错误。
8.args: 列表,用于传递给浏览器进程的命令行参数。例如:['--disable-gpu']

4.Context(浏览器上下文)

一个浏览器实例下可以有多个context,将浏览器分割成不同的上下文,以实现会话的隔离,如需要不同用户登录同一个网页,不需要创建多个浏览器实例,只需要创建多个context即可

  • 可以理解为轻量级的浏览器实例.如需要不同用户登录同一个网页,不需要创建多个浏览器实例,只需要创建多个context即可。

浏览器上下文,相当于一个全新的浏览器配置文件,提供了完全的测试隔离,并且零开销。创建一个新的浏览器上下文只需要几毫秒,每个上下文都有自己的Cookie、浏览器存储和浏览历史记录。浏览器上下文允许同时打开多个页面并与之交互,每个页面都有自己单独的状态,一个 BrowserContext 可以包含多个 Page

#new_context()方法是Playwright库中用于创建一个新的浏览器上下文的函数。它接受一个可选参数,该参数可以是一个字典,用于配置浏览器上下文的选项
#1.创建浏览器上下文
context = browser.new_context()
#2.关闭
context.close()

Context相关常用配置项

1.no_viewport=True:最大化窗口(与browser的args联合使用) 
2.java_script_enabled=False:  禁用javascript:
3.viewport: 字典,用于指定浏览器窗口的大小和位置。例如:{'width': 800, 'height': 600}4.忽略https错误: ignore_https_errors=True
5.user_agent: 字符串,默认为当前浏览器的用户代理字符串。如果设置为其他值,则会使用指定的用户代理字符串。
6.accept_downloads: 布尔值,默认为False。如果设置为True,则会在下载文件时自动接受下载对话框。
7.record_har: 字典,用于录制HTTP请求和响应数据。例如:{'path': '/tmp/har.har'}8.其他配置
device_scale_factor: 浮点数,指定设备缩放比例,例如 1.5。如果不指定,则使用默认的设备缩放比例。
is_mobile: 布尔值,指定是否模拟移动设备,默认为 False。
has_touch: 布尔值,指定是否支持触摸事件,默认为 False。
bypass_csp: 布尔值,指定是否绕过内容安全策略,默认为 False。
locale: 字符串,指定浏览器的语言和地区,例如 “en-US” 或 “zh-CN”。如果不指定,则使用默认的语言和地区。
timezone_id: 字符串,指定浏览器的时区,例如 “Asia/Shanghai” 或 “America/New_York”。如果不指定,则使用默认的时区。
geolocation: 字典,指定浏览器的地理位置,包括 latitude(纬度),longitude(经度)和 accuracy(精度),例如 {“latitude”: 31.2304, “longitude”: 121.4737, “accuracy”: 10}。如果不指定,则使用默认的地理位置。
permissions: 列表,指定浏览器的权限,例如 [“geolocation”, “notifications”, “camera”]。如果不指定,则使用默认的权限。
extra_http_headers: 字典,指定浏览器的额外 HTTP 头部,例如 {“x-foo”: “bar”}。如果不指定,则使用默认的 HTTP 头部。
offline: 布尔值,指定是否模拟离线状态,默认为 False。
http_credentials: 字典,指定浏览器的 HTTP 认证,包括 username(用户名)和 password(密码),例如 {“username”: “admin”, “password”:123456}。如果不指定,则使用默认的 HTTP 认证。
color_scheme: 字符串,指定浏览器的配色方案,可以是 “dark” 或 “light”。如果不指定,则使用默认的配色方案。
record_video: 字典,指定是否录制浏览器的视频,包括 dir(视频保存的目录)和 size(视频的宽度和高度),例如 {“dir”: “videos/, “size”: {“width”: 800, “height”: 600}}。如果不指定,则不录制视频。
proxy: 字典,指定代理设置,包括 server(代理服务器地址),bypass(要绕过代理的域名列表),username(代理用户名),password(代理密码)

context常用方法

context.pages :获取context所有page对象
context.new_page():生成一个新的page对象
context.close():关闭context
context.add_cookies():将cookie添加到此浏览器上下文中。此上下文中的所有页面都将安装这些cookie。只能传入列表  List[{name: str, value: str, url: Union[str, None], domain: Union[str, None], path: Union[str, None], expires: Union[float, None]context.clear_cookies():清除context的cookie
context.grant_permissions():授予浏览器上下文的指定权限,具体见api
context.clear_permissions():清除授权

5.Page页面(浏览器标签页)

一个context下可以有多个page,一个page就代表一个浏览器的标签页或弹出窗口,用于进行页面操作。这个也是我们主要操作的对象。后续打开网页 、定位元素、页面操作都是基于page

#1.创建一个新的浏览器页面
page = context.new_page()
#2.打开一个网页
page.page.goto(url , **kwargs)#默认是在当前tab打开 page.goto(url)    如果你想要在同一个上下文中打开多个页面,重新创建page即可# url就是网址,需要包含访问协议,比如https://www.bing.com# **kwargs包括:# timeout = 10000  # 可选项,单位ms,超时时间,默认30秒,设为0则永不超时# wait_until = 'load'  # 可选项,等待页面状态符合指定值,默认为load,具体解释参加下方内容
#3.关闭
page.close()#4.获取当前页面的URL
page.url
#5.在页面上执行JavaScript代码
page.evaluate('() => document.title')
#6.截取页面的屏幕截图
page.screenshot(path='screenshot.png')
async def new_page(self,viewport: ViewportSize = None,#为每个页面设置一致的窗口。默认为1280x720窗口screen: ViewportSize = None, # 通过“window.screen”模拟网页内可用的一致窗口屏幕大小 ,只能在viewport设置之后使用  noViewport: bool = None,# 不强制固定窗口,允许在标题模式下调整窗口大小ignoreHTTPSErrors: bool = None,javaScriptEnabled: bool = None, #禁用 javaScriptbypassCSP: bool = None,userAgent: str = None, # 设置代理用于上下文locale: str = None, #指定用户区域,设置将影响Accept-Language'请求标头值以及数字和日期格式规则timezoneId: str = None, #设置时区geolocation: Geolocation = None,permissions: List[str] = None,extraHTTPHeaders: Dict[str, str] = None,offline: bool = None,httpCredentials: HttpCredentials = None,deviceScaleFactor: float = None,isMobile: bool = None, #设备相关,不用管hasTouch: bool = None,colorScheme: ColorScheme = None, #Union["dark", "light", "no-preference", "null", None]#设置颜色主题forcedColors: ForcedColors = None, #Union["active", "none", "null", None]reducedMotion: ReducedMotion = None,acceptDownloads: bool = None,defaultBrowserType: str = None,proxy: ProxySettings = None, #设置代理recordHarPath: Union[Path, str] = None,recordHarOmitContent: bool = None,recordVideoDir: Union[Path, str] = None,recordVideoSize: ViewportSize = None,storageState: Union[StorageState, str, Path] = None,baseURL: str = None,strictSelectors: bool = None,serviceWorkers: ServiceWorkersPolicy = None,recordHarUrlFilter: Union[Pattern[str], str] = None,recordHarMode: HarMode = None,recordHarContent: HarContentPolicy = None,
) -> Page:

四.页面元素定位

1.locator选择器

locator()方法支持所有的CSS选择器`,包括:

  • 基本选择器:如 div, span, .my-class, #my-id 等。
  • 属性选择器:如 [href], [class=“my-class”], [data-my-attr=“value”] 等。
  • 伪类选择器:如 :hover, :focus, :first-child, :last-of-type 等。
  • 结合选择器:如 div.my-class, div, span, div > p, div + p 等。
  1. 操作元素有两种方式

    1. 先定位元素再操作元素
    # 先定位再操作
    page.locator('#kw').fill("上海悠悠")
    page.locator('#su').click()
    
    1. 直接在操作元素的时候定位元素
      如:调用fill 和 click 方法,传入Selector选择器**
    page.fill('#kw', "欧阳博客")
    page.click('#su')
    
  2. locator()方法可以根据元素的CSS选择器来查找。您可以使用各种CSS选择器,包括但不限于:

    标签名:例如 page.locator('button')
    类名:例如 page.locator('.my-class')
    ID:例如 page.locator('#my-id')
    属性:例如 page.locator('[data-testid="my-test-id"]')
    文本内容:例如 page.locator(':text("My Text")')
    
    • 使用 locator 定位元素,不管元素存不存在,都会返回一个locator 对象,可以用到count() 方法统计元素的个数,如果元素个数是 0, 那么元素就不存在
    • locator 是定位当前页面上的元素,不会自动等待,如果用click等方法结合使用,会自动去等待元素处于可点击状态。

1.文本选择器

文本选择器是一个非常实用的定位方式,根据页面上看到的text文本就可以定位了 playwright 封装了text文本定位的方式,也可以支持2种文本定位方式

  • page.click('text=登录') 没有加引号(单引号或者双引号),模糊匹配,对大小写不敏感
  • page.click('text="登录"') 有引号,精确匹配,对大小写敏感
	has_text()查找子代或后代所有包含对应文本的,相反的也有has_not_text()text()查找第一个文本等于...的元素has_text:筛选包含指定文本的元素,匹配元素内或子元素中的文本内容。has_not_text:筛选不包含指定文本的元素。比如:<article><div >Playwright</div></article>.page.locator(':has_text("Playwright")').click()
# 也可以这样写,指定标签
page.locator('article:has_text("Playwright")').click()
# 也可以这样
page.locator(":text('Playwright')").click()
# 还可以这样
page.locator('article:has'text=Playwright').click()

2.css选择器和Xpath 定位

page.locator('css=button').click() # 根据标签
page.locator('css=#nav-bar .contact-us-item').click() # 通过id +class
page.locator('css=[data-test=login-button]').click() # 属性定位
page.locator("css=[aria-label='Sign in']").click()page.locator(xpath="//div[@id='myId']").click()
#不需要前面的前缀css= 和 xpath=, 它会自动判断你写的是css还是xpath语法,前提是你语法没有错误。

3.组合定位:text、css、xpath三者可以两组合定位

  1. css+text组合定位

    page.locator("article:has-text('Playwright')").click()
    page.locator("#nav-bar :text('Contact us')").click()
    
  2. css+css组合定位

    page.locator(".item-description:has(.item-promo-banner)").click()
    
  3. Xpath + css 组合定位

    page.fill('//div[@class="SignFlow-account"] >>css=[name="username"]',"0863")
    
  4. xpath+xpath组合定位

    page.fill('//div[@class="SignFlowInput"] >> //input[@name="password"]',"ma160065")
    
  5. 利用HTML元素的属性来定位,比如ID、name或其他自定义属性。

    page.locator("[data-testid='my-element']")
    
  6. 组合定位: 在复杂场景下,你可能需要结合多个条件来定位元素,Playwright 支持链式调用来实现这一需求。

    page.locator("div.container").locator("input[type='text']")
    

2.playwright推荐的内置定位——get_by

get_by_role: 根据元素在页面中扮演的角色(如按钮、链接、输入框等)进行定位 例如:page.get_by_role("button", name="Submit")
get_by_text: 通过使用文本内容来定位元素,适合于元素没有唯一标识符的情况。例如:page.get_by_text("Submit")
get_by_label: 根据label属性值查找元素,类似于HTML中的label标签和对应的for属性。get_by_id: 通过元素的 id 属性来查找元素,例如:page.get_by_id("my-id")
get_by_name: 通过元素的 name 属性来查找元素,例如:page.get_by_name("my-name")get_by_title: 通过元素的 title 属性来查找元素,例如:page.get_by_title("my-title")
get_by_placeholder: 通过元素的 placeholder 属性来查找元素,例如:page.get_by_placeholder("my-placeholder")
get_by_selector: 通过 CSS 选择器来查找元素,例如:page.get_by_selector("#submit-button")
get_by_xpath: 通过 XPath 表达式来查找元素,例如:page.get_by_xpath("//div[@class='my-class']")

3.html5的role属性与get_by_role

html5总能role的作用是 是增强html语义性,当现有的html标签不能充分表达语义性的时候,就可以借助role来说明。

  • 通常这种情况出现在一些自定义的组件上,这样可增强组件的可访问性、可用性和可交互性。

  • role的作用是描述一个非标准的tag的实际作用。比如用div做button,那么设置div 的 role=“button”,辅助工具就可以认出这实际上是个button

  • 元素的role属性参考https://www.w3.org/TR/2014/REC-wai-aria-implementation-20140320/#mapping_role_tablehttp://

常用role属性

1. button :表示一个按钮,用于触发某个操作。
2. link :表示一个链接,通常用于导航目的。
3. heading:表示一个标题,标识文档结构。
4.  textbox :表示一个文本框,用户可以在其中输入文本。
5. checkbox:表示一个复选框,用户可以选择或取消选择。
6. radiobutton :表示一个单选按钮,用户可以从一组选项中选择一个。
7. menu :表示一个菜单,用户可以从中选择一个选项。
8. list :表示一个列表,可以是有序或无序的。
9. progressbar :表示一个进度条,用于表示任务的进度。
10. dialog :表示一个对话框,用户可以与之交互。

在这里插入图片描述

get_by_role

#元素:<li class="el-menu-item" role="menuitem" tabindex="-1">队列管理</li>
page.get_by_role("menuitem", name="队列管理").click()#元素:<button class="el-button el-button--primary el-button--default mr-24px mb-12px" aria-disabled="false" type="button"><span>新增队列</span></button>
page.get_by_role("button", name="新增队列").click()

五.浏览器操作

比如:输入文本、单选、多选、选择下拉框、点击按钮/文本、按下某个按键、上传文件、元素对应焦点、鼠标的拖拽、执行JS脚本等等。

1.Text input文本输入

对应的是input、textarea、contenteditable等元素

locator = page.get_by_label("Password")
locator.fill("mypassword")   # 输入一段文字
locator.fill("type")#一个字符一个字符地输入字段

2.Checkboxes and radio buttons 单选和多选

locator = page.get_by_label('I agree to the terms above')
locator.check()

3.Select options下拉选择

locator = page.get_by_label('Choose a color')
locator.select_option('blue')

4.Click鼠标单击和双击

# 点击
page.get_by_role("button").click()# 双击
page.get_by_text("Item").dblclick()# 右击
page.get_by_text("Item").click(button="right")# Shift + 点击
page.get_by_text("Item").click(modifiers=["Shift"])# 鼠标悬停在元素上
page.get_by_text("Item").hover()# 点击左上角
page.get_by_text("Item").click(position={ "x": 0, "y": 0})

5.Press按下指定的键

# 按Enter键
page.get_by_text("Submit").press("Enter")  # locator上按回车键# 按ctrl + 右方向键
page.get_by_role("textbox").press("Control+ArrowRight")  # ctrl + 右方向键# 按键盘上的$符合
page.get_by_role("textbox").press("$")  # 按下$

上述特殊按键有:

Backquote, Minus, Equal, Backslash, Backspace, Tab, Delete, Escape,
ArrowDown, End, Enter, Home, Insert, PageDown, PageUp, ArrowRight,
ArrowUp, F1 - F12, Digit0 - Digit9, KeyA - KeyZ

可以组合按下指定的键

# <input id=name>
page.locator('#name').press('Shift+A')  # id为name的元素中按下shift + A# <input id=name>
page.locator('#name').press('Shift+ArrowLeft')

6.Focus聚焦

page.get_by_label('password').focus()

7.Darg and Drop拖拉

效果是先将鼠标移动要操作的locator上,然后按住左键,移动鼠标到目标locator所在位置,松开鼠标

page.locator("#item-to-be-dragged").drag_to(page.locator("#item-to-drop-at"))
# 将一个locator拖到另一个locator上

8.鼠标移动到指定的locator上

这在处理一些隐藏菜单很有效,鼠标放到菜单上后,菜单显示,然后就可以操作

page.locator("#item-to-be-dragged").hover()
page.mouse.down()
page.locator("#item-to-drop-at").hover()
page.mouse.up()

9.运行JS脚本

这也是一个很有效的手段,比如某个日期输入框是只读的,无法直接录入想要的日期,只能通过日期选择框去选择,而通过日期选择框去选择效率会很低下,这个时候我们只需要通过运行JS脚本将该输入框的只读属性去掉,然后使用input方法录入日期即可

# 将id为txtStartDtate的元素去掉readonly属性
page.evaluate('document.getElementById("txtStartDate").removeAttribute("readonly");')

10.文件上传

# Select one file
page.get_by_label("Upload file").set_input_files('myfile.pdf')
# page.get_by_label("Upload file")为一个locator,选择一个文件myfile.pdf# Select multiple files,选择多个文件
page.get_by_label("Upload files").set_input_files(['file1.txt', 'file2.txt'])# Remove all the selected files,清楚选择的文件名
page.get_by_label("Upload file").set_input_files([])# Upload buffer from memory
page.get_by_label("Upload file").set_input_files(files=[{"name": "test.txt", "mimeType": "text/plain", "buffer": b"this is a test"}],
)

11.页面事件监听

Page 对象提供了一个 on 方法,它可以用来监听页面中发生的各个事件,比如 close、console、load、request、response 等等

from playwright.sync_api import sync_playwrightdef run(playwright):chromium = playwright.chromiumbrowser = chromium.launch()page = browser.new_page()# 监听请求和响应事件page.on("request", lambda request: print(">>", request.method, request.url))page.on("response", lambda response: print("<<", response.status, response.url))page.goto("https://example.com")browser.close()with sync_playwright() as playwright:run(playwright)

12.获取元素文本

inner_text():获取元素的文本内容

六.断言

expect(locator).to_be_checked()  复选框可被选中
expect(locator).to_be_disabled()	元素处于禁用状态
expect(locator).to_be_editable()	元素为可编辑状态
expect(locator).to_be_empty()	容器为空
expect(locator).to_be_enabled()	元素状态为enabled
expect(locator).to_be_focused()	元素位于焦点
expect(locator).to_be_hidden()	元素不可见
expect(locator).to_be_visible()	元素可见
expect(locator).to_contain_text()	元素包含文本
expect(locator).to_have_attribute()	Element has a DOM attribute
expect(locator).to_have_class()	Element has a class property
expect(locator).to_have_count()	List has exact number of children
expect(locator).to_have_css()	Element has CSS property
expect(locator).to_have_id()	Element has an ID
expect(locator).to_have_js_property()	Element has a JavaScript property
expect(locator).to_have_text()	Element matches text
expect(locator).to_have_value()	Input has a value
expect(locator).to_have_values()	Select has options selected
expect(page).to_have_title()	Page has a title
expect(page).to_have_url()	Page has a URL
expect(response).to_be_ok()	Response has an OK status

可自定义一个不符合条件的错误信息:

# 不符合条件超时错误后,提示should be logged in
expect(page.get_by_text("Name"), "should be logged in").to_be_visible()

举例说明,访问bing页面,会根据所在的ip地理位置显示不同版本的页面

page.goto('https://www.bing.com')try:# 可尝试更改'必应'为'bing',看是否会报错expect(page, '非中文页面').to_have_title('必应') # 显示的页面标题是否为必应,否则报错:非中文页面print('中文页面')
except Exception as e:print('进入非中文页面')print(e)

可设置全局expect超时时间,默认为5秒

expect.set_options(timeout=10_000)  # 超时为10

七.浏览器常见配置

1.截图

1.1. 截图整个页面

from playwright.sync_api import sync_playwright  with sync_playwright() as p:  browser = p.chromium.launch(headless=False)  # headless=False表示以有头模式运行,可以看到浏览器界面  page = browser.new_page()  page.goto("https://example.com")  page.screenshot(path="screenshot.png")  # 截图并保存到当前目录下的screenshot.png  browser.close()
  • 如果你想要截取整个可滚动页面的屏幕截图(长截图),可以添加full_page=True参数:
page.screenshot(path="full_page_screenshot.png", full_page=True)

1.2. 截取整个页面并裁剪

首先,你可以截取整个页面,然后使用图像处理库(如Pillow(Python)、Sharp(Node.js)等)来裁剪出你需要的部分。

Python 示例(使用Pillow):

from PIL import Image  
from playwright.sync_api import sync_playwright  with sync_playwright() as p:  browser = p.chromium.launch(headless=False)  page = browser.new_page()  page.goto("https://example.com")  # 截取整个页面  full_page_screenshot = page.screenshot(path="full_page.png", full_page=True)  # 截取整个可滚动页面的屏幕截图(长截图),可以添加full_page=True参数:# 使用Pillow裁剪图片(这里需要你指定裁剪的坐标和大小)  img = Image.open("full_page.png")  cropped_img = img.crop((left, top, right, bottom))  # left, top, right, bottom 是裁剪区域的坐标  cropped_img.save("cropped_image.png")  browser.close()
  • 注意:你需要根据页面内容和布局来手动计算裁剪区域的坐标(left, top, right, bottom)。

2. 设置窗口(Viewport)大小

另一种方法是调整浏览器窗口(Viewport)的大小,以匹配你想要截取的图片大小,然后截取整个页面。但是,这种方法可能不适用于需要滚动条来查看整个内容的页面。

from playwright.sync_api import sync_playwright  with sync_playwright() as p:  browser = p.chromium.launch(headless=False)  context = browser.new_context(viewport_size={"width": 800, "height": 600})  # 设置窗口大小  page = context.new_page()  page.goto("https://example.com")  # 由于窗口大小已设置,截取的图片大小将与窗口大小相匹配  page.screenshot(path="viewport_screenshot.png")  browser.close()

4.截取特定元素并调整大小

Playwright还支持截取页面中的特定元素。你可以使用locator来定位元素,并调用其screenshot方法:

  • 如果你只需要截取页面上的特定元素,并且想要控制输出图片的大小,你可以先截取该元素,然后使用图像处理库来调整图片大小。
# ...(之前的代码,定位到特定元素)  # 截取特定元素  
element_screenshot = page.locator("selector").screenshot(path="element_screenshot.png")  # 使用Pillow调整图片大小(如果需要)  
# ...(与上面裁剪图片的代码类似,但使用resize方法)

5. 捕获截图为字节流

如果你不想将截图保存到文件,而是想将其捕获为字节流以便进一步处理(如发送到服务器或进行像素差异比较),可以这样做:

import base64  screenshot_bytes = page.screenshot()  
screenshot_base64 = base64.b64encode(screenshot_bytes).decode()  
print(screenshot_base64)  # 输出截图的Base64编码

2.自定义Header

browser_context.set_extra_http_headers(headers)
from playwright.async_api import async_playwright  async def run(playwright):  browser = await playwright.chromium.launch()  context = await browser.new_context()  # 设置额外的HTTP头部  extra_headers = {  "Authorization": "Bearer YOUR_ACCESS_TOKEN",  "Custom-Header": "HeaderValue"  }  await context.set_extra_http_headers(extra_headers)  # 现在,由这个上下文中的任何页面发起的请求都将包含这些额外的HTTP头部  page = await context.new_page()  await page.goto('https://example.com')  # ... 其他操作 ...  await browser.close()  async_playwright().start(run)

3.自定义UserAgent

创建浏览器上下文(BrowserContext)时,通过new_context方法的user_agent参数来设置user-agent。这种方式该上下文创建的所有页面都会共用user_agent

from playwright.sync_api import Playwright, sync_playwrightwith sync_playwright() as playwright:browser = playwright.chromium.launch()# 在浏览器上下文级别设置user-agent  context = browser.new_context(user_agent='Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36')page = context.new_page()page.goto('https://example.com')# 后续操作...  browser.close()

4.设置浏览器代理

在使用Playwright进行自动化测试或浏览器操作时,设置代理是一个常见的需求。Playwright支持在多个层面上设置代理,包括全局代理、上下文代理以及页面级别的代理。以下是如何在Playwright中设置代理的几种方式:

1. 启动时设置全局代理

在启动浏览器时,可以通过launch方法的proxy参数来设置全局代理。这种方式会影响由该浏览器实例发起的所有请求。

示例代码:

from playwright.sync_api import Playwright, sync_playwright  with sync_playwright() as playwright:  # 不需要身份验证的代理  browser = playwright.chromium.launch(proxy={'server': 'http://ip:port'})  # 需要身份验证的代理  # browser = playwright.chromium.launch(proxy={'server': 'http://ip:port', 'username': '用户名', 'password': '密码'})  # 后续操作...  # browser.close()

2. 上下文设置代理

通过为每个页面创建一个独立的context对象,并在该对象上设置代理,可以实现为特定页面或一组页面指定不同的代理设置。

from playwright.sync_api import Playwright, sync_playwright  with sync_playwright() as playwright:  browser = playwright.chromium.launch()  # 设置代理  context = browser.new_context(proxy={'server': 'http://ip:port'})  # 基于该上下文创建页面  page = context.new_page()  # 后续操作...  # page.close()  # context.close()  # browser.close()

5.自动等待机制

1.自动等待和##可操作性校验(Auto-waiting)

Playwright具有内置的自动等待机制,该机制在执行某些操作(如点击、输入等)之前,会自动检查目标元素是否满足以下条件:

  • 元素加载DOM完成:确保元素已经被加载到DOM中。
  • 元素可见:确保元素在页面中可见,没有被其他元素遮挡。
  • 元素是稳定的:确保元素的状态已经稳定,不会因为页面的其他操作而发生变化。(非动画中或动画已完成)
  • 元素没有被其他元素遮挡:确保点击或交互的位置没有其他元素(如覆盖层)阻挡。
  • 元素是可操作的:确保元素是可交互的,没有被禁用。(例如,按钮的enabled属性为true)

如果以上校验在设定的超时时间内得没有通过,Playwright将继续执行下一步操作;否则,将抛出TimeoutError异常。这种自动等待机制大大简化了测试脚本的编写,并提高了测试的稳定性。

2.显式等待API(Explicit Waiting)

除了自动等待外,Playwright还提供了多种显式等待方法,API允许开发者在测试脚本中设置等待条件,从而避免手动等待的繁琐和不确定性。

wait_for_selector(selector, options):等待指定的选择器匹配到的元素出现在页面上。
wait_for_timeout(timeout):等待指定的时间。
wait_for_url(url, options):等待URL包含指定的字符串。
wait_for_navigation(options):等待页面完成导航。
wait_for_event:等待给定的事件被触发,如click、submit等。
wait_for_function:等待指定的JavaScript函数返回true。

详细介绍

  1. wait_for_selector(selector, options):等待指定的选择器匹配到的元素出现在页面上。(等待元素加载完毕)

    • selector:CSS选择器或XPath表达式,用于指定要等待的元素。

    • options(可选):一个对象,包含等待的选项,如timeout(超时时间,单位毫秒)。

      element = await page.wait_for_selector('#my-element', { timeout: 5000 })
      #这个示例将等待最多5秒钟,直到页面上出现ID为my-element的元素。
      
      • 在进行页面跳转后,可以加入wait_for_selector等待元素加载,以确保页面内容已经完全加载完成

      • state 参数可以设置等待状态,用四个状态:“attached”, “detached”, “hidden”, “visible”。
        在这里插入图片描述

    wait_for() 方法和>wait_for() 方法 和 wait_for_selector()使用区别:

    • page.locator(‘定位元素’).wait_for() 返回的是None,后面不能继续操作元素
    • page.wait_for_selector(“定位方法”)返回的是locator 对象,后面可以继续操作元素
  2. wait_for_timeout(timeout):等待指定的时间。这通常用于调试目的,但在生产环境中应谨慎使用。

    • timeout:等待的时间,单位毫秒。
      await page.wait_for_timeout(5000)
      
  3. wait_for_url(url, options) 等待当前页面的URL包含指定的字符串或完全匹配指定的URL。

    • url:要等待的URL字符串或包含部分URL的字符串。
    • options(可选):一个对象,包含等待的选项,如timeout。
      await page.wait_for_url('https://example.com', { timeout: 10000 })
      #等待最多10秒钟,直到当前页面的URL包含https://example.com。
      
  4. wait_for_navigation(options) 等待页面完成导航。

    • options(可选):一个对象,包含等待的选项,如waitUntil(指定等待的导航状态,如’networkidle’表示等待网络请求空闲)和timeout。

      await page.click('a.some-link')  
      await page.wait_for_navigation({ waitUntil: 'networkidle' })
      #首先点击一个链接,然后等待页面导航到新的URL,并等待直到网络请求空闲。
      

3.全局设置等待超时时间

  • 这些设置将影响所有接受timeout参数的方法。设置的优先级是:页面级别的优先于浏览器上下文级别。
browser_context.set_default_timeout(timeout):设置浏览器上下文级别的默认超时时间。
page.set_default_timeout(timeout):设置页面级别的默认超时时间。
browser_context.set_default_navigation_timeout(timeout):设置浏览器上下文级别的默认导航超时时间。
page.set_default_navigation_timeout(timeout):设置页面级别的默认导航超时时间。

6.处理新的窗口、弹窗,iframe

selenium处理iframe比较麻烦,但是playwright就比较简单,有不同方法

  1. 直接定位一个frame,在frame基础上操作
# ********同步*********
#根据iframe名字
frame = page.frame('frame-login')
#根据iframe的url
frame = page.frame(url=r'.*domain.*')# Interact with the frame
frame.fill('#username-input', 'John')# *********异步***********
#根据iframe名字
frame = page.frame('frame-login')
#根据iframe的url
frame = page.frame(url=r'.*domain.*')
# Interact with the frame
await frame.fill('#username-input', 'John')
  1. 直接定位到frame再定位到上面的元素,在元素基础上操作
username = page.frame_locator('.frame-class').locator('#username-input')
username.fill('jonas')

处理弹窗,一般注册、或者点击一些按钮容易出现弹窗,我们可以利用page.expect_popup()来获取新窗口的iframe

示例:

with page.expect_popup() as popup_info:# iframe中的id如果是动态的,所以我们只匹配关键字page.frame_locator("iframe[id^=x-URS-iframe]").locator("text=注册新帐号").click()register_page = popup_info.value# 点击邮箱地址输入框register_page.locator("input[id=\"username\"]").click()# 输入邮箱register_page.locator("input[id=\"username\"]").fill("TesterRoad")# 点击密码输入框register_page.locator("input[id=\"password\"]").click()# 输入密码register_page.locator("input[id=\"password\"]").fill("TesterRoad@126")

手动设置等待是为了确保接下来的操作可以成立,旧版本里使用了很多类似wait_for_selector的用法,但新版本推荐使用的是expect方法,就是期望某个条件成立,默认超时时间为5秒

7.支持Pytest框架

另外,还可以配合pytest插件一起使用,给出一段官网示例:

# 导入pytest和playwright的sync_api(也可以使用async_api)  
import pytest  
from playwright.sync_api import Page  # 使用pytest的fixture来初始化浏览器页面  
@pytest.fixture(scope="function")  
def page(browser_type):  """启动浏览器并创建一个新页面"""  browser = browser_type.launch(headless=False)  # 如果想看到浏览器运行,可以设置为False  page = browser.new_page()  yield page  # 测试函数将在这里接收page对象  browser.close()  # 测试完成后关闭浏览器  # 编写测试函数  
def test_example(page):  """示例测试:访问Playwright官网并验证标题"""  # 导航到Playwright官网  page.goto("https://playwright.dev/")  # 验证页面标题是否包含"Playwright"  title = page.title()  assert "Playwright" in title  # 进一步的操作,比如点击链接、填写表单等  # ...  # 注意:上述代码中的browser_type是由pytest-playwright插件自动提供的fixture  
# 你可以通过它来启动浏览器(如Chromium、Firefox、WebKit等)  
# headless=False 表示以有头模式运行浏览器,这样你可以看到浏览器界面  
# 如果你想要以无头模式运行(即不显示浏览器界面),可以将headless设置为True或省略该参数(因为默认就是无头模式)

8.移动端浏览器支持

移动端支持Safari 浏览器、谷歌、不支持火狐,可以传入的设备有iPhone和Pixel 2 (Pixel 2 是谷歌的一款安卓手机)

  • 示例:模拟打开 iPhone 12 Pro Max 上的 Safari 浏览器,然后手动设置定位,并打开百度地图并截图

  • 故宫的经纬度是 39.913904, 116.39014,我们可以通过geolocation参数传递给 Webkit 浏览器并初始化

from playwright.sync_api import sync_playwrightwith sync_playwright() as p:iphone_12_pro_max = p.devices['iPhone 12 Pro Max']browser = p.webkit.launch(headless=False)context = browser.new_context(**iphone_12_pro_max,locale='zh-CN',geolocation={'longitude': 116.39014, 'latitude': 39.913904},permissions=['geolocation'])page = context.new_page()page.goto('https://amap.com')page.wait_for_load_state(state='networkidle')page.screenshot(path='location-iphone.png')browser.close()

注意事项

  • 设置user-agent时,请确保它符合你的测试需求或目标网站的兼容性要求。
  • 如果你需要频繁地更改user-agent,考虑将设置user-agent的逻辑封装成一个函数或方法,以便在需要时重复使用。
  • 请注意,某些网站可能会根据user-agent的不同而返回不同的内容或执行不同的逻辑。因此,在自动化测试或爬虫开发过程中,合理地设置user-agent是非常重要的。

额外信息
– 除了user-agent之外,Playwright还允许你在创建浏览器上下文时设置其他许多浏览器级别的参数,如窗口大小(viewport)、地理位置(geolocation)、语言(locale)、时区(timezone)等。这些参数可以帮助你更精确地模拟不同用户的浏览器环境,从而提高自动化测试或爬虫开发的效率和准确性。

八.playwright如何绕过反爬虫检测

检测地址:https://intoli.com/blog/not-possible-to-block-chrome-headless/chrome-headless-test.html

  • 网站为了保护信息不被爬取会添加一些反爬虫策略,比如直接打开谷歌浏览器,在控制台输入window.navigator.webdriver,可以看到该属性为false
    在这里插入图片描述

  • 用selenium或者playWright打开浏览器,该属性为true
    在这里插入图片描述

  • 网站很容易在前端根据这些属性判断是否使用了playwright,从而阻止用户采用自动化工具获取信息

那么如何屏蔽掉这些属性,让网站无法识别是否使用了playwright呢?。

  1. 首先通过浏览器打开网站https://bot.sannysoft.com/,该网站列出了常用的一些反爬虫检测属性
    在这里插入图片描述

  2. 使用playwright打开这个网站, 发现webdriver属性被检测出异常

from playwright.sync_api import sync_playwright
import timewith sync_playwright() a playwright:browser  _playwright.chromium.launch(headless=False)page = browser.new_page()page.goto('https://bot.sannysoft.com/')time.sleep(100)browser.close()

在这里插入图片描述

1 防止webdriver属性被检测

from playwright.sync_api import sync_playwright
import timewith sync_playwright() as playwright:browser = playwright.chromium.launch(headless=False)page = browser.new_page()js="""Object.defineProperties(navigator, {webdriver:{get:()=>false}});"""page.add_init_script(js)page.goto('https://bot.sannysoft.com/')time.sleep(1000)browser.close()
  • 运行后可以看到webdriver还是没有通过,打开控制台,输入navigator.webdriver
    在这里插入图片描述

  • 发现这个值的确为false,那么没有通过的原因是什么?找到网站检测的源码,有这么一几行代码

    // Webdriver Testconst webdriverElement = document.getElementById('webdriver-result');if (navigator.webdriver || _.has(navigator, "webdriver")) {webdriverElement.classList.add('failed');webdriverElement.classList.remove('passed');webdriverElement.innerHTML = 'present (failed)';} else {webdriverElement.classList.add('passed');webdriverElement.classList.remove('failed');webdriverElement.innerHTML = 'missing (passed)';}
    
    • 属性 _.has(navigator, “webdriver”)true没有通过,这个表示navigator中有webdriver这个属性了,必须去掉才可以过这个检测。
      • 这个去掉该属性直接用GitHub上下载的一个stealth.min.js,地址为https://github.com/kingname/stealth.min.js/blob/main/stealth.min.js
    from playwright.sync_api import sync_playwright
    import timewith sync_playwright() as p:'''防止被浏览器检测的处理方法'''browser = p.chromium.launch(headless=False)page = browser.new_page()#加载stealth.min.js的javascriptwith open('stealth.min.js','r') as f:js=f.read()page.add_init_script(js)page.goto('https://bot.sannysoft.com/')time.sleep(1000)browser.close()
    
    • 运行后,这次检测已经通过了。
      在这里插入图片描述

2 headless=True无头浏览器如何绕过反爬虫

上面可以过检测用的是带界面浏览,当为无头浏览器是怎么样的呢,这里采用运行后进行截图的方式进行调试

from playwright.sync_api import sync_playwright
import timewith sync_playwright() as p:browser = p.chromium.launch(headless=True)page = browser.new_page()with open('stealth.min.js','r') as f:js=f.read()page.add_init_script(js)page.goto('https://bot.sannysoft.com/')#进行截图page.screenshot(path='bot_sannysoft.png',full_page=True)time.sleep(1000)browser.close()

在这里插入图片描述

  • 当用无头浏览器时user agent没有通过,因此需重新设置user agent
from playwright.sync_api import sync_playwright
import timewith sync_playwright() as p:browser = p.chromium.launch(headless=True,args=['--disable-blink-features=AutomationControlled','--user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36'])page = browser.new_page()with open('stealth.min.js','r') as f:js=f.read()page.add_init_script(js)# 设置网页大小也可以防止无头浏览器被检测page.set_viewport_size({'width': 1024, 'height': 768})page.goto('https://bot.sannysoft.com/')#进行截图page.screenshot(path='bot_sannysoft.png',full_page=True)time.sleep(1000)browser.close()
  • 运行后,发现无头浏览器所有检测也均能通过。
    在这里插入图片描述

3.stealth.min.js作用

‌stealth.min.js 这个JavaScript主要用于保护用户隐私和匿名性,同时也在自动化测试中隐藏自动化特征。
主要功能和应用场景:

  • 隐藏行为:可以通过模拟用户行为的方式来执行各种操作,比如点击、滚动、输入等,从而隐藏真实用户的操作轨迹使得网站无法准确追踪用户的行为。

  • 保护用户隐私和匿名性:通过修改‌User Agent、禁用浏览器指纹识别、隐藏浏览器插件信息、阻止第三方Cookie等方式,stealth.min.js可以帮助用户在使用网络时保持匿名,防止被网站或第三方服务追踪个人信息。‌

  • 防止爬虫检测:在自动化测试中,如使用‌Selenium进行网页测试时,stealth.min.js可以帮助隐藏自动化工具的特征,防止被网站识别为非法访问,从而提高测试的效率和准确性。‌

4.防止爬虫检测的方式

  1. 使用无头浏览器:无头浏览器不会显示图形界面,从而降低了被检测的风险。
  2. 设置User-Agent:通过模拟常见的浏览器User-Agent,可以减少被检测的可能性。
  3. 添加随机延迟:在爬虫中添加随机延迟,模拟真实用户的操作习惯,降低被检测的风险。
  4. 使用代理IP:通过代理IP来隐藏真实的IP地址,降低被识别和封锁的风险。

九.通过CDP(Chrome DevTools Protocol)连接现有浏览器

1.CDP(Chrome DevTools Protocol)和WDP (WebDriver Protocol)协议

WDP 和 CDP 是用于自动化浏览器的2个主要协议,大多数的浏览器自动化工具都是这两个协议实现和浏览器交互,通过代码来控制浏览器,完成浏览器的自动化行为(包括网页加载,点击、输入、按键、截图,导出pdf等)。

2.WebDriver Protocol

  • WebDriver 是一个用于控制浏览器的远程控制接口,由Selenium HQ开发,后来由 W3C 标准化。它提供了一个平台和语言中立的接口,支持几乎所有主流浏览器,如 Chrome、 Firefox、 Safari、 Edge、 Opera 等。
    • 官网:https://w3c.github.io/webdriver/
  • 它和浏览器的通信是通过 JSON Wire 协议完成的,提供了RESTful的web服务,该服务端就被被称为webdriver,例如chromeDriver、geckoDriver等。
    • webdriver的客户端可为任何语言由webdriver客户端和webdriver服务端交互,webdriver服务端和浏览器交互,从而操作浏览器
    • 常见的客户端就是selenium,nightwatch,webdriverio
      在这里插入图片描述
      加上我们的自己写的自动化测试代码之后,交互流程如下:
      在这里插入图片描述
    • 常见的调用流程如下
      1. webdriver客户端(Python代码) 通过调用自动化库API
      2. 自动化库通过对应的webdriver服务端(如selenium)基于WDP协议通过 JSON Wire 协议RESTful方式向浏览器发起操作请求(打开/关闭/点击/输入/按键/截图等等
      3. 浏览器接收到自动化工具请求后,完成相关操作然后返回响应给webdriver服务端
      4. webdriver服务器端接收到浏览器响应,返回响应给webdriver客户端

3.Chrome DevTools Protocol

  • ChromeDevTools Protocol (CDP)是一个基于Chromium的浏览器的调试协议,如 Chrome、 Edge、 Opera 等。通过它可以直接和浏览器交互。控制浏览器的行为。

    • 官网:https://chromedevtools.github.io/devtools-protocol/
  • 浏览器是由客户端使用 CDP 协议直接控制的,客户端和浏览器之间没有类似于WebDriver Protocol的服务端(webdriver),客户端通过WebSocket直接和浏览器连接 ,由客户端通过WebSocket发送命令给浏览器,浏览器执行并返回响应
    在这里插入图片描述

  • 常见的客户端就是:Puppeteer和Playwright。它们不依赖于webdriver,而是通过 Chrome DevTools Protocol (CDP)直接与浏览器通话。从而更加灵活稳定的控制浏览器。

4.WebDriver Protocol和Chrome DevTools Protocol对比

在这里插入图片描述

十.拓展知识

屏幕坐标系,世界坐标系

在这里插入图片描述

屏幕坐标系,主要有两种,

  • 第一种:以左上角为原点。代表的操作系统有Windows,Android,Symbian,iOS 的Core Graphics

  • 第二种:以左下角为原点。比如iOS的CGContextDrawImage

    • IOS 零点在左上角
    • mac 零点在左下角

十一.Playwright 和 Selenium 的区别

在这里插入图片描述
在这里插入图片描述

  • Playwright的优点是简单方便、功能强大、稳定性高,缺点是相对新,用户群体少,学习资料少。只能看官网文档
  • Selenium的优点是灵活性高、用户群体大、学习资料多,缺点是需要自己封装或者导入其他模块来实现一些功能,启动速度慢,稳定性差。

如果你是新手,毫不犹豫应该直接学playwright


参考文章:《最新出炉》系列初窥篇-Python+Playwright自动化测试

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/402433.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

SQL每日一练-0815

今日SQL题难度&#xff1a;&#x1f31f;☆☆☆☆☆☆☆☆☆ 1、题目要求 计算每个产品类别在每个月的总销售额和总销量。找出每个月销售额最高的产品类别&#xff0c;显示类别名称、销售月份、总销售额和总销量。 2、表和虚拟数据 现有两个表&#xff1a;Products 和…

RockerMQ学习

消息中间件以前常用RabbitMQ和ActiveMQ&#xff0c;由于业务需要&#xff0c;后期业务偏向大数据&#xff0c;现着重学习一下RocketMQ&#xff08;RocketqMQ原理同ctg-mq&#xff09;&#xff0c;后续更新Kafka 一、RocketMQ特性 Kafka特性 &#xff08;高性能分布式&#xff…

day34-nginx常用模块

## 0. 网络面试题 网络面试题: TCP三次握手 TCP四次挥手 DNS解析流程 OSI七层模型 抓包工具 tcpdump RAID级别区别 开机启动流程 如何实现不同的网段之间通信(路由器) ip route add 192.168.1.0 255.255.255.0 下一跳的地址或者接口 探测服务器开启了哪些端口(无法登录服务器…

渗透测试-行业术语

1.肉鸡 肉鸡用来比喻哪些可以随意被我们控制的计算机&#xff0c;可以是普通的个人电脑&#xff0c;也可以是大型服务器或者其他网络设备&#xff0c;我们可以像操作自己的电脑一样操作他们而不被发觉。 2.木马 表面上伪装成了正常程序&#xff0c;但是当程序被运行的时候&a…

配置MySQL主从,配置MySQL主主 +keeplive高可用

在大数据-Hadoop体系中 配置MySQL主主keeplive高可用 注意&#xff1a;这个是我两年前的word文档&#xff0c;可以当作参考文档有个思路参考一下&#xff0c;但是里面可能有些地方有误 另外 :关于一些企业级实战技术可以参考这篇mysql 物理备份 MySQL 全量备份 增量备份 差异…

Linux_vi vim的使用

目录 vi和vim的基本介绍 vi和vim常用的三种模式 案例演示 vim的快捷键 快捷键使用练习 vi和vim的基本介绍 linux系统内会内置vi文本编译器。vim可以简单认为是vi的增强版本。 vi和vim常用的三种模式 有正常模式&#xff0c;移动光标&#xff0c;删除字符等。插入模式可以进…

Flask 线上高并发部署方案实现

目录 1、Flask默认多线程执行 2、使用gevent.pywsgi实现 3、是用uWSGI服务器实现 1、Flask默认多线程执行 前言&#xff1a;在Flask的较早版本中&#xff0c;默认并不支持多线程模式。然而&#xff0c;从Flask 0.9版本开始&#xff0c;引入了多线程模式的支持&#xff0c;并…

【自动驾驶】ROS中的TF坐标变换(一):静态坐标变换

目录 引子ros中的右手坐标系补充&#xff1a;欧拉角及四元数理解旋转平移操作复合操作 运行坐标变换的例子坐标转换 静态坐标变换-发布坐标系信息创建功能包 静态坐标变换-订阅坐标系信息添加cpp订阅者主文件修改cmakelist文件编译报错的解决方案运行程序进行测试 引子 机器人…

【MySQL数据库】单机、集群、分布式的区别

单机、集群和分布式是计算机系统中三种不同的架构模型,它们在资源管理、任务执行和性能优化方面有显著区别。 图片来源 1. 单机(Standalone) 单机指的是单一计算机系统,即所有的计算任务和数据都在一台计算机上处理。单机系统的特点包括: 硬件限制:受限于单台机器的计…

Visual Studio 2022 无法打开源文件atlimage.h

最近在搞tcp socket 通信demo&#xff0c;网上抄了一下源码&#xff08;代码参考&#xff1a;C中的Socket编程使用协议发送图片_快速传输 照片 c-CSDN博客&#xff09;&#xff0c;还没开始编译就提示 无法打开源文件atlimage.h&#xff0c;全局搜了一下没有这个文件&#xff0…

JSON Web Token (JWT): 理解与应用

JWT&#xff08;JSON Web Token&#xff09;是一种开放标准&#xff08;RFC 7519&#xff09;&#xff0c;它定义了一种紧凑且自包含的方式&#xff0c;用于在各方之间以JSON对象的形式安全地传输信息。JWT通常用于身份验证和授权目的&#xff0c;因为它可以使用JSON对象在各方…

Unity开发抖音小游戏广告部分接入

Unity开发抖音小游戏广告部分接入 介绍环境确保开通流量主获取广告位广告部分代码测试如下总结 介绍 最近在使用Unity做抖音小游戏这块的内容&#xff0c;因为要接入广告&#xff0c;所以这里我把我接入广告的部分代码和经验分享一下。 环境确保 根据抖音官方的文档我们是先…

Linux网络编程—socket、bind

一、socket创建套接字 socket是用来创建网络通信或本地通信的套接字&#xff0c;跟文件有关&#xff1a;告诉系统&#xff0c;PCB&#xff08;进程控制块&#xff09;控制的数据应该向哪个套接字写入、或读取&#xff1b;这个套接字是在TCP/IP协议下运行的 #include <sys/t…

选择排序(附动图)

1.思路 基本思想&#xff1a; 每一次从待排序的数据元素中选出最小&#xff08;或最大&#xff09;的一个元素&#xff0c;存放在序列的起始位置&#xff0c;直到全部待排序的数据元素排完 。 1.1双向选择排序&#xff08;升序&#xff09; 头尾指针&#xff08;索引&#xf…

初识C++

一、C的由来 C的起源可以追溯到1979年&#xff0c;当时Bjarne Stroustrup(本贾尼斯特劳斯特卢普&#xff0c;这个翻译的名字不同的地方可能有差异)在贝尔实验室从事计算机科学和软件工程的研究工作。面对项目中复杂的软件开发任务&#xff0c;特别是模拟和操作系统的开发⼯作&…

涉案财物管理系统DW-S405|实现人员随身物品智能化管理

涉案财物管理系统DW-S405系统基于物联网技术规范涉案财物管理流程&#xff0c;确保涉案财物的安全性、完整性和合法性&#xff1b;可以提高办案效率&#xff0c;减少办案成本&#xff0c;实现资源共享。 财物管理 管理员可通过个人账号和指纹验证两种登录方式进入财物管理系统…

1. 数据结构——顺序表的主要操作

1. 内容 顺序表的初始化、插入、删除、按值查找、输出以及其时间复杂度的计算。 2.代码 #include<stdio.h> #include<stdlib.h> //函数结果状态代码 #define OK 1 #define OVERFLOW -2 #define ERROR 0 #define MAXSIZE 100typedef int ElemType; //顺序表每个…

使用Nexus搭建Maven私服仓库

一、私服仓库简介 在Java的世界中&#xff0c;我们通常使用Maven的依赖体系来管理构件&#xff08;artifact&#xff0c;又称为二方库或三方库&#xff09;的依赖&#xff0c;Maven仓库用于存储这些构件。一般的远程仓库&#xff08;比如Maven Central&#xff09;只提供下载功…

OpenCV Python 图像处理入门

OpenCV入门 OpenCV&#xff1a;轻量、高效、开源。最广泛使用的计算机视觉工具。 下面涉及图片的读取&#xff0c;RGB彩色通道&#xff0c;区域裁剪&#xff0c;绘制图形和文字&#xff0c;均值滤波&#xff0c;特征提取&#xff0c;模板匹配&#xff0c;梯度算法&#xff0c…

获奖方案|趋动科技:资源池化释放AI算力价值

“据统计&#xff0c;GPU的平均利用率不超过30%&#xff0c;会产生巨大的算力资源浪费。我们用软件定义的方式通常可以把用户GPU的利用率提升3-8倍&#xff0c;甚至可以到10倍。” 这是算力池化软件公司趋动科技援引行业报告数据并结合自身企业最佳实践经验给出的最新数据。通…