ClaudeCode+Playwright MCP/CLI的基本使用
文章目录
Playwright
Playwright简介
Playwright 是由 Microsoft 推出的现代化 浏览器 自动化框架,支持使用代码控制真实浏览器完成用户操作。可以把它理解为一个功能强大的 Web 浏览器控制器 。允许通过一套统一的 API,用代码去自动操作 Chromium(Chrome、Edge 的内核)、Firefox 和 WebKit(Safari 的内核)这三种主流浏览器自动完成"人类的浏览器操作":打开网页、点击、输入、拖拽、上传文件、截图/PDF、录制日志与回放,最常见的用途是 端到端(E2E)测试,也可做轻量爬取与流程自动化。。
核心特性:
1.智能自动等待:这是其最核心的特性之一。当你执行 click()、fill() 等操作时,Playwright 会自动检查元素是否可见、可用、稳定,直到满足可操作状态才会执行下一步 。这几乎消除了在代码中随意添加 time.sleep() 或手工设置等待时间的需要。
2.强大的选择器引擎:它提供了多种现代化的定位方式,让选择器更易写、更健壮 。可以通过元素的语义角色和名称定位;也可以通过标签文本、占位符或测试id 等来定位,也支持传统的 CSS 和 XPath 。
3.全面的测试工具链:Playwright 不仅是一个自动化库,还自带了一套完整的测试工具 :
- Codegen(代码生成器):它会打开一个浏览器窗口和一个检查器。你在浏览器上的每一次点击、输入都会被自动转换成你指定语言的测试代码 。
- Trace Viewer(追踪查看器):当测试失败时,它可以捕获完整的执行轨迹,包括操作录屏、每一步前后的 DOM 快照、网络请求等。
- HTML 报告:测试运行后会自动生成详细的 HTML 报告,包含测试结果、耗时、错误日志和截图,方便结果分享和趋势分析 。
应用场景:
- 前端测试:自动测试网页的按钮、表单、导航等是否正常。
- 回归测试:新功能上线前,跑一遍全站测试用例,确保旧功能不出问题。
- 数据采集(爬虫):抓取动态网页(比如需要滚动才能看到的数据)。
- 网页截图 & PDF:给页面生成截图或 PDF(比如生成报告)。
- 流程自动化:自动化重复操作(如自动登录、批量表单填写)。
- 端到端(E2E)测试:模拟真实用户在关键路径上的完整操作流程,如注册、登录、下单结账等 。
- 跨浏览器测试:只需一套脚本,就能确保你的 Web 应用在 Chrome、Firefox 和 Safari 上都能正常工作,有效发现兼容性问题 。
- API 测试:它不仅限于 UI,还能直接发送请求测试后端 API,可以在 UI 测试中拦截和模拟(Mock)API 响应,用于测试各种边界情况 。
- 性能监控:定时运行 Playwright 脚本,可以测量关键页面的加载时间,对网站进行主动的“合成监控” 。
与传统工具(如 Selenium)的对比
| 功能 | Playwright | Selenium |
|---|---|---|
| 自动等待 | 内置智能等待,操作前自动等待元素就绪 | 需手动设置等待时间,脚本易不稳定 |
| 跨浏览器支持 | 一套 API 无缝支持 Chromium, Firefox, WebKit | 支持,但各浏览器需单独驱动,配置繁琐 |
| 测试执行速度 | 快速,通过 WebSocket 直接控制浏览器,支持原生并行 | 较慢,基于 HTTP 的 WebDriver 协议有额外开销 |
| 支持语言 | 官方支持 JS/TS, Python, Java, .NET | 支持 Java, Python, C#, Ruby, JS 等 |
| 核心功能与生态 | 功能全面且强大:丰富内置,如网络拦截、移动端模拟、Trace 查看器等,提供 Trace Viewer 和 Codegen 等工具,生态由微软公司维护 | 功能基础:多需依赖第三方库或插件,调试相对传统,多依赖日志和截图,生态成熟,社区庞大 |
Playwright快速入门
下文中Playwright特指Playwright for python(Playwright 官方为 Python 语言提供的库,可以用 Python 代码来无缝控制 Chromium、Firefox 和 WebKit 浏览器,实现 Web 自动化 )
环境准备:
- 安装python,Playwright内部使用异步(async/await)写法,所以需要python3.7及以上版本
官网地址:https://www.python.org/downloads/
- 安装Playwright
单独安装Playwright
pip install playwright
同时安装Playwright和pytest
pip install pytest-playwright
- 安装浏览器
Playwright需要使用特定的浏览器,这些浏览器的Playwright进行了编译并提供下载,安装命令:
playwright install #安装所有支持的浏览器
playwright install chrome # 只安装chrome浏览器
Codegen一个交互式的代码生成器,能将浏览器中的操作实时输出为Playwright代码
在pycharm终端启动Codegen命令:
playwright codegen url # url可以是任何想测试的网站
如:百度登录页面
playwright codegen https://passport.baidu.com/v2/?login
执行命令后将会出现两个窗口:
浏览器窗口:在次窗口中的所有操作(点击、输入、选择等)都将被记录,可以完全模拟用户操作
Playwright Inspector窗口:实时显示操作所对应的Playwright Python代码
添加断言
Codegen无法自动记录断言,可通过Inspector按钮添加断言:
- Assert visibility:断言元素的可见
- Assert text:断言元素的text属性
- Assert value:断言元素的value属性
Codegen应用场景:
- API学习:当不确定某个操作应用那个API时,手动操作一遍,Codegen会给出标准答案;
- 定位器探索:当在浏览器中移动鼠标时,Codegen会高亮元素并提示推荐的定位器策略;
- 快速原型开发:快速录制一个完整的业务流程,将生成的代码作为测试用例的初始框架,再进行后续的优化和封装。
Playwright API应用
Playwright最核心的三个对象:
- Browser:一个 Browser 实例代表了一个实际的浏览器,例如 Chromium、Firefox 或 WebKit;
- BrowserContext:一个 BrowserContext 就像一个独立的浏览器会话。它完全隔离了页面、本地存储、cookies 等数据。可以在一个浏览器中同时运行多个互不影响的自动化任务;
- Page:进行实际操作的地方。代表了浏览器上下文中的一个标签页或窗口。所有的操作,如点击、输入、导航、截图等,都是在 Page 对象上执行的。
同步/异步
- 同步模式 (sync_api):代码会按照顺序一行一行地执行,等前一个操作(如打开网页)完全结束后,才会执行下一个操作。它的优点是简单直观,容易上手。
from playwright.sync_api import sync_playwright
def run_sync():
with sync_playwright() as p: # 使用同步with语句管理上下文
browser = p.chromium.launch(headless=False) # 无头模式浏览器启动
page = browser.new_page() # 创建 Page 对象
page.goto('https://example.com') # 页面基本导航
browser.close() # 关闭浏览器
run_sync()
- 异步模式 (async_api):代码可以在等待一个操作(如页面加载)的同时,转而去执行另一个任务。它的优点是效率高,特别适合需要同时处理多个浏览器操作的场景。
import asyncio
from playwright.async_api import async_playwright
async def run_async():
async with async_playwright() as p: # 使用异步with语句管理上下文
browser = await p.chromium.launch(headless=False) # 无头模式浏览器启动 需要await
page = await browser.new_page() # 创建 Page 对象 需要await
await page.goto('https://example.com') # 页面基本导航 需要await
await browser.close() # 关闭浏览器 需要await
asyncio.run(run_async())
对于绝大多数测试脚本和自动化任务,选择同步模式就足够了,简单、直接、不容易出错。
with 语句
在 Playwright 中,with 语句(上下文管理器)会自动处理浏览器实例和 Playwright 进程的创建与销毁,确保资源被正确释放,避免内存泄漏。
from playwright.sync_api import sync_playwright
with sync_playwright() as p: # 使用with管理playwright的整个生命周期
# 这里的p是PlaywrightContextManager对象
browser = p.chromium.launch()
page = browser.new_page()
page.goto('https://example.com')
print(page.title())
browser.close() # 退出with块后,playwright进程自动关闭
浏览器启动
#各种浏览器启动选项
browser = playwright.chromium.launch(
headless=False, # 显示浏览器界面
slow_mo=100, # 操作间延迟(毫秒)
args=['--start-maximized'], # 浏览器参数
executable_path='/path/to/chrome', # 指定浏览器路径
timeout=30000, # 超时时间
devtools=True, # 打开开发者工具
proxy={
'server': 'http://proxy.example.com:8080',
'username': 'user',
'password': 'pass'
}
)
等待策略
#等待元素出现
page.wait_for_selector('#element-id', timeout=10000)
#等待特定条件
page.wait_for_function('document.querySelector(".content").innerText.includes("Hello")')
#等待超时
page.wait_for_timeout(3000) # 等待3秒
#等待导航完成
with page.expect_navigation():
page.click('a#submit')
#等待弹出窗口
with page.expect_popup() as popup_info:
page.click('a[target="_blank"]')
popup = popup_info.value
等待策略多用于调试、爬取数据,测试使用场景较少,因Playwright存在自动等待,如fill方法默认等待最大时间30秒:

