news 2026/7/5 9:45:03

Playwright Python自动化测试与网页截图终极实战指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Playwright Python自动化测试与网页截图终极实战指南

1. 项目概述:为什么我们需要一个“终极”的自动化测试工具?

如果你是一名测试工程师、开发人员,或者任何需要和网页打交道的人,最近一定没少听到“Playwright”这个名字。它就像一阵旋风,迅速席卷了自动化测试和网页爬虫的圈子。但你可能也困惑过:市面上已经有Selenium和Puppeteer了,为什么还要学Playwright?这个“终极指南”到底“终极”在哪里?

简单来说,Playwright是微软开源的一个现代化浏览器自动化库。它解决了我们过去用Selenium时最头疼的几个问题:等待元素的不确定性、跨浏览器兼容性的繁琐配置、以及处理现代单页应用(SPA)动态内容的无力感。我最初接触它,是因为一个需要同时兼容Chrome、Firefox和Safari的截图项目。用Selenium写一套脚本,光是处理不同浏览器的驱动和等待策略就耗掉大半天,还经常因为页面加载不完全导致截图失败。换成Playwright后,同样的功能,代码量减少了三分之一,运行稳定性和速度却提升了一倍不止。

这份指南的目标,就是带你从零开始,彻底掌握Playwright Python的核心能力,重点聚焦在跨浏览器自动化测试高保真网页截图这两个最实用、最高频的场景。无论你是想为你的Web应用构建一套健壮的测试体系,还是需要批量、精准地捕获网页快照用于归档、监控或数据分析,这篇文章都能给你一套可直接复制粘贴的“工业级”解决方案。我们会从环境搭建讲到高级技巧,并分享大量我踩过坑后才总结出的实战经验。

2. 核心设计思路:Playwright凭什么成为“新王”?

在深入代码之前,我们必须理解Playwright的设计哲学。它不是一个简单的“Selenium替代品”,而是一次架构上的革新。

2.1 架构优势:超越WebDriver协议

传统的Selenium通过WebDriver协议与浏览器通信,这是一个标准,但也是瓶颈。每个浏览器厂商提供的WebDriver实现质量参差不齐,导致行为不一致,且协议本身对现代浏览器的一些高级特性支持滞后。

Playwright则采用了更底层的CDP(Chrome DevTools Protocol)或私有协议直接与浏览器内核对话。这意味着Playwright能获得对浏览器更精细、更强大的控制力。例如,它可以:

  • 拦截和修改网络请求:在请求发出前或响应返回后注入你的逻辑,轻松实现Mock数据或性能测试。
  • 模拟丰富的输入设备:不仅支持键盘鼠标,还能模拟触摸屏、地理定位、设备朝向等。
  • 获得更准确的页面生命周期事件:知道页面何时“真正”加载完成(包括所有异步JavaScript和网络请求),这是实现稳定截图和测试的基石。

2.2 核心特性拆解

  1. 自动等待(Auto-waiting):这是Playwright最“香”的特性。在Selenium里,我们不得不写大量的time.sleep()或显式等待(WebDriverWait),既低效又不稳定。Playwright的绝大多数操作(如click,fill,screenshot)内部都内置了智能等待。它会等待元素可操作(可见、启用、稳定)后才执行动作,极大减少了因时序问题导致的脚本失败。
  2. 浏览器上下文(Browser Context):你可以把它理解为一个独立的、隔离的浏览器会话。每个上下文都有独立的cookie、本地存储和缓存,互不干扰。这为并行测试和数据隔离提供了完美支持。一个浏览器进程可以创建多个轻量级的上下文,而不是启动多个沉重的浏览器实例。
  3. 强大的选择器引擎:Playwright支持CSS、XPath,还提供了非常实用的文本选择器(text=)和React/Vue等框架的组件选择器。特别是文本选择器,在编写可读性高的测试用例时非常方便。
  4. 网络拦截与Mock:无需依赖第三方代理工具,直接在脚本中拦截请求、修改响应或返回自定义数据,对于测试边缘场景和依赖第三方API的应用至关重要。
  5. 追踪与调试工具:内置了playwright trace功能,可以录制测试执行过程中的所有操作、网络请求、控制台日志,生成一个可视化的ZIP文件,用于事后分析失败的测试用例,堪称“时光机”。

