前端数据爬虫之puppeteer
puppeteer能做什么
-
生成页面 PDF。
-
抓取 SPA(单页应用)并生成预渲染内容(即"SSR"(服务器端渲染))。
-
自动提交表单,进行 UI 测试,键盘输入等。
-
创建一个时时更新的自动化测试环境。 使用最新的 JavaScript 和浏览器- 功能直接在最新版本的Chrome中执行测试。
-
捕获网站的 timeline trace,用来帮助分析性能问题。
-
测试浏览器扩展
安装
npm i puppeteer
使用
请使用高版本的node
官网说需要使用Node v6.4.0(async/await需要在Node v7.6.0)及以上版本,但是实测Node v14.21.3 运行不起来,目前我用的是 Node v22.1.0
创建文件
文件名为:example.js
js
// 引入官网的一个例子,生成一个 example.png 图片
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: 'example.png'});
await browser.close();
})();
执行命令
node example.js
API解读
puppeteer.launch()
创建一个浏览器实例
js
const browser = await puppeteer.launch({
ignoreHTTPSErrors: false, // 是否在导航期间忽略 HTTPS 错误. 默认是 false。
executablePath: '', // 可运行浏览器的路径
slowMo: 10, // 将 Puppeteer 操作减少指定的毫秒数。这样你就可以看清发生了什么,这很有用。
defaultViewport: { // 默认视口大小,默认800*600。如果为null的话就禁用视口
width: 1920,
height: 1080
},
timeout: 3000, // 等待浏览器实例启动的最长时间(以毫秒为单位)。默认是 30000 (30 秒). 通过 0 来禁用超时。
env: 'process.env', // 指定浏览器可见的环境变量。默认是 process.env。
});
// 关闭浏览器
await browser.close();
browser.newPage()
提供操作一个 tab 页,一个 Browser 实例可以有多个 Page 实例。
js
const page = await browser.newPage();
监听事件 on
、once
、removeListener
Page会触发多种事件,可以用 node 原生的方法 来捕获处理,比如 on,once 或者 removeListener
- 语法
js
/**
* 页面事件监听
* @param {String} eventName 事件名称
* @param {Function} Function 监听事件回调
*/
page.on(eventName, Function)
- 示例
js
page.on("request", (request) => {
// 当请求发起后页面会触发这个事件。
request.continue();
});
age.on("response", (response) => {
// 请求收到响应的时候触发。
// const headers = response.headers();
});
page.on("requestfailed", (request) => {
// 请求失败时触发
// console.log(request.url());
});
page.on("requestfinished", (request) => {
// 请求完成并且响应体下载完成时触发
// console.log(request.url());
});
page.on('framenavigated', (frame) => {
// 监听url改变
// frame.url()
})
页面导航/跳转 goto
- 语法
js
/**
* 页面导航/跳转
* @param {String} url 航到的地址. 地址应该带有http协议, 比如 https://.
* @param {Object} options 导航配置,可选值
* @param {String} options.timeout 跳转等待时间,单位是毫秒, 默认是30秒, 传 0 表示无限等待
* @returns {Promise} Promise对象resolve后是主要的请求的响应。如果有多个跳转, resolve后是最后一次跳转的响应
*/
page.goto(url[, options])
- 示例
js
page.goto('https://www.baidu.com/')
执行 JavaScript evaluate
- 语法
js
/**
* 执行 JavaScript
* @param {Funtion | String} pageFunction 要在页面实例上下文中执行的方法
* @param {Object} args 要传给 pageFunction 的参数
* @returns {Promise} pageFunction执行的结果
* @description 如果pageFunction返回的是Promise,page.evaluate将等待promise完成,并返回其返回值。
* @description 如果pageFunction返回的是不能序列化的值,将返回undefined
*/
page.evaluate(pageFunction[, ...args])
- 示例
js
const result = await page.evaluate(x => {
return Promise.resolve(8 * x);
}, 7); // (译者注: 7 可以是你自己代码里任意方式得到的值)
console.log(result); // 输出 "56"
console.log(await page.evaluate('1 + 2')); // 输出 "3"
const x = 10;
console.log(await page.evaluate(`1 + ${x}`)); // 输出 "11"
选择元素 $
、$$
、$eval
、$$eval
- 语法
js
/**
* 选择元素
* @param {String} selector 选择器
*/
page.$(selector) // 此方法在页面内执行 document.querySelector。如果没有元素匹配指定选择器,返回值是 null。
page.$$(selector) // 此方法在页面内执行 document.querySelectorAll。如果没有元素匹配指定选择器,返回值是 []。
/**
* 选择元素
* @param {String} selector 选择器
* @param {Function} pageFunction 在浏览器实例上下文中要执行的方法
* @param {Object} args 要传给 pageFunction 的参数
*/
page.$eval(selector, pageFunction[, ...args]) // 此方法在页面内执行 document.querySelector,然后把匹配到的元素作为第一个参数传给 pageFunction。
page.$$eval(selector, pageFunction[, ...args]) // 此方法在页面内执行 Array.from(document.querySelectorAll(selector)),然后把匹配到的元素数组作为第一个参数传给 pageFunction。
- 示例
js
const searchValue = await page.$eval('#search', el => el.value);
const preloadHref = await page.$eval('link[rel=preload]', el => el.href);
const html = await page.$eval('.main-container', e => e.outerHTML);
const divsCounts = await page.$$eval('div', divs => divs.length)
等待指定的选择器匹配的元素出现在页面中 waitForSelector
- 语法
js
/**
* 等待指定的选择器匹配的元素出现在页面中
* @param {String} selector 要等待的元素选择器
* @param {Object} options 可选参数
* @param {Boolean} options.visible 等元素出现在dom中并且可以看到, 比如。 没有 display: none 或者 visibility: hidden 样式。 默认是 false。
* @param {Boolean} options.hidden 等元素在dom中消失或看不到, 比如。 有 display: none 或者 visibility: hidden 样式。 默认是 false。
* @param {Number} options.timeout 最大等待时间,单位是毫秒,默认是30000 (30 seconds),传0表示不会超时
* @returns {<Promise<ElementHandle>>} Promise对象,当指定选择器匹配的元素添加到dom中时
*/
page.waitForSelector(selector[, options])
- 示例
js
await page.waitForSelector('div)');
定位器 locator
- 语法
js
/**
* 定位某个元素
* @param {String} selector 选择器
*/
page.locator(selector);
- 示例
js
// 元素点击
await page.locator('button').click();
// 填写输入
await page.locator('input').fill('value');
// 将鼠标悬停在元素上
await page.locator('div').hover();
// 滚动一个元素
await page.locator('div').scroll({
scrollLeft: 10,
scrollTop: 20,
});
// 等待元素可见,等待元素变为 visible 或隐藏。
await page.locator('.loading').wait();