chrome

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Chrome Automation

Chrome浏览器自动化

Automate browser interactions using Puppeteer or Playwright.
使用Puppeteer或Playwright实现浏览器交互自动化。

Prerequisites

前提条件

bash
undefined
bash
undefined

Puppeteer

Puppeteer

npm install puppeteer
npm install puppeteer

Or Playwright

Or Playwright

npm install playwright npx playwright install chromium
undefined
npm install playwright npx playwright install chromium
undefined

Puppeteer 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.js
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();
})();
运行:
node script.js

With 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');  // Puppeteer
javascript
// 输入文本
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 production
javascript
// 等待选择器出现
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 tool
javascript
// 生成基准截图
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

最佳实践

  1. Use explicit waits - Not timeouts
  2. Handle errors - try/catch important
  3. Close browsers - Always clean up
  4. Use headless for CI - Faster, no display needed
  5. Test selectors - Prefer data-testid
  6. Screenshot on failure - Debug easier
  7. Reuse contexts - Faster than new browsers
  1. 使用显式等待 - 避免使用固定时长的超时
  2. 处理错误 - 对关键逻辑使用try/catch
  3. 关闭浏览器实例 - 始终清理资源
  4. 在CI环境中使用无头模式 - 速度更快,无需显示设备
  5. 测试选择器 - 优先使用data-testid属性
  6. 失败时自动截图 - 便于调试
  7. 复用上下文 - 比新建浏览器实例更高效