3. 环境搭建与核心API详解

理论说再多,不如动手搭环境。这里我会给出一个兼顾新手和团队协作的配置方案。

3.1 一站式环境配置

首先,确保你安装了Python(3.7+)。我强烈建议使用虚拟环境来管理依赖。

# 1. 创建项目目录并进入 mkdir playwright-project && cd playwright-project # 2. 创建虚拟环境(以venv为例) python -m venv venv # 3. 激活虚拟环境 # Windows: venv\Scripts\activate # macOS/Linux: source venv/bin/activate # 4. 安装Playwright Python库 pip install playwright # 5. 安装Playwright所需的浏览器内核(Chromium, Firefox, WebKit) playwright install

注意playwright install这一步会下载浏览器二进制文件,体积较大(约1GB),请确保网络通畅。它默认会安装所有三个浏览器。如果你只需要其中某一个,可以使用playwright install chromium

3.2 同步与异步API的选择

Playwright提供了两套API:同步异步。对于大多数自动化测试和截图脚本,同步API更直观易懂,适合线性任务。如果你的应用本身就是异步的(如FastAPI、Sanic),或者你需要处理大量并发页面操作,异步API能提供更好的性能。

本指南主要以同步API为例,因为它的学习曲线更平缓。但我会在关键部分指出异步的写法。

一个最简单的同步脚本示例:打开页面并截图

from playwright.sync_api import sync_playwright def run(): with sync_playwright() as p: # 启动Chromium浏览器,headless=True表示无头模式(不显示UI) browser = p.chromium.launch(headless=True) # 创建一个浏览器上下文 context = browser.new_context() # 在上下文中打开一个新页面 page = context.new_page() # 导航到目标网址 page.goto('https://example.com') # 对页面进行截图并保存 page.screenshot(path='example.png', full_page=True) # 关闭资源 context.close() browser.close() if __name__ == '__main__': run()

3.3 浏览器、上下文与页面的关系

理解这三者的层级关系是有效使用Playwright的关键:

  • Browser:一个浏览器进程实例(如Chrome)。通过它启动和关闭浏览器。
  • Context:一个独立的浏览器会话环境。它比启动一个新浏览器实例要轻量得多,并且实现了完美的隔离。你可以在一个Browser下创建多个Context来模拟不同用户同时登录。
  • Page:一个标签页。你的绝大部分操作(导航、点击、截图)都发生在Page对象上。一个Context可以拥有多个Page。

这种设计带来了巨大的灵活性。例如,在做截图对比时,你可以在同一个Browser下,为Chrome和Firefox各创建一个Context,然后分别打开Page访问同一个URL进行截图,效率极高。

4. 跨浏览器自动化测试实战

让我们构建一个真实的测试场景:测试一个登录功能在Chrome、Firefox和Webkit(Safari内核)上的表现是否一致。

4.1 测试用例设计与结构

我们不依赖任何测试框架(如pytest),先用纯Playwright实现,这样能更清晰地理解其原理。