页面交互
- 页面导航
#基本导航
page.goto('https://example.com')
#带选项的导航
page.goto('https://example.com',
timeout=30000, # 超时时间
wait_until='networkidle', # 等待条件:'load'|'domcontentloaded'|'networkidle'
referer='https://google.com' # 设置referer
)
#导航事件处理
page.on('load', lambda: print('Page loaded!'))
#前进和后退
page.go_back()
page.go_forward()
#重新加载
page.reload()
- 页面状态
#获取当前页面URL
current_url = page.url
#获取当前页面标题
page_title=page.title()
#获取完整的页面HTML内容
content = page.content()
- 页面动作
#设置页面的视口大小
page.set_viewport_size({"width":375,"height":812})
#捕获当前页面的截图
page.screenshot(path="screenshots/login")
#截取整个可滚动页面的完整长图,关键参数full_page=True
page.screenshot(path="screenshots/login_full",full_page=True)
#在页面上下文中执行一段JavaScript表达式并返回其结果
page.evaluate(localStorage.getItem("access_token"))
元素定位
Locator定位器的特性:
- 惰性定位:
Playwright使用Locator定位元素,但只有当该元素需要执行一个动作或断言时,才会根据Locator内容去页面上寻找匹配的元素。
- 自动等待:
当Locator去页面上寻找元素时,当元素自动等待以下状态就绪,确保寻找到的元素可以进行使用:
- Attached(已附加):元素已存在于DOM树中;
- Visible(可见):元素及其祖先没有display:none或visibility:hidden等样式,且尺寸不为零;
- Stable(稳定):元素已停止动画或过渡效果,位置固定;
- ReceivesEvents(可接受事件):元素没有被其他元素遮挡,能够接收鼠标点击;
- Enable(已启用):元素不是disabled状态;
- Editable(可编辑):对于输入动作,元素必须是可编辑状态。
面向用户定位:基于可访问性(Accessibility)信息,模拟真实用户的感知方式
- Role定位 get_by_role() 通过元素的ARIA角色和可访问名称定位,最健壮、不受DOM结构变化影响。
#定位"登录"按钮
page.get_by_role("button", name="登录").click()
#定位文本输入框(通过关联的标签)
page.get_by_role("textbox", name="用户名").fill("myuser")
#定位标题
page.get_by_role("heading", name="欢迎回来", level=1)
- Label定位 get_by_label() 通过关联的
#定位"邮箱地址"对应的输入框
page.get_by_label("邮箱地址")
- 文本定位 get_by_text() 通过元素的可见文本内容定位,适合按钮、链接等。
#精确匹配
page.get_by_text("提交")
#模糊匹配(包含)
page.get_by_text("商品", exact=False)
#正则匹配
page.get_by_text(/确认.*/)
- 占位符定位 get_by_placeholder() 通过placeholder属性定位输入框输入框专用。
page.get_by_placeholder("请输入手机号")
- Alt文本定位get_by_alt_text()通过alt属性定位元素,通常是图像。
page.get_by_alt_text("产品图片")
- Title定位get_by_title()通过title属性定位元素。
page.get_by_title("用户头像")
面向结构定位:当用户定位方式不适用时使用的备选方案,依赖DOM结构。
- 测试ID定位 get_by_test_id()需要开发配合在元素上添加data-testid属性,完全隔离UI变化影响,稳定的结构定位。
#HTML: <button data-testid="login-submit">登录</button>
page.get_by_test_id("login-submit").click()
- CSS选择器 locator()灵活但易受样式变化影响。
#ID定位
page.locator("#username")
#类名定位
page.locator(".product-item")
#属性定位(支持模糊匹配)
page.locator('input[type="text"]')
page.locator('[class*="btn-primary"]') # 包含
page.locator('[id^="input-"]') # 开头匹配
- XPath定位强大但脆弱,维护成本高,作为最后手段。
#文本匹配
page.locator("xpath=//button[text()='登录']")
#组合条件
page.locator("xpath=//input[@type='checkbox' and @checked='true']")
高级定位技巧
- 组合定位(链式调用)从父元素出发定位子元素,提高精确度。
#先定位商品列表容器,再找具体商品
product_list = page.locator("ul.product-list")
products = product_list.locator("li.item")
#根据包含文本过滤
await page
.get_by_role("row")
.filter(has_text="待付款")
.get_by_role("button", name="支付")
.click()
- 可见性过滤,只操作可见元素。
#只点击可见的按钮
page.locator("button:visible:has-text('提交')").click()
- 包含关系定位,定位包含特定子元素的父元素。
#定位包含"特惠"标签的商品卡片
discount_product = page.locator('div.product:has(span.discount:has-text("特惠"))')
- 列表元素处理
#获取所有匹配元素
items = page.locator(".list-item")
count = items.count() # 获取数量
#遍历处理
for i in range(count):
item = items.nth(i)
print(item.text_content())
#取第一个/最后一个
first = items.first()
last = items.last()
- iframe定位
#切换到iframe内定位
frame = page.frame_locator("iframe#payment-frame")
frame.locator("input#card-number").fill("1234")
- 动态元素处理
#等待元素出现再操作
page.wait_for_selector(".modal-content", state="visible")
#使用locator的自动等待特性
locator = page.locator(".dynamic-element")
locator.click() # 自动等待直到可操作
元素交互
#点击操作
page.click('button')
page.dblclick('button')
page.click('button', button='right') # 右键点击
page.click('button', modifiers=['Shift']) # 带修饰键点击
#输入操作
page.fill('input#name', 'John Doe')
page.type('input#name', 'Hello World', delay=100) # 模拟按键延迟
#选择操作
page.select_option('select#colors', 'red')
page.select_option('select#colors', index=1) # 按索引选择
page.select_option('select#colors', value=['red', 'blue']) # 多选
#复选框和单选按钮
page.check('input#agree')
page.uncheck('input#subscribe')
#文件上传
page.set_input_files('input[type=file]', 'path/to/file.txt')
page.set_input_files('input[type=file]', ['file1.txt', 'file2.txt']) # 多文件
#聚焦和模糊
page.focus('input#search')
page.blur('input#search')
#悬停
page.hover('div.menu-item')
#拖放
page.drag_and_drop('#source', '#target')
高级交互
- 键盘操作
#键盘输入
page.keyboard.type('Hello World!')
page.keyboard.press('Enter')
page.keyboard.down('Shift')
page.keyboard.up('Shift')
#快捷键
page.keyboard.press('Control+A') # 全选
page.keyboard.press('Control+C') # 复制
page.keyboard.press('Control+V') # 粘贴
#特殊键
page.keyboard.press('ArrowLeft')
page.keyboard.press('Tab')
page.keyboard.press('Escape')
- 鼠标操作
#获取元素位置
bounding_box = page.query_selector('button').bounding_box()
#精确鼠标控制
page.mouse.move(bounding_box['x'] + bounding_box['width']/2,
bounding_box['y'] + bounding_box['height']/2)
page.mouse.click(bounding_box['x'] + bounding_box['width']/2,
bounding_box['y'] + bounding_box['height']/2)
#鼠标拖拽
page.mouse.down()
page.mouse.move(100, 100)
page.mouse.up()
页面与框架管理
- 多页面处理
# 获取所有页面
all_pages = context.pages
# 创建新页面
new_page = context.new_page()
# 等待新页面
with context.expect_page() as new_page_info:
page.click('a[target="_blank"]')
new_page = new_page_info.value
# 切换到特定页面
context.pages[1].bring_to_front()
- 框架处理
# 获取框架
frame = page.frame(name='frame-name')
frame = page.frame(url=r'.*login.*')
# 框架内操作
frame.click('button.submit')
frame.fill('input#username', 'user')
# 遍历所有框架
for frame in page.frames:
print(frame.name)
页面上下文
# 执行JavaScript
page.evaluate('document.title')
result = page.evaluate('([x, y]) => x + y', [1, 2])
# 注入JavaScript
page.add_script_tag(url='https://code.jquery.com/jquery.js')
page.add_script_tag(content='console.log("Hello");')
# 注入样式
page.add_style_tag(url='https://cdn.example.com/style.css')
page.add_style_tag(content='body { background: red; }')
# 设置页面内容
page.set_content('<html><body><h1>Hello</h1></body></html>')
网络请求处理
- 请求拦截与修改
# 路由拦截
def handle_route(route):
if 'api.example.com' in route.request.url:
route.fulfill(
status=200,
content_type='application/json',
body='{"success": true}'
)
else:
route.continue_()
page.route('**/*', handle_route)
# 特定模式拦截
page.route('**/*.jpg', lambda route: route.abort())
page.route('**/api/*', handle_route)
# 修改请求头
page.route('**/*', lambda route: route.continue_(headers={**route.request.headers, 'x-custom': 'value'}))
- 请求监控
# 请求事件处理
def log_request(request):
print(f"Request: {request.method} {request.url}")
def log_response(response):
print(f"Response: {response.status} {response.url}")
page.on('request', log_request)
page.on('response', log_response)
# 等待请求完成
with page.expect_response('https://example.com/api/data') as response_info:
page.click('button#load-data')
response = response_info.value
# 等待多个请求
with page.expect_response(lambda response: response.url.startswith('https://api')) as response_info:
page.click('button#fetch')
- API请求直接调用
# 使用Playwright发起API请求
response = page.request.get('https://api.example.com/data')
print(response.json())
# 带参数的请求
response = page.request.post(
'https://api.example.com/login',
data={'username': 'user', 'password': 'pass'},
headers={'Content-Type': 'application/json'}
)
断言
- 内置断言
# 页面标题断言
assert page.title() == 'Expected Title'
# URL断言
assert page.url == 'https://example.com'
# 元素可见性断言
assert page.is_visible('div.success')
# 文本内容断言
assert 'Welcome' in page.text_content('body')
- 等待断言
# 等待元素出现并断言
page.wait_for_selector('div.success', state='visible')
assert page.text_content('div.success') == 'Operation successful'
# 等待文本出现
page.wait_for_selector('text=Welcome back')
# 等待函数条件
page.wait_for_function('() => document.querySelectorAll(".item").length > 5')
截图与PDF生成
- 截图功能
# 页面截图
page.screenshot(path='screenshot.png')
# 元素截图
page.locator('div.chart').screenshot(path='chart.png')
# 截图选项
page.screenshot(
path='fullpage.png',
full_page=True, # 截取完整页面
type='jpeg', # 图片类型:'png'|'jpeg'
quality=80, # JPEG质量(0-100)
omit_background=True, # 隐藏默认背景
timeout=10000 # 超时时间
)
- PDF生成
# 生成PDF
page.pdf(
path='page.pdf',
scale=0.8, # 缩放比例
format='A4', # 纸张格式
margin={'top': '1cm', 'bottom': '1cm'}, # 边距
print_background=True, # 打印背景
landscape=False # 横向/纵向
)
测试框架集成
与pytest集成
# conftest.py
import pytest
from playwright.sync_api import sync_playwright
@pytest.fixture(scope='session')
def browser():
with sync_playwright() as p:
browser = p.chromium.launch(headless=False)
yield browser
browser.close()
@pytest.fixture
def page(browser):
context = browser.new_context()
page = context.new_page()
yield page
context.close()
# test_example.py
def test_login(page):
page.goto('https://example.com/login')
page.fill('input#username', 'testuser')
page.fill('input#password', 'password')
page.click('button#submit')
assert page.url == 'https://example.com/dashboard'
测试最佳实践
# 页面对象模型
class LoginPage:
def __init__(self, page):
self.page = page
self.username_input = page.locator('input#username')
self.password_input = page.locator('input#password')
self.submit_button = page.locator('button#submit')
def navigate(self):
self.page.goto('https://example.com/login')
def login(self, username, password):
self.username_input.fill(username)
self.password_input.fill(password)
self.submit_button.click()
# 使用页面对象
def test_login(page):
login_page = LoginPage(page)
login_page.navigate()
login_page.login('testuser', 'password')
assert page.url == 'https://example.com/dashboard'
调试
# 启用调试模式
browser = p.chromium.launch(headless=False, devtools=True)
# 暂停执行
page.pause()
# 慢速模式
browser = p.chromium.launch(headless=False, slow_mo=1000)
# 记录控制台输出
page.on('console', lambda msg: print(f'CONSOLE: {msg.text}'))
# 记录页面错误
page.on('pageerror', lambda err: print(f'PAGE ERROR: {err}'))
# 记录请求失败
page.on('requestfailed', lambda req: print(f'REQUEST FAILED: {req.url} {req.failure}'))
# 高亮匹配元素
page.locator('button').highlight()
# 评估选择器
count = page.locator('button').count()
print(f'Found {count} buttons')
# 调试选择器
try:
page.wait_for_selector('button:visible', timeout=5000)
except:
print('Button not found within 5 seconds')
性能优化
- 浏览器上下文复用
# 复用浏览器上下文
context = browser.new_context()
# 在不同测试中复用
def test_1(context):
page = context.new_page()
# 测试代码...
def test_2(context):
page = context.new_page()
# 测试代码...
# 清理上下文
context.clear_cookies()
context.clear_permissions()
- 并行执行
# 使用多线程并行测试
import concurrent.futures
def run_test(test_func, browser_type):
with sync_playwright() as p:
browser = getattr(p, browser_type).launch()
context = browser.new_context()
page = context.new_page()
test_func(page)
browser.close()
with concurrent.futures.ThreadPoolExecutor() as executor:
futures = []
for _ in range(3):
futures.append(executor.submit(run_test, test_function, 'chromium'))
for future in concurrent.futures.as_completed(futures):
future.result()
Playwright MCP
使用 Playwright 提供浏览器自动化功能的 Model Context Protocol (MCP) 服务器。该服务器使 LLM 能够通过结构化的无障碍快照与网页进行交互,从而绕过了对屏幕截图或视觉调优模型的需求。
主要特性
- 快速且轻量:使用 Playwright 的无障碍树,而不是基于像素的输入;
- LLM 友好:无需视觉模型,纯粹基于结构化数据操作;
- 确定性的工具应用:避免了基于屏幕截图方法常见的歧义。
使用场景
- 网页导航和表单填写;
- 从结构化内容中提取数据;
- 由 LLM 驱动的自动化测试;
- 适用于代理的一般用途浏览器交互。
在ClaudeCode中安装
在命令行中运行以下命令:
#切换到你的项目目录
cd your-project-folder
#添加Playwright MCP服务器
claude mcp add playwright -- cmd /c npx @playwright/mcp@latest
#安装浏览器(Chromium、Firefox等)
npx playwright install
#验证安装
claude mcp list #playwright显示为"Connected"状态
使用Playwright MCP
安装完成后,在Claude Code会话中就可以直接用自然语言控制浏览器了:
“使用playwright mcp 打开 https://passport.baidu.com/v2/?login
使用用户名登录,在用户名字段输入13800000000,在密码字段输入123,点击登录按钮
等待登录信息出现后截屏,保存至.\screenshots”
Playwright MCP 完整工具集
- 输入自动化(8个工具)
| 工具名 | 描述 | 参数 |
|---|---|---|
| browser_click | 在网页上执行点击操作 | element-元素描述, ref-元素引用 |
| browser_drag | 在两个元素之间执行拖放操作 | startElement-源元素描述, startRef-源元素引用, endElement-目标元素描述, endRef-目标元素引用 |
| browser_type | 在可编辑元素中输入文本 | element-元素描述, ref-元素引用, text-输入文本, submit-是否按回车提交 |
| browser_hover | 悬停在页面元素上 | element-元素描述, ref-元素引用 |
| browser_select_option | 在下拉菜单中选择选项 | element-元素描述, ref-元素引用, values-要选择的值数组 |
| browser_choose_file | 选择一个或多个文件进行上传 | paths-要上传文件的绝对路径数组 |
| browser_press_key | 在键盘上按下一个键 | key-键名或字符,如ArrowLeft或a |
| browser_save_as_pdf | 将页面保存为PDF | 无 |
- 导航自动化(4个工具)
| 工具名 | 描述 | 参数 |
|---|---|---|
| browser_navigate | 导航到指定的URL | url-要导航到的URL地址 |
| browser_go_back | 返回上一页 | 无 |
| browser_go_forward | 前进到下一页 | 无 |
| browser_close | 关闭当前页面 | 无 |
- 调试与捕获(3个工具)
| 工具名 | 描述 | 参数 |
|---|---|---|
| browser_snapshot | 捕获当前页面的可访问性快照(优于截图) | 无 |
| browser_take_screenshot | 捕获页面的屏幕截图 | raw-(可选)返回无损PNG格式截图,默认为JPEG |
| browser_wait | 等待指定的时间(秒) | time-等待时间,上限10秒 |
Chrome DevTools MCP
充当MCP服务器,让 AI 能够访问 Chrome DevTools 的全部功能,以实现可靠的自动化、深入调试和性能分析。
主要特性
- 获取性能洞察:使用 Chrome DevTools 记录跟踪并提取可操作的性能洞察;
- 高级浏览器调试:分析网络请求、截屏并检查浏览器控制台;
- 可靠的自动化:使用 puppeteer 在 Chrome 中自动执行操作,并自动等待操作结果。
在ClaudeCode中安装
在命令行中运行以下命令:
#切换到你的项目目录
cd your-project-folder
#添加chrome-devtools服务器
claude mcp add chrome-devtools -- cmd /c npx chrome-devtools-mcp@latest
#验证安装
claude mcp list #chrome-devtools应显示为"Connected"状态
使用Chrome DevTools MCP
安装完成后,在Claude Code会话中用自然语言控制浏览器:
“使用chrome-devtools打开当前浏览器分析性能”
Chrome DevTools MCP 完整工具集
- 输入自动化(7个工具)
| 工具名 | 描述 | 参数 |
|---|---|---|
| click | 点击页面元素 | element-元素描述, ref-元素引用 |
| drag | 拖放操作 | startElement-起始元素描述, startRef-起始元素引用, endElement-目标元素描述, endRef-目标元素引用 |
| fill | 填充输入框 | element-元素描述, ref-元素引用, text-输入文本 |
| fill_form | 一键填写整个表单 | formData-包含字段名和值的对象 |
| handle_dialog | 处理弹窗(alert/confirm/prompt) | action-操作类型(accept/dismiss), promptText-(可选)提示框输入文本 |
| hover | 悬停在元素上 | element-元素描述, ref-元素引用 |
| upload_file | 上传文件 | element-上传元素描述, ref-元素引用, paths-文件路径数组 |
- 导航自动化(7个工具)
| 工具名 | 描述 | 参数 |
|---|---|---|
| close_page | 关闭当前页面 | 无 |
| list_pages | 列出所有打开的页面 | 无 |
| navigate_page | 导航到指定URL | url-目标网址, waitUntil-等待条件(load/domcontentloaded/networkidle) |
| navigate_page_history | 历史导航 | direction-方向(back/forward) |
| new_page | 创建新页面 | context-(可选)浏览器上下文 |
| select_page | 切换到指定页面 | pageId-页面ID |
| wait_for | 等待条件满足 | condition-等待条件(load/selector/function), timeout-超时时间 |
- 模拟(3个工具)
| 工具名 | 描述 | 参数 |
|---|---|---|
| emulate_cpu | 模拟CPU性能(节流) | throttlingRate-CPU节流倍率,例如4表示4倍慢速 |
| emulate_network | 模拟网络条件 | networkCondition-网络条件(offline/slow3G/fast3G/wifi等), latency-自定义延迟(ms), downloadThroughput-自定义下载速度, uploadThroughput-自定义上传速度 |
| resize_page | 调整页面视口大小 | width-视口宽度(px), height-视口高度(px) |
- 性能(3个工具)
| 工具名 | 描述 | 参数 |
|---|---|---|
| performance_analyze_insight | 分析性能洞察 | traceData-性能追踪数据, insightType-洞察类型(loadTime/renderBlocking/layoutShift等) |
| performance_start_trace | 开始性能追踪 | categories-要追踪的类别数组,例如["loading","scripting","rendering"] |
| performance_stop_trace | 停止性能追踪并获取结果 | 无 |
- 网络(2个工具)
| 工具名 | 描述 | 参数 |
|---|---|---|
| get_network_request | 获取特定网络请求的详细信息 | requestId-请求ID |
| list_network_requests | 列出所有网络请求 | filter-(可选)过滤条件,例如*.js、api/*等 |
- 调试(4个工具)
| 工具名 | 描述 | 参数 |
|---|---|---|
| evaluate_script | 在页面上下文中执行JavaScript脚本 | script-要执行的JavaScript代码, returnByValue-是否返回值(true)或返回对象引用(false) |
| list_console_messages | 列出控制台消息 | clear-是否在获取后清除控制台消息 |
| take_screenshot | 截取页面截图 | format-图片格式(png/jpeg), quality-(仅jpeg)图片质量0-100, fullPage-是否截取整个页面(包括滚动部分) |
| take_snapshot | 捕获页面的DOM快照(包含可访问性信息) | includeDom-是否包含DOM结构, includeAccessibility-是否包含可访问性信息 |
Playwright MCP vs Chrome DevTools MCP:
一、核心差异对比
| 对比维度 | Playwright MCP | Chrome DevTools MCP |
|---|---|---|
| 底层协议 | Playwright自动化库 | Chrome DevTools Protocol (CDP) |
| 浏览器实例 | 启动全新的浏览器实例 | 连接已有的Chrome浏览器 |
| 适用场景 | UI自动化测试、E2E测试、表单填写 | 调试现有页面、性能分析、网络监控 |
| 核心优势 | 自动化能力强、跨浏览器支持 | 调试功能丰富、性能分析深入 |
| 启动方式 | 每次新建独立会话 | 可复用现有浏览器 |
| 学习曲线 | 平缓,面向自动化 | 中等,面向调试场景 |
二、工具集功能对比
- 输入自动化能力
| 功能 | Playwright MCP | Chrome DevTools MCP |
|---|---|---|
| 表单填写 | ❌ 需要手动组合 | ✅ fill_form(一键填表) |
| 处理弹窗 | ❌ | ✅ handle_dialog |
| 键盘按键 | ✅ browser_press_key | ❌ |
- 导航与页面管理
| 功能 | Playwright MCP | Chrome DevTools MCP |
|---|---|---|
| 列出所有页面 | ❌ | ✅ list_pages |
| 切换页面 | ❌ | ✅ select_page |
| 新建页面 | ❌ | ✅ new_page |
- 调试与诊断能力
| 功能 | Playwright MCP | Chrome DevTools MCP |
|---|---|---|
| 页面快照 | ✅ browser_snapshot(可访问性树) | ✅ take_snapshot(DOM+可访问性) |
| 截图 | ✅ browser_take_screenshot | ✅ take_screenshot(更多格式选项) |
| 保存为PDF | ✅ browser_save_as_pdf | ❌ |
| 执行JS脚本 | ❌ | ✅ evaluate_script |
| 查看控制台 | ❌ | ✅ list_console_messages |
| 性能追踪 | ❌ | ✅ performance_start/stop_trace |
| 性能分析 | ❌ | ✅ performance_analyze_insight |
| 网络请求监控 | ❌ | ✅ list_network_requests |
| 网络详情获取 | ❌ | ✅ get_network_request |
- 模拟与仿真能力
| 功能 | Playwright MCP | Chrome DevTools MCP |
|---|---|---|
| CPU节流 | ❌ | ✅ emulate_cpu |
| 网络模拟 | ❌ | ✅ emulate_network |
| 视口调整 | ❌(需启动时配置) | ✅ resize_page |
Playwright MCP 是自动化测试的首选,它提供了简洁的API、稳定的执行环境和跨浏览器支持,适合构建可靠的测试套件。
Chrome DevTools MCP 是调试和诊断的利器,它深入浏览器内部,提供性能分析、网络监控和实时调试能力,适合开发和问题排查。
结合使用:
- 用Playwright构建自动化测试流水线 :编写稳定的E2E测试、表单填写、用户行为模拟;
- 用DevTools深入分析问题和优化性能 :当测试失败时,用DevTools调试;当需要优化时,用DevTools分析;
- 在关键场景中互相验证和补充 :用Playwright模拟用户操作,用DevTools验证页面状态和性能指标。
@playwright/cli
微软官方推出的专为AI编码代理设计的命令行工具,于2026年初发布。它与传统的 npx playwright test 完全不同,是一个专门面向AI代理(如Claude Code、GitHub Copilot、Cursor等)的浏览器自动化接口。
核心理念:
极致的token效率,与MCP将完整的可访问性树和截图数据推送到AI上下文不同,CLI将所有数据保存在磁盘上,AI代理只接收简洁的命令输出和文件路径,按需读取所需信息。
MCP VS CLI:
| 对比项 | MCP方式 | CLI方式 |
|---|---|---|
| 页面快照 | 返回完整可访问性树(数千token) | 保存为YAML文件,返回文件路径 |
| 截图 | 返回Base64图像(数万token) | 保存为PNG文件,返回文件路径 |
| 单会话token消耗 | ~114,000 tokens | ~27,000 tokens(约4倍节省) |
| 长会话表现 | 上下文迅速填满,性能下降 | 上下文始终保持轻量 |
安装
- 安装
#全局安装
npm install -g @playwright/cli@latest
#验证安装
playwright-cli --version
#在工作区初始化
cd your-project-folder
playwright-cli install #在当前工作区创建 .playwright-cli/ 目录,用于存放浏览器会话和配置文件。
- 安装浏览器
#如果系统没有Chrome,可以安装独立浏览器
playwright-cli install-browser
#安装特定浏览器
playwright-cli install-browser --browser=firefox
- 安装技能(让AI学习CLI)
#为Claude Code安装技能文档
playwright-cli install --skills #复制 SKILL.md 文件到工作区,AI代理可以通过阅读该文件学习所有可用命令。
@playwright/cli 提供了超过50个命令,远多于MCP默认启用的工具集,如需了解工具集可查询帮助文档查看,也可以询问ClaudeCode,梳理大致使用场景
使用playwright-cli
“使用playwright-cli打开https://passport.baidu.com/v2/?login,测试登录功能,使用有头模式让我看见”
核心优势:
- 极致token效率:比MCP节省4-10倍的token消耗;
- 命令集更丰富:50+命令 vs MCP的~20个工具;
- 确定性控制:元素引用ID(如 e21)确保精准交互;
- 多会话支持:并行管理多个独立浏览器实例;
- 可视化监控:playwright-cli show 实时观察AI操作。
与 Playwright MCP 的选型指南:
| 选择条件 | 推荐 @playwright/cli | 推荐 Playwright MCP |
|---|---|---|
| 代理类型 | 编码代理(Claude Code、Copilot) | 通用聊天代理(Claude Desktop) |
| 环境 | 有文件系统和shell访问权限 | 沙箱环境,无文件系统访问 |
| 会话长度 | 长会话(10+步骤) | 短会话(1-3步) |
| token预算 | 有限,需优化 | 充足,接受高消耗 |
| 确定性要求 | 高,需精确控制 | 中等,允许探索性 |
| 集成场景 | 与代码库、测试框架协同 | 独立聊天工具 |
微软官方的建议:
如果你的任务涉及编码、测试,且使用编码代理——使用 CLI。如果你正在构建需要 MCP 协议标准的自主代理工作流——使用 MCP。
总结:
- MCP vs CLI 的本质区别:不是功能多少,而是数据传递方式。MCP推送完整数据(适合短会话),CLI保存文件+路径(适合长会话)。
- token效率是AI时代的关键:@playwright/cli的4-10倍token节省。
- 生态互补而非替代:传统库、MCP服务器、CLI工具三者各司其职,共同构成完整的Playwright生态系统。
- 未来趋势:随着AI编码代理的普及,@playwright/cli这类面向AI设计的工具将逐渐成为主流。
更多推荐



所有评论(0)