持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第3天,点击查看活动详情
前言
最近公司需要做一个爬虫来定时抓数据,通常的方案就是发送请求分析响应报文,但页面内容是异步加载的,还有表单什么的,网上一搜就发现了Puppteer这个好东西。
Puppeteer 是一个 Node 库,它提供了一个高级 API 来通过 DevTools 协议控制 Chromium 或 Chrome。说白了就是可以模拟人进行浏览器操作,只要理清操作步骤,就可以随便玩了。
安装
官方提供了两个包:puppeteer和puppeteer-core,区别是前者会在安装时下载chromium浏览器而后者不会,国内下载chromium比较慢,而且我们可以直接使用chrome,所以直接安装puppteer-core就行了。
npm install -S puppeteer-core
开始使用
puppeteer的使用比较简单,分为三步:
- 启动浏览器,新建页面
- 执行页面操作
- 关闭浏览器
const puppeteer = require('puppeteer-core');
// 本地chrome执行文件路径
const executablePath = '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome';
async function start() {
const browser = await puppeteer.launch({
executablePath,
headless: false, // 表示是否在前台显示浏览器窗口,默认为true表示不显示,在后台操作
});
const page = await browser.newPage();
// ... 执行page操作
await browser.close();
}
如何找到chrome执行文件路径?
Mac上一般跟我代码里的路径一样,实在不知道可以下载一个叫carlo
的包来查询。
// npm install -S carlo
const findChrome = require('carlo/lib/find_chrome');
async function findChromePath() {
let ChromePath = await findChrome({});
let executablePath = ChromePath.executablePath;
return executablePath;
}
findChromePath().then((data) => console.log(data));
制作一个爬虫
既然puppteer是模拟人的操作,那么爬虫的基本过程就是访问一个页面,然后在页面上下文中执行JS代码获取数据。没错,puppeteer提供了执行JS和访问WebAPI的能力,一切就和人在控制台里写代码一样。
比如我们访问豆瓣读书,想要获取新书速递里面的内容,那我们的步骤就是:
- 启动浏览器,新建页面
- 页面导航至豆瓣读书URL:book.douban.com/
- 获取目标元素的selector
- 使用DOM访问并返回元素内容
let scrape = async () => {
const browser = await puppeteer.launch({
executablePath,
headless: true, // 默认为true,可以不写
});
const page = await browser.newPage();
await page.goto('https://book.douban.com');
// page.evaluate可以在页面上下文中执行JS代码
const result = await page.evaluate(() => {
const bookList = document.querySelectorAll(
'#content > div > div.article > div.section.books-express > div.bd > div.carousel > div > ul:nth-child(2) >li > .info'
);
return Array.from(bookList).map((item) => {
const title = item.querySelector('.title').innerText;
const author = item.querySelector('.author').innerText;
return { title, author };
});
});
await browser.close();
return result;
};
scrape().then((result) => console.log(result));
执行结果如下:
[
{ title: '我生于美洲', author: '[意大利] 伊塔洛·卡尔维诺' },
{ title: '犬之力', author: '[美] 托马斯•萨维奇' },
{ title: '鸭镇夜色:王奎张亮故事集', author: '' },
{ title: '椰风蕉雨:南洋故事集', author: '刘以鬯 / 梅子 编' },
{ title: '帕特森:威廉斯的诗', author: '[美国] 威廉·卡洛斯·威廉斯' },
{ title: '贫穷的质感:王梆的英国观察', author: '' },
{ title: '千里江山图', author: '孙甘露' },
{ title: '希腊人与非理性', author: '[爱尔兰] E.R.多兹' },
{ title: '活着为了讲述', author: '[哥伦比亚] 加西亚·马尔克斯' },
{ title: '德勒兹归来:不可思议的俄耳甫斯之新历险', author: '[德]马丁·汤姆·迪克 / [德]延斯·巴尔策' }
]
如何快速获取元素selector?
浏览器交互
puppeteer提供了很多API模拟人和浏览器的交互操作,比如鼠标移动、键盘输入等。
比如我们模拟在百度上搜“儿童节”的相关信息,步骤如下:
- 启动浏览器,新建页面
- 页面导航至百度URL:www.baidu.com/
- 输入关键词并回车
let search = async () => {
const browser = await puppeteer.launch({
executablePath,
headless: false,
});
const page = await browser.newPage();
await page.setViewport({ width: 1440, height: 900 }); // 设置页面大小
await page.goto('https://www.baidu.com');
await page.keyboard.type('儿童节');
await page.keyboard.press('Enter');
};
search();
其它的功能还有截图、生成PDF等等,反正你能在浏览器上做的操作,puppeteer都能帮你做,大家自己去API里翻一番,还是挺有趣的。
最后祝大家儿童节快乐!