拓冰建站拓冰建站
首页 / 资讯中心 / 正文

从Selenium到Playwright:Web自动化测试实战指南

1. 为什么我最终抛弃了Selenium转向Playwright先聊点实际的。做Web自动化的人基本都经历过这么几个阶段最早用Selenium写用例写到怀疑人生后来接触了Puppeteer发现无头浏览器确实快但每次都要自己管浏览器实例、管页面生命周期脏活累活一大堆再后来Cypress火了一阵但它的架构决定了只能跑在自己的测试框架里想做爬虫、做UI自动化、做多标签页操作处处受制。我转投Playwright起因是一个很实际的需求要处理一套多步骤的登录流程里头有滑块验证、有动态加载的iframe、还有几个新窗口之间的跳转。用Selenium写这套流程光等元素就写了一堆显式等待跑起来还时不时因为浏览器驱动版本不匹配崩一次。后来换Playwright同样的场景代码量直接砍了一半稳定性还明显提升。这玩意儿是微软开源的底层基于Chrome DevTools Protocol目前支持Chromium、Firefox、WebKit三大内核。跟Selenium最大的区别是它不需要单独的浏览器驱动自带浏览器下载和版本管理完全不依赖WebDriver协议所有操作走CDP速度和稳定性都上了一个台阶。这个教程会从安装开始一步步带你装环境、跑起第一个脚本再到元素定位、截图、网络拦截、多页面管理这些高频场景最后结合热搜词里几个高频问题Playwright过瑞数、动态iframe、打开接入AdsPower、Linux安装、Codegen录制、MCP集成、连接Electron、跟Cypress的对比、反检测逐一拆解。基础部分适合刚接触自动化的小白进阶部分适合已经用Selenium或Puppeteer写过东西、想换框架的人。2. 安装与第一个脚本最容易踩坑的三个细节2.1 安装命令与镜像加速安装Playwright本身很简单pip install playwright一行搞定。但很多人装完卡在下一步因为Playwright需要单独下载浏览器内核。pip install playwright playwright install第二条命令会下载Chromium、Firefox、WebKit三个内核。国内网络环境下这一步经常卡在99%或者直接超时。解决办法是用国内镜像源# Windows set PLAYWRIGHT_DOWNLOAD_HOSThttps://npmmirror.com/mirrors/playwright/ playwright install chromium # Linux / macOS export PLAYWRIGHT_DOWNLOAD_HOSThttps://npmmirror.com/mirrors/playwright/ playwright install chromium如果只需要跑Chromium内核没必要把三个内核全装了playwright install chromium只装一个省时间也省磁盘。另外有个细节playwright install装的是Playwright自带的浏览器版本跟你系统里已有的Chrome是两回事二者互不干扰。如果你只想用系统已装的Chrome可以在启动浏览器时传channelchrome参数这样Playwright就不会去下载自己的Chromium了。2.2 第一个脚本启动、打开页面、截图装好之后先跑个最小脚本验证环境from playwright.sync_api import sync_playwright with sync_playwright() as p: browser p.chromium.launch(headlessFalse) # 有头模式能看到浏览器窗口 page browser.new_page() page.goto(https://example.com) page.screenshot(pathexample.png) print(page.title()) browser.close()这个脚本干了几件事创建浏览器实例、新建页面、访问URL、截图、打印标题、关闭浏览器。跑通这一步说明你的安装没问题。这里注意一个关键点Playwright有两种API模式——同步sync和异步async。同步API写起来更直观适合脚本、爬虫、简单的自动化任务异步API适合需要高并发的场景比如同时跑几十个页面。新手一律建议先用同步API等理解了事件循环之后再考虑异步优化性能。2.3 headlessTrue时截图字体缺失的问题无头模式下截图经常会遇到网页字体乱码、中文显示成方框的问题。这不是Playwright的锅是系统缺少中文字体。我在一台纯净的Linux服务器上就踩过这个坑截图出来所有中文都是□□□□。排查了半天最后发现是系统没装中文字体。解决方式# Ubuntu / Debian apt install -y fonts-noto-cjk # CentOS / RHEL yum install -y wqy-microhei-fonts wqy-zenhei-fonts装完字体后删除浏览器的缓存目录默认在~/.cache/ms-playwright下重新启动浏览器中文就正常了。这个问题非常隐蔽你在Windows本地上怎么测都没事一上服务器就翻车。3. 元素定位与等待机制Playwright让你少写八成等待代码3.1 定位器Locator与自动等待用Selenium的人最烦躁的事情就是写各种显式等待WebDriverWait(driver, 10).until(EC.element_to_be_clickable(...))。一套流程写下来等待代码占了三分之一。Playwright的定位器Locator内置了自动等待机制。当你调用click()、fill()这类操作时Playwright会自动等待元素出现在DOM中、可见、稳定且可被操作默认超时时间是30秒。举个例子点击一个动态加载出来的按钮page.get_by_role(button, name提交).click()这行代码不需要额外的等待逻辑Playwright会自动等按钮出现并可点击。如果30秒内没出现才会抛出TimeoutError。3.2 定位API的优先级我建议的定位器使用顺序是get_by_role按ARIA角色定位最推荐的方式因为它不依赖CSS类名或DOM结构页面改版也不容易挂。get_by_label定位表单输入框自动关联label标签。get_by_text按可见文本定位适合定位按钮、链接等。get_by_placeholder按占位符文本定位输入框。locator(css...)CSS选择器如果你对XPath非常熟也可以用XPath但我个人不推荐。举几个实际场景# 定位搜索框 search_box page.get_by_placeholder(请输入关键词) # 定位导航菜单里的某个链接 link page.get_by_role(link, name用户协议) # 表单提交按钮 submit_btn page.locator(button[typesubmit]) # 按文本定位精确匹配 page.get_by_text(登录, exactTrue).click()3.3 规避动态iframe的坑新版Playwright处理iframe的方式非常优雅直接用frame_locator就行了不需要像Selenium那样先switch_to_frame切来切去。frame page.frame_locator(#dynamic-iframe).locator(input[nameusername]) frame.fill(test_user)frame_locator内部会自动处理iframe加载完成、内容动态渲染这些情况它定位到的元素会自动等待。但是动态iframe有个非常隐蔽的问题iframe的src是异步加载的或者iframe本身是js动态创建出来的第一次访问时frame_locator可能定位不到元素。这时候最简单的解决办法是等一下或者轮询from playwright.sync_api import expect expect(page.frame_locator(#dynamic-iframe).locator(input)).to_be_visible(timeout10000)expect是Playwright的断言方法作用是等待某个条件成立。把超时时间放宽到10秒动态生成的iframe内元素基本都能等到。3.4 等待页面完全加载什么时候别等networkidle很多人写爬虫时习惯用page.wait_for_load_state(networkidle)即等待页面所有网络请求结束。但我要提醒你对于现代网页来说networkidle可能永远等不到因为页面会有持续的心跳请求、埋点上报、轮询接口。我的建议是放弃networkidle改用以下策略中的一种# 等待某个关键元素出现 page.locator(#content-loaded).wait_for() # 或者直接操作让Playwright的自动等待去处理 page.get_by_text(加载完成).click()尽量少用固定的sleep因为sleep时间短了不稳定长了浪费时间。Playwright内置的自动等待已经覆盖了绝大多数场景。4. 高频实战场景截图、网络拦截、多标签页、上下文隔离4.1 全页截图与元素截图截图是Playwright的强项一行代码搞定而且支持全页截图自动滚动拼接和元素级截图。# 全页截图页面太长时自动滚动拼接 page.screenshot(pathfullpage.png, full_pageTrue) # 元素截图 element page.locator(.article-content) element.screenshot(pathelement.png) # 指定视口大小截图 page.set_viewport_size({width: 1920, height: 1080})在无头模式下做整页截图时有个细节页面上有懒加载图片的滚动太快图片可能来不及加载。解决办法是全页截图前先执行一段JavaScript把页面滚动一遍page.evaluate( async () { await new Promise((resolve) { let totalHeight 0; const distance 100; const timer setInterval(() { const scrollHeight document.body.scrollHeight; window.scrollBy(0, distance); totalHeight distance; if (totalHeight scrollHeight) { clearInterval(timer); resolve(); } }, 100); }); } ) # 滚动完后再截图 page.screenshot(pathfullpage.png, full_pageTrue)4.2 网络请求拦截与Mock数据Playwright的route方法可以拦截和修改网络请求这在测试中非常有用。比如你不想等某个慢接口直接Mock掉或者想收集页面发出的所有API请求。拦截并放行打印请求信息def on_request(request): if request.resource_type xhr or request.resource_type fetch: print(request.method, request.url) page.on(request, on_request)拦截并直接返回Mock数据不请求服务器def handle_route(route): route.fulfill( status200, content_typeapplication/json, body{code: 0, data: {token: mock_token}} ) page.route(**/api/login, handle_route)这个能力在做前端自测时特别有用。我有个习惯所有依赖第三方接口的自动化用例一律Mock掉外部依赖只测前端页面的交互逻辑。这样用例就不会因为外部接口超时而跑挂。route还能做资源屏蔽比如屏蔽图片和样式表的加载来加速爬虫page.route(**/*.{png,jpg,jpeg,gif,webp}, lambda route: route.abort()) page.route(**/*.{css,woff,woff2}, lambda route: route.abort())实测下来屏蔽图片和CSS后简单页面加载速度能提升30%-50%。4.3 多标签页与多页面管理操作浏览器打开新标签页传统方案是先获取当前页面的target然后切换到新targetPlaywright的思路不一样——它直接监听新页面事件。with page.expect_popup() as popup_info: page.click(a[target_blank]) new_page popup_info.value new_page.wait_for_load_state()这段代码的逻辑是点击一个会打开新窗口的链接然后等待新页面出现返回的popup_info.value就是新页面的Page对象。这样在多页面跳转的时候你不需要不断切换上下文每个Page对象都是独立控制的。多页面并行操作时可以用asyncio async APIimport asyncio from playwright.async_api import async_playwright async def crawl_url(browser, url): page await browser.new_page() await page.goto(url) title await page.title() await page.close() return title async def main(): async with async_playwright() as p: browser await p.chromium.launch() urls [https://example.com, https://example.org] titles await asyncio.gather(*[crawl_url(browser, url) for url in urls]) print(titles) asyncio.run(main())这个例子同时开启了两个页面分别抓取实际可以扩展成几十个并发任务。单机开几十个Chromium页面只要机器内存够速度比串行快一个数量级。4.4 浏览器上下文Context隔离会话的利器这是Playwright非常核心的概念也是我特别想强调的。Context浏览器上下文相当于一个独立的浏览器会话。同一个Context内的页面共享cookies、localStorage不同的Context之间完全隔离互不干扰。context1 browser.new_context() context2 browser.new_context() page1 context1.new_page() page2 context2.new_page() # page1登录了page2不受影响 page1.goto(https://example.com/login) page1.fill(input[nameusername], user1) page1.fill(input[namepassword], pass1) page1.click(button[typesubmit]) # page2仍然是未登录状态这个特性的价值在于你可以一次启动浏览器开多个隔离的会话环境配合代理的话每个上下文还可以绑定不同IP。对于需要多账号并行操作的场景比如批量处理用Context隔离是最干净的做法不需要反复启动/关闭浏览器。5. 反检测与指纹控制网站如何检测到被自动化控制5.1 网站常用的检测思路很多网站会对自动化脚本做拦截。它们怎么识别你是真人还是脚本主要看几类特征WebDriver属性Selenium时代的navigator.webdriver永远是true这是最经典的检测点。浏览器指纹自动化浏览器和真实浏览器在某些API细节上存在差异比如navigator.plugins、navigator.languages、Canvas指纹、WebGL渲染器信息等。行为特征鼠标移动轨迹、点击间隔、滚动速度是否像人。CDP痕迹如果检测端用了反自动化对抗方案会扫描页面里是否开启了DevTools协议的关键调用特征。Playwright没有把navigator.webdriver设为true默认是false这是一大优势但想完全模拟真实用户行为还需要做额外的操作。5.2 隐藏自动化特征先说结论普通网站的检测Playwright默认就能通过遇到硬核的瑞数、加固风控一类的方案热搜词里提到的Playwright过瑞数就不是改两个参数能搞定的了要专门讲。基础层面推荐做这几件事from playwright.sync_api import sync_playwright with sync_playwright() as p: browser p.chromium.launch( headlessFalse, args[ --disable-blink-featuresAutomationControlled, --disable-automation, ] ) context browser.new_context( user_agentMozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36, viewport{width: 1920, height: 1080}, localezh-CN, timezone_idAsia/Shanghai, ) page context.new_page()这里做了几件事--disable-blink-featuresAutomationControlled这个参数会去掉Blink内核中开发者是否通过自动化控制的标志位也是目前绕过大量检测脚本的关键参数之一。自定义user_agent模拟真实Chrome的UA避免默认UA被识别。设置locale和timezone_id如果目标站点是中文的这些值要跟真实用户一致不然navigator.language暴露。更彻底的做法是在页面初始化前注入一段JavaScript来剔除navigator.webdriver属性context.add_init_script( Object.defineProperty(navigator, webdriver, { get: () undefined }); )add_init_script会在每个新页面加载前执行相当于在页面任何脚本运行之前就把webdriver属性改掉了。实测这一招能过掉很多基础检测。5.3 指纹兜底方案如果目标站点的风控更严格你还需要处理Canvas指纹、WebGL、字体列表等更细粒度的指纹信息。这个方向有两个主流方案Playwright的stealth插件社区有人做了playwright-stealth原理跟Puppeteer的stealth插件类似在add_init_script里做了几十项指纹修补。指纹浏览器接入也就是AdsPower这类工具。用Playwright打开AdsPower里配置好的浏览器环境你可以直接获得真实浏览器指纹和独立的代理IP然后用CDP接入。基础做法是装一个stealthpip install playwright-stealthfrom playwright_stealth import stealth_sync with sync_playwright() as p: browser p.chromium.launch() page browser.new_page() stealth_sync(page) page.goto(https://example.com)5.4 关于过瑞数这类重度风控的现状关于Playwright过瑞数这个热搜词我说点实际的。瑞数这类动态安全方案的原理是前端生成动态Token每次请求都要带不同的加密参数而且它会在页面加载时用JavaScript重新改写自身代码检测环境是否被自动化控制。这类方案靠简单的add_init_script根本绕不过去因为它检测的不只是单个属性而是整个运行时环境的一致性。我见过不少人在问有没有一个参数直接过瑞数统一回复没有银弹。常规思路是用真实的指纹浏览器环境AdsPower等作为运行载体直接复用其指纹用Playwright只做操作不做伪装——所有伪装在前置环节完成必要时候配合代理IP池使用。拿热搜词里playwright打开调用adspower来说AdsPower支持通过本地端口启动一个浏览器实例然后用Playwright通过CDP连接这个实例复用它的指纹。具体思路from playwright.sync_api import sync_playwright # 假设AdsPower已通过API在本地9999端口启动了一个浏览器实例 with sync_playwright() as p: browser p.chromium.connect_over_cdp(http://127.0.0.1:9999) context browser.contexts[0] page context.new_page() page.goto(https://example.com)connect_over_cdp可以直接接管由AdsPower启动的Chrome浏览器操作方式和本地创建的浏览器一模一样。这就实现了AdsPower负责提供干净的IP和指纹Playwright负责自动化操作。两者各司其职。6. Codegen录制先用录制器跑通流程再优化代码6.1 录制器的正确使用方式Playwright自带录制器codegen它能在可视窗口中记录你的操作并自动生成代码。这功能常被低估其实它不只是给小白用的老手做复杂流程时也会先录制一遍拿到基础代码再手动优化。启动方式playwright codegen https://example.com运行后会弹出两样东西一个浏览器窗口、一个代码生成面板。你在浏览器里的每一步操作点击、输入、下拉选择、滑动等都会被记录下来并实时生成可运行的Python/Java/JavaScript代码。我最常用的流程是先手动录一遍核心流程生成基础脚本把生成的代码整理成函数去掉多余跳转用Playwright的expect断言替换写死的等待弱网或慢网络场景下补充超时重试逻辑。6.2 录制后必须改的三类问题codegen生成代码有个通病它会把所有元素都用CSS选择器来定位。await page.locator(body div:nth-child(2) div:nth-child(1) form input).click()这串选择器一看就脆——页面稍微改个结构就失效了。你需要手工替换成语义更稳定的定位方式await page.get_by_placeholder(请输入邮箱).fill(testexample.com)第二类要改的是缺失的断言。录制器不会自动判断哪个元素出现才代表页面加载成功你需要自己补上关键节点await expect(page.get_by_text(登录成功)).to_be_visible()第三类要改的是不必要的全页等待。录制过程如果你停顿了几秒生成代码里可能多出几个固定等待要删掉。6.3 录制器在调试中的妙用除了生成代码codegen还有个别名用法——playwright codegen可以附加到已打开的浏览器上。这个特性在排查问题时很管用。比如你在跑一个复杂脚本跑到某个页面弹出异常弹窗想知道具体是哪个元素触发的问题可以手动操作一遍页面看录制器生成了什么选择器然后在脚本里用同样的选择器去定位快速定位bug。7. Linux环境部署与Elasticsearch那类会遇到的系统依赖问题7.1 Linux下安装步骤很多人的Playwright脚本在Windows上跑得好好的部署到Linux服务器就各种报错。大多是系统依赖没装全。在干净的Linux上推荐用官方提供的一键安装方式pip install playwright playwright install --with-deps chromium--with-deps会自动安装Chromium运行所需的系统库省得一个个去翻缺少哪个.so文件。如果漏装了启动时会报类似libnss3.so: cannot open shared object file的错误原因就是某个系统共享库缺失。如果你不想用自带的依赖安装可以手动装这些基础库# Ubuntu/Debian apt install -y libnss3 libnspr4 libatk1.0-0 libatk-bridge2.0-0 libcups2 libdrm2 libxkbcommon0 libatspi2.0-0 libxcomposite1 libxdamage1 libxfixes3 libxrandr2 libgbm1 libpango-1.0-0 libcairo2 libasound27.2 无Root权限环境下的安装很多公司服务器上没有root权限这就比较麻烦。playwright install --with-deps需要sudo没有root就得自己想办法。我的经验是用虚拟环境装Python包然后手动下载浏览器到指定目录python -m venv venv source venv/bin/activate pip install playwright # 指定浏览器下载目录当前用户可写 export PLAYWRIGHT_BROWSERS_PATH$HOME/.cache/ms-playwright playwright install chromium启动时再加一个参数browser p.chromium.launch(executable_path/path/to/chrome/linux-120/chrome)executable_path可以指定浏览器可执行文件的绝对路径这样就不依赖Playwright默认的目录发现了。7.3 中文字体在服务器上的部署问题前面提到过Linux服务器上截图中文变方框是因为缺字体。这个问题分两种情况如果目标网站是中文站一定要装中文字体如果你只是跑测试不涉及截图那可以不装。但如果你是做爬虫和网页截图字体这个问题绕不开建议一开始就把fonts-noto-cjk装上避免后续截图数据缺字。8. 进阶玩法Playwright MCP、集成Electron模拟登录、与Cypress的对比8.1 Playwright MCP让AI替你操作浏览器Playwright MCP是近期社区里很火的玩法。MCPModel Context Protocol是Claude等大模型的一种工具调用协议Playwright官方发布了MCP服务允许大模型通过自然语言来操作浏览器。说白了你可以跟AI说打开某个页面搜一下某个关键词把第一条结果的标题告诉我AI会调用Playwright去执行再把结果返回给你。安装和启动方式npx playwright/mcplatest然后在你支持MCP协议的客户端比如Claude Desktop里配置好服务地址AI就能使用浏览器工具了。这个玩法目前还在快速迭代中但方向很有意思——它把人写自动化脚本变成了人描述意图AI写脚本并执行。对测试人员来说以后写端到端测试的门槛会进一步降低。不过它现在对复杂场景的稳定性和可控性还有待完善真要跑严格的回归测试还是人工写脚本更靠谱。实际使用中我遇到的一个典型场景是用OpenCode这类编码工具配合Playwright MCP让它直接去浏览器里复现一个前端bug获取控制台报错和页面相关元素状态比纯靠肉眼去测试页效率高很多。热搜词里opencode playwright 怎么测试前端bug指的就是这类用法——让智能体自己打开页面、执行交互、采集报错信息。8.2 连接Electron内嵌浏览器Electron应用内嵌了一个Chromium实例很多桌面端工具其实就是Web页面套个壳。Playwright能直接连进Electron的浏览器内核对它进行自动化操作。npm install -D playwrightfrom playwright.sync_api import sync_playwright with sync_playwright() as p: electron_app p._electron.launch(args[path/to/your-electron-app]) window electron_app.first_window() window.goto(https://example.com)这里有两个注意点Electron自动化的前提是目标应用是以Electron方式打包的且没有禁用remote debugging部分生产环境会关闭。Playwright连接Electron的操作跟你操作普通浏览器页面逻辑相同可以用所有定位器方法和断言。如果你的目标Electron应用在运行时会拉起多个窗口可以用electron_app.windows遍历所有窗口找到你需要的那个再操作。Electron窗口本质上是BrowserWindow所以内部页面的跳转、iframe、弹窗都跟普通Chromium一致。8.3 与Cypress的横向对比选型是很多人纠结的事。Cypress和Playwright都属于现代端到端测试框架但设计哲学不同。我做个简要对比维度PlaywrightCypress支持的浏览器Chromium、Firefox、WebKit仅Chromium系Firefox实验性语言Python、Java、JavaScript、.NETJavaScript/TypeScript多标签页/多窗口原生支持不支持有工作区限制iframe支持原生frame_locator需要特殊处理网络拦截/Mock原生route支持原生支持浏览器驱动自带无需额外安装自带无头模式执行速度快较快跨域场景无限制跨域受限适合爬虫等非测试场景完全适合不适合绑定测试框架结论很直接如果你的目标是纯Web测试框架、团队又正好是JS技术栈Cypress非常顺手它的断言语法和交互体验打磨得确实好。但如果你的需求超出了测试范畴——比如我要跑爬虫、要多标签页、要接外部指纹浏览器、要复用Session、要跨语言开发Playwright是明显更优的选择。而且Playwright的多浏览器支持是实打实的同一套代码可以分别跑在Chromium和WebKit上用来验证Safari的兼容性这个能力在Cypress里目前还实现不了。8.4 Playwright在Windows上遇到chrome-headless-shell.exe热搜词里有一个很具体的问题playwright chrome-headless-shell.exe。这其实是Playwright新版的一个实现细节。较新版本的Playwright在安装Chromium时会额外下载一个chrome-headless-shell二进制文件它是独立的无头浏览器壳专门用于旧版无头模式。这个文件的用途是替代原来--headless模式下加载的完整浏览器内核运行速度更快、资源占用更低。如果你在任务管理器或文件目录里看到chrome-headless-shell.exe不要慌这不是病毒是Playwright的组件之一。它出现在~/.cache/ms-playwright/chrome-headless-shell/目录下。如果你的脚本设了headlessTruePlaywright默认会选择这个轻量版无头浏览器如果你通过CDP连接到别的浏览器比如AdsPower这个文件就不会被使用。9. 断点调试与CI集成从能跑到能稳定跑9.1 用headed模式排查问题Playwright最常用的调试方式是headlessFalse有头模式还有--slow-mo参数让操作变慢方便肉眼观察。browser p.chromium.launch(headlessFalse, slow_mo500)slow_mo500表示每个操作间隔500毫秒配合page.pause()还能在关键步骤处暂停并打开Playwright的调试工具page.goto(https://example.com) page.pause() # 执行到这行会暂停弹出步进调试面板page.pause()会启动一个交互式调试面板你能看到当前页面的元素定位、网络请求、控制台日志还可以在面板里直接执行操作。另外建议在脚本里加上trace记录context browser.new_context() context.tracing.start(screenshotsTrue, snapshotsTrue) page.goto(https://example.com) context.tracing.stop(pathtrace.zip)跑完用例后生成的trace.zip可以用playwright show-trace trace.zip打开回放。回放时能看到每一步操作前后页面的DOM状态、网络请求、Console报错排查为什么这里报错效率极高。9.2 在测试框架里集成Playwright与pytest的集成非常顺畅官方提供了pytest-playwright插件。pip install pytest-playwright写测试用例时插件会自动创建page、context、browser三个fixturedef test_login(page): page.goto(https://example.com/login) page.fill(input[nameusername], test) page.fill(input[namepassword], pass) page.click(button[typesubmit]) page.get_by_text(登录成功).wait_for()在命令行运行时可以指定浏览器、无头模式等参数pytest tests --browserchromium --headed --slowmo500如果要跑多浏览器测试pytest tests --browserchromium --browserfirefox --browserwebkit一套用例同时跑三个内核对于想验证跨浏览器兼容性的前端项目非常实用。9.3 CI/CD里的稳定性策略在CI/CD环境里跑Playwright最大的敌人是环境不一致。推荐的做法是用官方Docker镜像FROM mcr.microsoft.com/playwright:v1.40.0-focal这个镜像里预装了所有浏览器内核和系统依赖直接跑测试命令就行省去了在CI机器上折腾依赖的时间。CI中还有几个提高稳定性的细节每个测试用例都应该从独立的Context开始用例之间不共享Session对超时时间的设置要有预期。CI机器的性能通常比本地差30秒默认超时可能不够可以统一放宽到45秒或60秒失败用例不要重启浏览器重试应该依赖用例代码的重试机制比如pytest-rerunfailures避免掩盖真实问题。9.4 沙箱限制下的处理热搜词里还有沙箱操作playwright。如果你把Playwright部署在Docker容器或者沙箱环境里经常会遇到一个报错Running as root without --no-sandbox is not supported解决方案是在启动参数里加上--no-sandboxbrowser p.chromium.launch(args[--no-sandbox, --disable-setuid-sandbox])如果你用的pytest插件可以直接传pytest --browserchromium --browser-channelchromium --headed --slowmo500 --sandboxfalse不过在加这个参数前你要明白它的安全性影响去掉沙箱意味着浏览器进程的安全隔离变弱在不受信任的页面上执行可能有风险。生产环境的CI/CD中尽量把浏览器跑在单独的容器里不要跟构建环境混在一起。10. 最后说点实在的Playwright这个框架我认为是当前做Web自动化的最优解之一。它并不是把Selenium的功能做了一遍重新封装而是从底层换了一套设计思路——把开发者从我到底要等多久这种无意义的问题里解放出来让代码专注于业务逻辑本身。我自己的体会是用Selenium的时候一半时间在排查为什么偶发失败元素没点上是最高频的问题换Playwright之后因为内置了自动等待和重试机制这类问题明显减少了。它在网络拦截、多页面、上下文隔离这些硬核能力上的完整度确实让人用得舒服。如果你还在纠结要不要切换我的建议是拿一个最常见的业务场景分别用Selenium和Playwright各写一版对比一下代码量和调试体验你自己就会有答案。最后分享一个实用技巧在做复杂流程自动化时先别急着把所有操作都写在一个脚本里。先拆分步骤、单独验证每步能不能跑通再组合成完整链路这样排查问题时会省很多时间。这个习惯我从Selenium时代保持到现在一直觉得是自动化脚本维护成本低的最大原因。
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门