from playwright.sync_api import sync_playwright import time def test_login_across_browsers(): """跨浏览器登录测试""" test_results = {} # 定义要测试的浏览器类型 browsers_to_test = ['chromium', 'firefox', 'webkit'] # 测试数据 login_url = 'https://your-test-site.com/login' username = 'test_user' password = 'test_pass123' expected_title_after_login = 'Dashboard' for browser_type in browsers_to_test: print(f"\n开始测试 {browser_type.upper()}...") with sync_playwright() as p: # 启动对应浏览器,headless=False便于观察,实际运行可设为True browser = getattr(p, browser_type).launch(headless=False, slow_mo=1000) # slow_mo让动作变慢,方便观察 context = browser.new_context() page = context.new_page() try: # 1. 导航到登录页 page.goto(login_url) # 等待页面关键元素出现(这里用了选择器,实际需替换) page.wait_for_selector('#username') # 2. 填写登录表单 # 使用CSS选择器定位元素并输入 page.fill('#username', username) page.fill('#password', password) # 点击登录按钮 page.click('button[type="submit"]') # 3. 验证登录成功 # 等待导航完成,并检查页面标题或某个成功元素 page.wait_for_url('**/dashboard**') # 使用通配符匹配URL actual_title = page.title() if expected_title_after_login in actual_title: print(f" ✅ {browser_type}: 登录成功!") test_results[browser_type] = 'PASS' else: print(f" ❌ {browser_type}: 登录失败,标题为 '{actual_title}'") test_results[browser_type] = 'FAIL' # 4. (可选) 登录后截图存档 page.screenshot(path=f'login_success_{browser_type}.png') except Exception as e: # 捕获任何异常,并截图保存错误现场 print(f" ⚠️ {browser_type}: 测试执行出错 - {e}") page.screenshot(path=f'error_{browser_type}_{int(time.time())}.png') test_results[browser_type] = 'ERROR' finally: # 确保资源被关闭 context.close() browser.close() # 输出测试总结 print("\n" + "="*30) print("跨浏览器测试结果总结:") for browser, result in test_results.items(): print(f" {browser.upper()}: {result}") return test_results if __name__ == '__main__': test_login_across_browsers()

4.2 关键操作与最佳实践

  • 选择器策略:优先使用CSS选择器,其次是文本选择器page.click('text=Log In')),最后才是XPath。Playwright的CSS引擎非常强大且稳定。
  • 等待策略page.goto()会等待页面触发load事件。对于单页应用,这通常不够。page.wait_for_selector()page.wait_for_url()是更可靠的选择。page.wait_for_load_state('networkidle')可以等待网络基本空闲,适合大多数动态加载页面。
  • slow_mo参数:在调试阶段,给launch方法加上slow_mo=500(单位毫秒),会让每个Playwright操作都延迟半秒执行,你可以清晰地看到脚本是如何运行的,极大方便调试。
  • 错误处理与截图:一定要用try...except包裹核心操作,并在异常时截图。截图文件名最好包含时间戳或浏览器类型,便于事后追溯。

4.3 与Pytest集成实现企业级测试

单独脚本适合简单任务,但真正的测试项目需要结构化管理、用例发现、夹具(fixture)和报告。pytest是Python生态的事实标准,Playwright官方也提供了pytest-playwright插件。

首先安装插件:

pip install pytest pytest-playwright

创建一个测试文件test_login.py:

import re import pytest from playwright.sync_api import Page, expect # 定义一个pytest fixture,用于为每个测试用例提供配置好的page对象 @pytest.fixture(scope="function") def page(browser): # browser fixture由pytest-playwright插件提供,默认是Chromium # 创建一个新的上下文和页面,确保测试隔离 context = browser.new_context() page = context.new_page() yield page # 测试结束后,清理上下文 context.close() # 参数化测试:用同一套逻辑测试不同浏览器 @pytest.mark.parametrize("browser_name", ["chromium", "firefox", "webkit"]) def test_login_with_pytest(browser_name, request): """使用pytest运行的登录测试""" # 通过request.getfixturevalue动态获取指定浏览器的fixture browser = request.getfixturevalue(browser_name) context = browser.new_context(record_video_dir="videos/") # 可选:录制视频 page = context.new_page() page.goto("https://your-test-site.com/login") page.fill("#username", "test_user") page.fill("#password", "test_pass123") page.click("button[type='submit']") # 使用Playwright的断言库,更语义化 expect(page).to_have_url(re.compile(r".*/dashboard")) expect(page.locator("h1")).to_contain_text("Welcome") context.close() # 使用page fixture的更简洁写法 def test_homepage_title(page: Page): """测试首页标题""" page.goto("https://example.com") expect(page).to_have_title("Example Domain")

