chrome
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseChrome Automation
Chrome浏览器自动化
Automate browser interactions using Puppeteer or Playwright.
使用Puppeteer或Playwright实现浏览器交互自动化。
Prerequisites
前提条件
bash
undefinedbash
undefinedPuppeteer
Puppeteer
npm install puppeteer
npm install puppeteer
Or Playwright
Or Playwright
npm install playwright
npx playwright install chromium
undefinednpm install playwright
npx playwright install chromium
undefinedPuppeteer Quick Start
Puppeteer快速入门
Basic Script
基础脚本
javascript
// script.js
const puppeteer = require('puppeteer');
(async () => {
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.goto('https://example.com');
await page.screenshot({ path: 'screenshot.png' });
await browser.close();
})();Run:
node script.jsjavascript
// script.js
const puppeteer = require('puppeteer');
(async () => {
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.goto('https://example.com');
await page.screenshot({ path: 'screenshot.png' });
await browser.close();
})();运行:
node script.jsWith Visible Browser
显示浏览器窗口模式
javascript
const browser = await puppeteer.launch({
headless: false,
slowMo: 50, // Slow down operations
});javascript
const browser = await puppeteer.launch({
headless: false,
slowMo: 50, // 放慢操作速度
});Playwright Quick Start
Playwright快速入门
Basic Script
基础脚本
javascript
// script.js
const { chromium } = require('playwright');
(async () => {
const browser = await chromium.launch();
const page = await browser.newPage();
await page.goto('https://example.com');
await page.screenshot({ path: 'screenshot.png' });
await browser.close();
})();javascript
// script.js
const { chromium } = require('playwright');
(async () => {
const browser = await chromium.launch();
const page = await browser.newPage();
await page.goto('https://example.com');
await page.screenshot({ path: 'screenshot.png' });
await browser.close();
})();Common Operations
常见操作
Navigation
页面导航
javascript
// Go to URL
await page.goto('https://example.com');
// Wait for navigation
await page.goto('https://example.com', { waitUntil: 'networkidle0' });
// Go back/forward
await page.goBack();
await page.goForward();
// Reload
await page.reload();javascript
// 跳转到指定URL
await page.goto('https://example.com');
// 等待页面导航完成
await page.goto('https://example.com', { waitUntil: 'networkidle0' });
// 后退/前进
await page.goBack();
await page.goForward();
// 刷新页面
await page.reload();Screenshots
截图操作
javascript
// Full page
await page.screenshot({ path: 'full.png', fullPage: true });
// Specific element
const element = await page.$('#header');
await element.screenshot({ path: 'header.png' });
// With options
await page.screenshot({
path: 'screenshot.png',
type: 'png',
quality: 90, // For jpeg
clip: { x: 0, y: 0, width: 800, height: 600 }
});javascript
// 整页截图
await page.screenshot({ path: 'full.png', fullPage: true });
// 特定元素截图
const element = await page.$('#header');
await element.screenshot({ path: 'header.png' });
// 带选项的截图
await page.screenshot({
path: 'screenshot.png',
type: 'png',
quality: 90, // 仅适用于jpeg格式
clip: { x: 0, y: 0, width: 800, height: 600 }
});Click Actions
点击操作
javascript
// Click element
await page.click('#button');
await page.click('button.submit');
// Double click
await page.dblclick('#item');
// Right click
await page.click('#element', { button: 'right' });
// Click and wait for navigation
await Promise.all([
page.waitForNavigation(),
page.click('a.link')
]);javascript
// 点击元素
await page.click('#button');
await page.click('button.submit');
// 双击
await page.dblclick('#item');
// 右键点击
await page.click('#element', { button: 'right' });
// 点击并等待页面导航
await Promise.all([
page.waitForNavigation(),
page.click('a.link')
]);Form Filling
表单填写
javascript
// Type text
await page.type('#email', 'user@example.com');
// Clear and type
await page.fill('#email', 'user@example.com'); // Playwright
await page.$eval('#email', el => el.value = ''); // Puppeteer clear
await page.type('#email', 'user@example.com');
// Select dropdown
await page.select('#country', 'US');
// Checkbox
await page.check('#agree'); // Playwright
await page.click('#agree'); // Puppeteer
// File upload
await page.setInputFiles('#file', '/path/to/file.pdf'); // Playwright
const input = await page.$('#file');
await input.uploadFile('/path/to/file.pdf'); // Puppeteerjavascript
// 输入文本
await page.type('#email', 'user@example.com');
// 清空后输入
await page.fill('#email', 'user@example.com'); // Playwright方式
await page.$eval('#email', el => el.value = ''); // Puppeteer清空方式
await page.type('#email', 'user@example.com');
// 选择下拉框
await page.select('#country', 'US');
// 勾选复选框
await page.check('#agree'); // Playwright方式
await page.click('#agree'); // Puppeteer方式
// 文件上传
await page.setInputFiles('#file', '/path/to/file.pdf'); // Playwright方式
const input = await page.$('#file');
await input.uploadFile('/path/to/file.pdf'); // Puppeteer方式Waiting
等待操作
javascript
// Wait for selector
await page.waitForSelector('#loaded');
// Wait for text
await page.waitForFunction(() =>
document.body.textContent.includes('Success')
);
// Wait for navigation
await page.waitForNavigation();
// Wait for network idle
await page.waitForLoadState('networkidle'); // Playwright
// Explicit wait
await page.waitForTimeout(1000); // Not recommended for productionjavascript
// 等待选择器出现
await page.waitForSelector('#loaded');
// 等待文本出现
await page.waitForFunction(() =>
document.body.textContent.includes('Success')
);
// 等待页面导航完成
await page.waitForNavigation();
// 等待网络空闲
await page.waitForLoadState('networkidle'); // Playwright方式
// 显式等待(不推荐生产环境使用)
await page.waitForTimeout(1000);Extract Data
数据提取
javascript
// Get text content
const text = await page.textContent('#element');
const text = await page.$eval('#element', el => el.textContent);
// Get attribute
const href = await page.getAttribute('a', 'href');
const href = await page.$eval('a', el => el.href);
// Get multiple elements
const items = await page.$$eval('.item', els =>
els.map(el => el.textContent)
);
// Get page content
const html = await page.content();javascript
// 获取文本内容
const text = await page.textContent('#element');
const text = await page.$eval('#element', el => el.textContent);
// 获取属性值
const href = await page.getAttribute('a', 'href');
const href = await page.$eval('a', el => el.href);
// 获取多个元素内容
const items = await page.$$eval('.item', els =>
els.map(el => el.textContent)
);
// 获取页面HTML内容
const html = await page.content();Evaluate JavaScript
执行JavaScript代码
javascript
// Run in browser context
const result = await page.evaluate(() => {
return document.title;
});
// With arguments
const text = await page.evaluate((selector) => {
return document.querySelector(selector).textContent;
}, '#element');javascript
// 在浏览器上下文运行代码
const result = await page.evaluate(() => {
return document.title;
});
// 带参数执行
const text = await page.evaluate((selector) => {
return document.querySelector(selector).textContent;
}, '#element');Testing Patterns
测试模式
Login Flow
登录流程测试
javascript
async function login(page, username, password) {
await page.goto('https://app.example.com/login');
await page.fill('#username', username);
await page.fill('#password', password);
await page.click('button[type="submit"]');
await page.waitForSelector('#dashboard');
}javascript
async function login(page, username, password) {
await page.goto('https://app.example.com/login');
await page.fill('#username', username);
await page.fill('#password', password);
await page.click('button[type="submit"]');
await page.waitForSelector('#dashboard');
}Form Submission Test
表单提交测试
javascript
async function testForm(page) {
await page.goto('https://example.com/form');
// Fill form
await page.fill('#name', 'Test User');
await page.fill('#email', 'test@example.com');
await page.select('#country', 'US');
await page.check('#agree');
// Submit
await page.click('button[type="submit"]');
// Verify success
await page.waitForSelector('.success-message');
const message = await page.textContent('.success-message');
console.assert(message.includes('Thank you'));
}javascript
async function testForm(page) {
await page.goto('https://example.com/form');
// 填写表单
await page.fill('#name', 'Test User');
await page.fill('#email', 'test@example.com');
await page.select('#country', 'US');
await page.check('#agree');
// 提交表单
await page.click('button[type="submit"]');
// 验证提交成功
await page.waitForSelector('.success-message');
const message = await page.textContent('.success-message');
console.assert(message.includes('Thank you'));
}Visual Regression
视觉回归测试
javascript
// Take baseline
await page.screenshot({ path: 'baseline.png', fullPage: true });
// Later, compare
await page.screenshot({ path: 'current.png', fullPage: true });
// Use image comparison tooljavascript
// 生成基准截图
await page.screenshot({ path: 'baseline.png', fullPage: true });
// 后续进行对比
await page.screenshot({ path: 'current.png', fullPage: true });
// 使用图片对比工具进行校验Device Emulation
设备模拟
javascript
// Puppeteer
const iPhone = puppeteer.devices['iPhone 12'];
await page.emulate(iPhone);
// Playwright
const iPhone = playwright.devices['iPhone 12'];
const context = await browser.newContext({ ...iPhone });
// Manual viewport
await page.setViewportSize({ width: 375, height: 812 });javascript
// Puppeteer方式
const iPhone = puppeteer.devices['iPhone 12'];
await page.emulate(iPhone);
// Playwright方式
const iPhone = playwright.devices['iPhone 12'];
const context = await browser.newContext({ ...iPhone });
// 手动设置视口
await page.setViewportSize({ width: 375, height: 812 });Network
网络操作
javascript
// Intercept requests (Playwright)
await page.route('**/api/*', route => {
route.fulfill({ status: 200, body: JSON.stringify({ mocked: true }) });
});
// Block resources
await page.route('**/*.{png,jpg,jpeg}', route => route.abort());
// Monitor requests
page.on('request', req => console.log(req.url()));
page.on('response', res => console.log(res.status(), res.url()));javascript
// 拦截请求(Playwright)
await page.route('**/api/*', route => {
route.fulfill({ status: 200, body: JSON.stringify({ mocked: true }) });
});
// 阻止资源加载
await page.route('**/*.{png,jpg,jpeg}', route => route.abort());
// 监控请求与响应
page.on('request', req => console.log(req.url()));
page.on('response', res => console.log(res.status(), res.url()));Best Practices
最佳实践
- Use explicit waits - Not timeouts
- Handle errors - try/catch important
- Close browsers - Always clean up
- Use headless for CI - Faster, no display needed
- Test selectors - Prefer data-testid
- Screenshot on failure - Debug easier
- Reuse contexts - Faster than new browsers
- 使用显式等待 - 避免使用固定时长的超时
- 处理错误 - 对关键逻辑使用try/catch
- 关闭浏览器实例 - 始终清理资源
- 在CI环境中使用无头模式 - 速度更快,无需显示设备
- 测试选择器 - 优先使用data-testid属性
- 失败时自动截图 - 便于调试
- 复用上下文 - 比新建浏览器实例更高效