传统爬虫遇到动态加载内容就束手无策——页面数据通过AJAX异步加载、需要执行JavaScript才能渲染、登录状态校验严格。Playwright作为现代浏览器自动化工具,能完美模拟人类操作:
- 支持Chromium/Firefox/WebKit三大内核
- 自动等待元素加载完成
- 可处理Cookie和本地存储
- 执行复杂交互动作
环境准备(Node.js示例)
npm init -y
npm install playwright
建议使用async/await语法,处理异步操作更直观。初始化浏览器实例时,建议关闭headless模式调试:
const { chromium } = require('playwright');
(async () => {
const browser = await chromium.launch({
headless: false, // 调试时设为可见
slowMo: 500 // 操作延迟毫秒数
});
})();
突破登录验证的4个关键步骤
1. 模拟登录流程
以知乎为例,需要处理手机号+密码登录:
const page = await browser.newPage();
await page.goto('https://www.zhihu.com/signin');
// 切换至密码登录标签
await page.click('div.SignContainer-switch span');
// 填写表单
await page.fill('input[name="username"]', 'your_phone');
await page.fill('input[name="password"]', 'your_password');
// 触发验证码(如有)
await page.click('button.SignFlow-submitButton');
// 人工介入处理验证码
await page.waitForTimeout(30000); // 留30秒手动操作
2. 保存登录状态
避免每次重复登录,可持久化存储cookies:
// 登录成功后获取cookies
const cookies = await page.context().cookies();
const fs = require('fs');
fs.writeFileSync('cookies.json', JSON.stringify(cookies));
// 下次启动时恢复会话
const loadedCookies = JSON.parse(fs.readFileSync('cookies.json'));
await page.context().addCookies(loadedCookies);
3. 处理动态加载内容
典型场景:滚动加载的微博feed流
// 连续滚动5次
for (let i = 0; i < 5; i++) {
await page.evaluate(() => window.scrollTo(0, document.body.scrollHeight));
await page.waitForSelector('div.new-loading', { state: 'hidden' });
}
// 获取所有动态内容
const posts = await page.$$eval('div.WB_feed_detail', nodes =>
nodes.map(n => ({
content: n.querySelector('div.WB_text').innerText,
time: n.querySelector('div.WB_from').innerText
}))
);
4. 绕过反爬机制
- 随机延迟:在关键操作间添加
page.waitForTimeout(Math.random() * 3000 + 1000)
- 修改指纹:启动时传入userAgent参数
- 代理IP:通过
proxy
配置项实现 - 规避检测:禁用WebDriver特征
const browser = await chromium.launch({
args: [
'--disable-blink-features=AutomationControlled'
],
proxy: {
server: 'http://proxy.example.com:8080'
}
});
实战案例:抓取淘宝商品评论
- 登录后跳转目标商品页
- 自动点击"累计评论"标签
- 循环点击"下一页"直到末页
- 使用
page.$$eval
提取评论数据 - 异常处理:网络超时/元素消失/验证码触发
try {
await page.click('div.tab-panel li[data-value="feed"]', { timeout: 5000 });
} catch (err) {
console.log('可能遇到验证码,需要人工干预');
await page.screenshot({ path: 'error.png' });
}
性能优化建议
- 并行处理:创建多个browserContext实现并发
- 资源控制:
page.route
拦截不必要的图片/样式表请求 - 内存管理:定期关闭闲置page实例
- 错误重试:实现指数退避重试机制
// 拦截图片请求
await page.route('**/*.{png,jpg,jpeg}', route => route.abort());
遇到验证码怎么办?推荐两种方案:
- 商业打码平台(超验/联众等)
- 人工介入时使用
page.pause()
进入调试模式
记住:遵守robots.txt协议,控制请求频率,避免对目标网站造成负担。