运行测试:

# 运行所有测试 pytest # 运行特定文件,并生成HTML报告 pytest test_login.py --html=report.html --self-contained-html

与pytest集成的优势

  1. 自动管理浏览器生命周期:通过fixture,你无需手动编写launchclose
  2. 测试隔离:每个测试函数都会获得一个全新的contextpage,避免测试间状态污染。
  3. 丰富的断言expectAPI提供了更人性化的断言方式,如to_have_title,to_be_visible等,失败时错误信息更清晰。
  4. 强大的参数化与夹具系统:轻松实现跨浏览器、多数据驱动的测试。
  5. 完善的报告:结合pytest-html等插件,可以生成漂亮的测试报告,包含截图、视频(如果录制了)和日志。

5. 高保真网页截图完整教程

截图是Playwright的另一项绝活,其稳定性和灵活性远超传统工具。我们将从基础截图讲到高级场景。

5.1 基础截图:元素、页面与全屏

from playwright.sync_api import sync_playwright with sync_playwright() as p: browser = p.chromium.launch(headless=True) page = browser.new_page() page.goto('https://example.com') page.wait_for_load_state('networkidle') # 等待网络空闲,确保资源加载完 # 1. 截取整个可视区域(当前窗口大小) page.screenshot(path='viewport.png') # 2. 截取完整页面(自动滚动拼接长图) page.screenshot(path='full_page.png', full_page=True) # 3. 截取页面上的某个特定元素 # 首先定位元素 heading_element = page.locator('h1') if heading_element.count() > 0: # 检查元素是否存在 heading_element.first.screenshot(path='heading_element.png') # 4. 带样式的截图:模拟设备视口 # 模拟iPhone 13 Pro iphone_13 = p.devices['iPhone 13 Pro'] context = browser.new_context(**iphone_13) page_mobile = context.new_page() page_mobile.goto('https://example.com') page_mobile.screenshot(path='mobile_view.png', full_page=True) browser.close()

5.2 高级截图技巧与实战场景

场景一:批量截图与定时监控你需要每天定时对一批重要网页进行截图存档,监控其内容变化或外观是否异常。

