
痛点场景 #
你有没有过这种经历:
每天要打开十几个网站查数据,重复操作累死人。
想抓取某个网站的信息,但不会写爬虫。 需要定期截图监控页面变化,每次都手动操作。
这活本该自动化。
为什么选择 Playwright? #
市面上的浏览器自动化工具有很多:
| 工具 | 优点 | 缺点 |
|---|---|---|
| Selenium | 老牌、生态好 | 配置复杂、速度慢 |
| Puppeteer | 只支持 Chrome | 功能单一 |
| Playwright | 支持多浏览器、API 简洁、速度快 | 相对较新 |
我选 Playwright 的理由:
- ✅ 支持 Chrome、Firefox、WebKit
- ✅ API 简洁,上手快
- ✅ 内置等待机制,不容易出错
- ✅ 支持无头模式,适合服务器部署
环境配置 #
1. 安装 Node.js #
# 检查是否已安装
node --version
# 如果没有,安装 Node.js 20+
# macOS
brew install node@20
# Linux
curl -fsSL https://deb.nodesource.com/setup_20.x | bash -
apt-get install -y nodejs2. 安装 Playwright #
# 创建项目目录
mkdir playwright-demo && cd playwright-demo
# 初始化项目
npm init -y
# 安装 Playwright
npm install -D playwright
# 安装 Chromium 浏览器
npx playwright install chromium3. 安装系统依赖(Linux) #
# Playwright 会自动检测并安装所需依赖
npx playwright install-deps chromium依赖列表(约 200MB):
- libatk-1.0-0
- libatk-bridge2.0-0
- libdrm2
- libxkbcommon0
- libxcomposite1
- …(约 30 个库)
安装完成后,环境就准备好了。
第一个脚本:截图 #
基础截图 #
const { chromium } = require('playwright');
(async () => {
const browser = await chromium.launch({
headless: true // 无头模式
});
const page = await browser.newPage();
await page.goto('https://www.example.com');
await page.screenshot({
path: 'screenshot.png',
fullPage: true // 完整页面
});
await browser.close();
console.log('截图完成!');
})();指定 viewport 尺寸 #
const page = await browser.newPage({
viewport: { width: 1280, height: 800 }
});保存为 JPEG #
await page.screenshot({
path: 'screenshot.jpg',
type: 'jpeg',
quality: 90 // 质量 0-100
});实战:访问小红书首页 #
const { chromium } = require('playwright');
async function screenshotWebsite(url, screenshotName) {
const browser = await chromium.launch({
headless: true,
args: [
'--no-sandbox',
'--disable-setuid-sandbox',
'--disable-dev-shm-usage',
'--disable-gpu'
]
});
const context = await browser.newContext({
viewport: { width: 1280, height: 800 },
userAgent: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
locale: 'zh-CN'
});
const page = await context.newPage();
try {
console.log(`正在访问:${url}`);
await page.goto(url, {
waitUntil: 'domcontentloaded',
timeout: 30000
});
// 等待页面稳定
await page.waitForTimeout(3000);
// 截图
const screenshotPath = `/path/to/${screenshotName}`;
await page.screenshot({
path: screenshotPath,
fullPage: true
});
console.log(`✅ 截图已保存:${screenshotPath}`);
const title = await page.title();
console.log(`页面标题:${title}`);
return screenshotPath;
} catch (error) {
console.error('访问失败:', error.message);
throw error;
} finally {
await browser.close();
}
}
// 运行
screenshotWebsite('https://www.xiaohongshu.com', 'xiaohongshu-home.png');运行结果:
正在访问:https://www.xiaohongshu.com
✅ 截图已保存:/path/to/xiaohongshu-home.png
页面标题:小红书 - 你的生活兴趣社区高级用法 #
1. 点击元素 #
// 点击按钮
await page.click('#submit-button');
// 点击链接
await page.click('a[href="/login"]');
// 等待后点击
await page.waitForSelector('#submit-button');
await page.click('#submit-button');2. 填写表单 #
// 填写文本框
await page.fill('#username', 'myusername');
await page.fill('#password', 'mypassword');
// 选择下拉框
await page.selectOption('#country', 'CN');
// 勾选复选框
await page.check('#agree-terms');
// 提交表单
await page.click('#submit');3. 等待元素 #
// 等待元素出现
await page.waitForSelector('.result');
// 等待元素可见
await page.waitForSelector('.result', { state: 'visible' });
// 等待元素消失
await page.waitForSelector('.loading', { state: 'hidden' });
// 等待特定时间
await page.waitForTimeout(2000);4. 提取数据 #
const data = await page.evaluate(() => {
const results = [];
const items = document.querySelectorAll('.product-item');
items.forEach(item => {
results.push({
title: item.querySelector('.title')?.textContent,
price: item.querySelector('.price')?.textContent,
link: item.querySelector('a')?.href
});
});
return results;
});
console.log(data);5. 处理弹窗 #
// 等待并关闭弹窗
page.on('dialog', async dialog => {
console.log(`弹窗内容:${dialog.message()}`);
await dialog.accept(); // 或 dialog.dismiss()
});6. 多标签页 #
// 打开新标签
const newPage = await context.newPage();
await newPage.goto('https://example2.com');
// 切换标签
await page.bringToFront();
// 关闭标签
await newPage.close();反爬应对 #
1. 设置 User-Agent #
const context = await browser.newContext({
userAgent: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36'
});2. 设置语言和本地化 #
const context = await browser.newContext({
locale: 'zh-CN',
timezoneId: 'Asia/Shanghai'
});3. 随机延迟 #
// 随机等待 1-3 秒
const randomDelay = Math.floor(Math.random() * 2000) + 1000;
await page.waitForTimeout(randomDelay);4. 使用代理 #
const context = await browser.newContext({
proxy: {
server: 'http://proxy.example.com:8080',
username: 'user',
password: 'pass'
}
});常见问题 #
问题 1: 页面加载超时 #
错误:
page.goto: Timeout 30000ms exceeded解决:
// 1. 延长超时时间
await page.goto(url, { timeout: 60000 });
// 2. 使用 domcontentloaded 而不是 networkidle
await page.goto(url, { waitUntil: 'domcontentloaded' });
// 3. 禁用部分功能加速
const browser = await chromium.launch({
args: ['--disable-gpu', '--disable-dev-shm-usage']
});问题 2: 元素找不到 #
错误:
page.click: Timeout 30000ms exceeded解决:
// 1. 先等待元素出现
await page.waitForSelector('#button');
await page.click('#button');
// 2. 使用更精确的选择器
await page.click('button.submit-btn');
// 3. 检查元素是否在 iframe 中
const frame = page.frame({ name: 'iframe-name' });
await frame.click('#button');问题 3: 系统依赖缺失 #
错误:
error while loading shared libraries: libatk-1.0.so.0解决:
# 自动安装所有依赖
npx playwright install-deps chromium成本对比 #
| 方案 | 时间成本 | 稳定性 | 学习曲线 |
|---|---|---|---|
| 手动操作 | 高(每天 30 分钟+) | 高 | 无 |
| 找外包开发 | 中(一次性) | 中 | 无 |
| 自己写 Playwright | 低(一次性学习) | 高 | 中(1-2 天上手) |
下一步行动 #
- 安装 Playwright:
npm install -D playwright - 运行第一个脚本:截图示例
- 尝试表单填写:找个需要登录的网站练习
- 学习数据抓取:用
page.evaluate()提取信息
老黄的笔记:
我花了一下午配置好 Playwright 环境。
现在可以自动访问任意网站、截图、抓取数据。 原本需要手动操作的重复工作,现在一个脚本搞定。
这个投资回报率,值。⚙️