puppeteer知识汇总
Published in:2024-08-29 | category: 爬虫


1. Puppeteer 特点

Puppeteer 是一个强大的 Web 爬虫工具,具有以下主要特点:

  • 控制浏览器: 可以启动和控制 Headless(无头)或有头的 Chrome/Chromium 浏览器实例。
  • 执行 JavaScript: 能够处理和渲染需要执行 JavaScript 的动态页面。
  • 模拟用户操作: 可以模拟用户在浏览器中的各种操作,如点击、输入、导航等。
  • 适用于动态内容: 特别适合那些需要执行 JavaScript 才能获取内容的页面。

2. 性能优化

提升 Puppeteer 爬取性能的主要方案包括:

2.1 禁用不必要的资源加载

1
2
3
4
5
6
7
8
await page.setRequestInterception(true);
page.on('request', (req) => {
if (['image', 'stylesheet', 'font'].includes(req.resourceType())) {
req.abort();
} else {
req.continue();
}
});

2.2 使用无头模式(Headless)

1
const browser = await puppeteer.launch({ headless: true });

2.3 并行化操作

使用puppeteer-cluster库来实现并行处理:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
const { Cluster } = require('puppeteer-cluster');

const cluster = await Cluster.launch({
concurrency: Cluster.CONCURRENCY_CONTEXT,
maxConcurrency: 5,
});

await cluster.task(async ({ page, data: url }) => {
await page.goto(url);
// 执行爬取逻辑
});

// 添加URL到集群中
cluster.queue('http://example.com');

2.4 使用持久化浏览器实例

1
const browser = await puppeteer.launch({ userDataDir: './user_data' });

2.5 设置合理的超时和重试机制

1
2
const page = await browser.newPage();
await page.goto(url, { timeout: 30000, waitUntil: 'networkidle0' });

2.6 优化页面加载和等待策略

1
await page.goto(url, { waitUntil: 'domcontentloaded' });

2.7 调整浏览器配置

1
2
3
const browser = await puppeteer.launch({
args: ['--no-sandbox', '--disable-setuid-sandbox', '--disable-dev-shm-usage']
});

3. 反爬虫策略及解决方法

3.1 用户代理检测

解决方法:伪装用户代理

1
await page.setUserAgent('Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36');

3.2 IP 限制

解决方法:使用代理池

1
2
3
const browser = await puppeteer.launch({
args: ['--proxy-server=http://proxy-server-address:port']
});

3.3 设备指纹

解决方法:无头浏览器-伪装设备指纹

1
2
3
4
5
await page.evaluateOnNewDocument(() => {
Object.defineProperty(navigator, 'webdriver', {
get: () => undefined,
});
});

3.4 验证码

解决方法:对于图片验证码,可以使用打码平台或机器学习方法。对于滑动验证码,可以使用以下流程:

  1. 加载完成后截图
  2. 识别旋转角度(使用打码平台或机器学习,或从页面属性中获取)
  3. 使用 sharp 控制旋转
  4. 替换原图

3.5 动态内容加载

解决方法:使用 Puppeteer 等无头浏览器模拟浏览器环境执行 JavaScript

3.6 访问频率控制

解决方法:降低抓取频率,添加随机延迟

1
await page.waitForTimeout(Math.floor(Math.random() * 3000) + 1000);

3.7 内容混淆

解决方法:分析并解密混淆的内容

3.8 行为分析

解决方法:使用 Puppeteer 模拟人类用户行为

1
2
await page.hover('selector');
await page.click('selector');

4. 错误处理和稳定性

4.1 爬取失败重试

使用指数退避(Exponential Backoff)策略:

1
2
3
4
5
6
7
8
9
const retry = async (fn, retries = 3, delay = 1000) => {
try {
return await fn();
} catch (err) {
if (retries <= 0) throw err;
await new Promise(resolve => setTimeout(resolve, delay));
return retry(fn, retries - 1, delay * 2);
}
};

4.2 子进程崩溃

  • 使用 PM2 监控和自动重启
  • 使用 Puppeteer Cluster 管理浏览器实例
  • 实施健壮性措施:
    • 释放资源
    • 分批抓取
    • 超时处理
    • 定期重启

4.3 内存泄漏预防

  • 及时关闭浏览器实例和页面
  • 使用puppeteer-cluster进行资源管理
  • 避免全局变量和未释放的对象
  • 定期重启浏览器实例
1
2
await page.close();
await browser.close();

4.4 判断僵尸进程

可以使用以下命令检查僵尸进程:

1
ps aux | grep 'Z'

1
pgrep -l -x ".*" | grep -w Z

5. 最佳实践

  1. 遵守网站的robots.txt规则和使用条款。
  2. 实现合理的请求间隔和并发限制。
  3. 定期更新和维护爬虫代码,以适应目标网站的变化。
  4. 实现全面的错误处理和日志记录。
  5. 考虑使用数据库或队列系统来管理大规模爬取任务。
  6. 定期检查和优化性能,特别是在大规模爬取时。

通过遵循这些最佳实践和技巧,你可以构建一个高效、稳定且难以被检测的 Puppeteer 爬虫系统。

Next:
前端知识体系