import schedule import time from datetime import datetime from playwright.sync_api import sync_playwright URL_LIST = [ 'https://news.example.com', 'https://status.example.com', 'https://blog.example.com' ] def capture_screenshots(): """为URL列表中的每个地址截图""" timestamp = datetime.now().strftime('%Y%m%d_%H%M%S') with sync_playwright() as p: browser = p.chromium.launch(headless=True) context = browser.new_context( viewport={'width': 1920, 'height': 1080}, # 固定视口大小,保证一致性 device_scale_factor=2 # 视网膜屏高清截图 ) for url in URL_LIST: try: page = context.new_page() # 设置超时和重试 page.goto(url, wait_until='networkidle', timeout=30000) # 生成安全的文件名 domain = url.split('//')[1].replace('/', '_').replace(':', '_') filename = f"screenshots/{timestamp}_{domain}.png" page.screenshot(path=filename, full_page=True, animations='disabled') # 禁用动画,截图更稳定 print(f"✅ 已截图: {filename}") page.close() except Exception as e: print(f"❌ 截图失败 {url}: {e}") browser.close() # 每天上午9点执行一次 schedule.every().day.at("09:00").do(capture_screenshots) print("定时截图任务已启动...") while True: schedule.run_pending() time.sleep(60)

场景二:对比测试与视觉回归开发新功能后,需要确保UI没有意外变化。你可以将新版本的截图与基线(baseline)图片进行像素级对比。

from playwright.sync_api import sync_playwright from PIL import Image, ImageChops import os def visual_regression(url, baseline_path, new_path, diff_path, threshold=0.01): """ 视觉回归测试 :param threshold: 容差阈值,差异像素占比超过此值则认为失败 """ # 1. 捕获新版本截图 with sync_playwright() as p: browser = p.chromium.launch(headless=True) page = browser.new_context().new_page() page.goto(url, wait_until='networkidle') page.screenshot(path=new_path, full_page=True) browser.close() # 2. 与基线图对比 if not os.path.exists(baseline_path): print(f"⚠️ 基线图不存在,将当前图保存为基线: {baseline_path}") os.rename(new_path, baseline_path) return True, "Baseline created" baseline_img = Image.open(baseline_path).convert('RGB') new_img = Image.open(new_path).convert('RGB') # 计算差异 diff_img = ImageChops.difference(baseline_img, new_img) diff_bbox = diff_img.getbbox() # 获取有差异的区域边界 if diff_bbox is None: print("✅ 视觉对比通过,无差异。") return True, "No difference" # 计算差异像素比例 diff_pixels = sum(diff_img.point(lambda x: 255 if x else 0).convert('L').point(bool).getdata()) total_pixels = baseline_img.size[0] * baseline_img.size[1] diff_ratio = diff_pixels / total_pixels if diff_ratio <= threshold: print(f"✅ 视觉对比通过,差异比例 ({diff_ratio:.4%}) 低于阈值 ({threshold:.2%})。") return True, f"Difference within threshold ({diff_ratio:.4%})" else: # 保存高亮显示差异的图片 highlight = diff_img.convert('L').point(lambda x: 255 if x > 30 else 0) # 阈值化 baseline_img_copy = baseline_img.copy() baseline_img_copy.paste(Image.new('RGB', baseline_img.size, (255, 0, 0)), mask=highlight) baseline_img_copy.save(diff_path) print(f"❌ 视觉对比失败!差异比例: {diff_ratio:.4%},差异图已保存至: {diff_path}") return False, f"Difference exceeded threshold ({diff_ratio:.4%})" # 使用示例 result, message = visual_regression( url='https://your-app.com', baseline_path='baselines/homepage.png', new_path='current/homepage.png', diff_path='diffs/homepage_diff.png', threshold=0.005 # 0.5%的差异容忍度 )

实操心得:视觉回归测试的关键在于一致性。必须确保每次截图的环境完全相同:相同的浏览器版本、相同的视口大小、相同的系统缩放比例(deviceScaleFactor),甚至要禁用动画和随机内容。建议在Docker容器中运行此类任务,以隔离环境变量。

5.3 处理复杂页面的截图挑战

现代网页充满了动态内容、懒加载和弹窗,直接截图常常不完整。

挑战一:懒加载(Lazy Load)页面滚动到下方时,图片才加载。full_page=True会自动滚动,但可能滚动太快,图片来不及加载。

解决方案:在截图前,模拟人工滚动,并给予足够等待时间。

def capture_lazy_load_page(page, url): page.goto(url, wait_until='domcontentloaded') # 获取页面总高度 total_height = page.evaluate("document.body.scrollHeight") viewport_height = page.viewport_size['height'] # 分段滚动 for i in range(0, total_height, viewport_height): page.evaluate(f"window.scrollTo(0, {i})") page.wait_for_timeout(500) # 每次滚动后等待500ms加载内容 # 滚回顶部再截全图,确保顶部状态一致 page.evaluate("window.scrollTo(0, 0)") page.wait_for_timeout(1000) return page.screenshot(path='lazy_loaded.png', full_page=True)

挑战二:悬浮弹窗与固定元素某些弹窗(如Cookie提示、订阅框)会遮挡主要内容。

解决方案一:在截图前关闭或隐藏它们。

# 方法1:通过JavaScript直接移除元素 page.evaluate("""() => { const popup = document.querySelector('.cookie-banner'); if (popup) popup.remove(); }""") page.screenshot(path='no_popup.png') # 方法2:通过Playwright点击关闭按钮(更模拟用户行为) close_button = page.locator('button:has-text("Accept")') # 或 'button:has-text("Close")' if close_button.is_visible(): close_button.click() page.wait_for_timeout(300) # 等待弹窗消失动画

解决方案二:调整截图区域,避开固定元素。

# 获取某个固定头部的高度 header_height = page.evaluate("""() => { const header = document.querySelector('header.fixed'); return header ? header.offsetHeight : 0; }""") # 截取页面除头部之外的部分 page.screenshot(path='content_only.png', clip={ 'x': 0, 'y': header_height, 'width': page.viewport_size['width'], 'height': page.viewport_size['height'] - header_height })

6. 常见问题排查与性能优化

即使工具强大,在实际项目中还是会遇到各种“坑”。这里记录了我遇到的一些典型问题及解决方案。

6.1 元素定位失败:最常见的问题

症状page.click(‘button’)报错TimeoutError: Timeout 30000ms exceeded

排查步骤

  1. 确认元素是否存在:立刻打开浏览器开发者工具,检查你的选择器是否能唯一匹配到目标元素。Playwright提供了一个超好用的调试命令playwright codegen,可以打开一个浏览器并录制你的操作生成代码,同时显示它推荐的选择器。
  2. 检查等待状态:页面可能还没加载完。在操作前增加page.wait_for_load_state(‘networkidle’)page.wait_for_selector(‘your-selector’)
  3. 元素是否被遮挡?有些元素可能被其他透明层或弹窗覆盖。使用page.locator(‘button’).click(force=True)可以强制点击,但不推荐,因为这不符合真实用户行为。更好的办法是找出并关闭遮挡物。
  4. iframe问题:如果元素在iframe内部,你必须先切换到对应的iframe上下文。
    # 通过名称或URL定位iframe frame = page.frame(name='login-frame') # 或 page.frame(url=‘**/login**') # 然后在frame对象上操作 frame.fill(‘#username’, ‘user’)

6.2 截图不完整或颜色异常

症状:截图缺少部分内容,或者颜色与浏览器中看到的不一致。

解决方案

  • 内容缺失:确保使用了full_page=True。如果仍有缺失,可能是懒加载问题,参考5.3节的滚动等待方案。
  • 颜色异常(深色模式/透明背景):默认截图背景是透明的。如果保存为PNG并在白色背景的图片查看器中查看,深色文字会显得很奇怪。可以通过omit_background选项设置白色背景。
    page.screenshot(path=‘page.png’, full_page=True, omit_background=True)
  • 高清截图:需要高DPI截图用于印刷或展示时,设置device_scale_factor
    context = browser.new_context(device_scale_factor=2) # 2倍高清 page = context.new_page()

6.3 性能优化:让脚本跑得更快更稳

当需要处理成百上千个页面时,性能至关重要。

  1. 复用浏览器实例:绝对不要在循环内部launchclose浏览器。始终在外部启动一次浏览器,在循环内只创建新的上下文和页面。
  2. 并行执行:使用asyncioconcurrent.futures实现并行截图/测试。每个任务应使用独立的BrowserContext,这是线程安全的。
    import concurrent.futures from playwright.sync_api import sync_playwright def capture_one(url, context): page = context.new_page() page.goto(url) # ... 截图逻辑 ... page.close() return url with sync_playwright() as p: browser = p.chromium.launch(headless=True) # 创建多个上下文供并行使用 contexts = [browser.new_context() for _ in range(4)] # 假设并行度为4 urls = [‘url1‘, ‘url2‘, ...] with concurrent.futures.ThreadPoolExecutor(max_workers=4) as executor: # 将URL和上下文映射到任务 future_to_url = {executor.submit(capture_one, url, contexts[i%4]): url for i, url in enumerate(urls)} for future in concurrent.futures.as_completed(future_to_url): url = future_to_url[future] try: result = future.result() print(f“Done: {result}“) except Exception as exc: print(f“{url} generated an exception: {exc}“) browser.close()
  3. 合理配置浏览器启动参数:禁用不必要的功能可以节省资源。
    browser = p.chromium.launch( headless=True, args=[ ‘--disable-gpu‘, ‘--disable-dev-shm-usage‘, # 在Docker等受限环境中有用 ‘--no-sandbox‘, ‘--disable-setuid-sandbox‘, ‘--disable-extensions‘, ] )
  4. 监控与日志:对于长时间运行的任务,记录详细的日志,包括每个页面的开始/结束时间、状态和任何错误。这有助于定位性能瓶颈和失败原因。

6.4 在CI/CD环境中运行

在GitHub Actions、GitLab CI或Jenkins等无头环境中运行Playwright,需要确保系统依赖已安装。

使用官方Docker镜像是最简单可靠的方式

# Dockerfile FROM mcr.microsoft.com/playwright/python:v1.40.0-noble WORKDIR /app COPY requirements.txt . RUN pip install -r requirements.txt COPY . . CMD [“python“, “your_script.py“]

在GitHub Actions中的配置示例

name: Playwright Tests on: [push] jobs: test: runs-on: ubuntu-latest container: image: mcr.microsoft.com/playwright/python:v1.40.0-noble steps: - uses: actions/checkout@v3 - name: Install dependencies run: pip install -r requirements.txt - name: Run tests run: pytest - uses: actions/upload-artifact@v3 if: always() # 即使测试失败也上传 with: name: playwright-report path: test-results/ # 假设pytest输出报告到这里

7. 进阶应用场景拓展

掌握了基础和问题排查后,Playwright还能玩出更多花样。

7.1 自动化性能审计

结合Playwright的page.metricspage.evaluate,可以自动化收集关键性能指标。

def measure_performance(page, url): page.goto(url, wait_until='networkidle') # 获取Performance Timing API数据 timing = page.evaluate("""() => { const perf = performance.timing; return { dns: perf.domainLookupEnd - perf.domainLookupStart, connect: perf.connectEnd - perf.connectStart, ttfb: perf.responseStart - perf.requestStart, // 首字节时间 domReady: perf.domContentLoadedEventEnd - perf.navigationStart, load: perf.loadEventEnd - perf.navigationStart, }; }""") # 获取Lighthouse兼容的指标(需在非无头模式下,且Chrome DevTools Protocol支持) # 更简单的方式是直接调用 page.evaluate 执行 PerformanceObserver cls, fid, lcp = page.evaluate("""() => { // 这里是一个简化示例,实际收集CLS、FID、LCP需要更复杂的代码 return new Promise(resolve => { new PerformanceObserver((entryList) => { const entries = entryList.getEntries(); // ... 处理逻辑 ... resolve([cls, fid, lcp]); }).observe({entryTypes: ['layout-shift', 'first-input', 'largest-contentful-paint']}); }); }""") return {**timing, ‘cls‘: cls, ‘fid‘: fid, ‘lcp‘: lcp}

7.2 生成PDF报告

Playwright可以直接将网页保存为PDF,格式完美,支持打印样式。

page.goto(‘https://example.com/report‘, wait_until=‘networkidle‘) page.pdf( path=‘report.pdf‘, format=‘A4‘, print_background=True, # 打印背景色和图片 margin={‘top‘: ‘1cm‘, ‘right‘: ‘1cm‘, ‘bottom‘: ‘1cm‘, ‘left‘: ‘1cm‘} )

7.3 模拟复杂用户交互流

测试一个多步骤的表单提交或购物流程。

# 模拟一个完整的购物流程 def test_checkout_flow(page): page.goto(‘https://shop.example.com‘) # 搜索商品 page.fill(‘[aria-label="Search"]‘, ‘Playwright Book‘) page.press(‘[aria-label="Search"]‘, ‘Enter‘) # 等待结果并点击第一个商品 page.wait_for_selector(‘.product-item‘) page.locator(‘.product-item‘).first.click() # 加入购物车 page.click(‘text=Add to Cart‘) # 去结算 page.click(‘#cart-icon‘) page.click(‘text=Proceed to Checkout‘) # 填写配送信息 page.fill(‘#shipping-name‘, ‘John Doe‘) # ... 填写更多字段 ... # 选择支付方式并下单 page.click(‘#credit-card-option‘) page.click(‘text=Place Order‘) # 验证订单成功 expect(page.locator(‘h1‘)).to_contain_text(‘Order Confirmed‘)

这个流程涵盖了导航、搜索、列表操作、表单填写、多页面跳转和最终断言,是一个完整的端到端(E2E)测试案例。通过合理组织这样的测试用例,你可以构建起一个覆盖核心业务流的自动化测试堡垒,确保每一次代码提交都不会破坏关键功能。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/5 9:43:25

医疗健康营销破局:知识管理+Plone+KARL实战指南

1. 项目概述&#xff1a;当医院营销人开始焦虑&#xff0c;我们真正该担心的不是预算&#xff0c;而是思维惯性上个月在奥兰多参加第17届医疗健康营销策略峰会时&#xff0c;我站在展台后观察了整整三天。不是看自己摊位前的人流&#xff0c;而是看参会者手机屏幕的光——那微弱…

作者头像 李华
网站建设 2026/7/5 9:41:16

Nginx国密HTTPS实战:SM2双证书部署与TongSuo编译指南

1. 项目概述与背景最近在给一个金融行业的客户做系统升级&#xff0c;核心要求之一就是实现HTTPS的“国密化”改造。简单来说&#xff0c;就是把我们熟悉的、基于RSA/ECC算法的国际标准SSL/TLS&#xff0c;替换成符合我国密码管理局&#xff08;国密局&#xff09;标准的SM2/SM…

作者头像 李华
网站建设 2026/7/5 9:39:18

Java实现RC4流加密算法:从原理到安全实践

1. 项目概述&#xff1a;为什么今天还要聊RC4&#xff1f;在Java开发者的日常里&#xff0c;加密解密是个绕不开的话题。从用户密码的存储&#xff0c;到API接口数据的传输&#xff0c;再到配置文件的安全&#xff0c;处处都需要可靠的加密方案。你可能用过AES、DES&#xff0c…

作者头像 李华
网站建设 2026/7/5 9:38:50

构建主动防御体系:从ATTCK框架到代码实战的网络安全防渗透指南

1. 项目概述&#xff1a;从被动防御到主动对抗在当前的数字环境中&#xff0c;谈论网络安全已经不再是“要不要做”的问题&#xff0c;而是“如何做得更有效、更主动”的生存之战。我见过太多团队&#xff0c;他们的安全策略还停留在安装防火墙、定期打补丁的初级阶段&#xff…

作者头像 李华
网站建设 2026/7/5 9:37:09

Python自动化测试提速3倍:pytest高级技巧与CI/CD实战

1. 项目概述&#xff1a;为什么你的自动化测试需要“提速”&#xff1f; 如果你是一名Python开发者&#xff0c;或者正在学习自动化测试&#xff0c;那么“写测试”这件事&#xff0c;大概率是你开发流程里那个“不得不做但又有点烦”的环节。我们常常听到这样的抱怨&#xff1…

作者头像 李华
网站建设 2026/7/5 9:37:07

大数定律:普通人做对决策的底层思维工具

1. 这不是数学课&#xff0c;是帮你拿稳生活决策权的底层工具“大数定律”这四个字听起来像教科书里蒙着灰的公式&#xff0c;但其实它每天都在你手机里、账单上、体检报告中悄悄发号施令。我做数据咨询十年&#xff0c;见过太多人因为没真正吃透它而踩坑&#xff1a;有人靠三场…

作者头像 李华