Node.js库Puppeteer常用API及骚操作总结
导读
这篇文章,主要用于收集整理常用的Puppeteer
的一些常用API操作,自动化操作,爬虫测试,基础使用等等。当然至于是什么是Puppeteer
呢,我们来看下官方介绍:Puppeteer
是谷歌官方出品的一个通过DevTools
协议控制headless Chrome
的Node
库。可以通过Puppeteer的提供的api直接控制Chrome模拟大部分用户操作来进行UI Test
或者作为爬虫访问页面来收集数据。

首先备注好中文API文档地址:点击打开Puppeteer中文文档API查看访问URL地址 官方API文档地址:github.com/GoogleChrom… 比较不错的新手文档资料参考:小一辈无产阶级码农的《Puppeteer 入门教程》
环境和安装
cnpm i puppeteer -S
安装的时候需要注意deshi ,Puppeteer
安装时自带一个最新版本的Chromium,可以通过设置环境变量或者npm config中的PUPPETEER_SKIP_CHROMIUM_DOWNLOAD
跳过下载。如果不下载的话,启动时可以通过puppeteer.launch([options])配置项中的executablePath
指定Chromium的位置。
基本使用
我们可以通过操作Browser
实例来操作浏览器作出对应的事情,比如生成页面,窗口截图、生成pdf文件(文字可复制),获取页面数据等等,这些都是可以做到的。
const puppeteer = require('puppeteer');
(async () => {
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.goto('http://rennaiqian.com');
await page.screenshot({path: 'example.png'});
await page.pdf({path: 'example.pdf', format: 'A4'});
await browser.close();
})();
当然,我们也可以新增一个headless:true
,不打开浏览器就能执行我们的各种操作,默认后台运行,修改如下:
const browser = await puppeteer.launch({headless:false})
new browser.newPage()
: 这个方法可以打开一个新选项卡并返回选项卡的实例page,通过page上的各种方法可以对页面进行常用操作。上述代码就进行了截屏和打印pdf的操作。

page.evaluate(pageFunction, ...args)
来实现这一目的,向页面注入我们的自定义函数:
const puppeteer = require('puppeteer');
(async () => {
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.goto('http://rennaiqian.com');
// Get the "viewport" of the page, as reported by the page.
const dimensions = await page.evaluate(() => {
// 在这里可以进行DOM操作
return {
width: document.documentElement.clientWidth,
height: document.documentElement.clientHeight,
deviceScaleFactor: window.devicePixelRatio
};
});
console.log('Dimensions:', dimensions);
await browser.close();
})();
爬虫相关实现
当然,这个puppeteer
这个框架,用的最多的地方就是在数据爬虫,页面模拟点击操作,用户名密码自动输入,表单提交,cookie无密码登录等等这些操作;

1. 模拟切换设备
这些操作呢,基本上都需要识别当前的设备,所以我们如何来模拟我们的当前设备呢?我们可以通过page.emulate(mobile)
来模拟我们所需要的设备,如下所示:
const puppeteer = require('puppeteer');
const devices = require('puppeteer/DeviceDescriptors'); // puppeteer内置的一些常见设备的模拟参数
const iPhone = devices['iPhone 6'];
puppeteer.launch().then(async browser => {
const page = await browser.newPage();
await page.emulate(iPhone);
await page.goto('https://www.example.com');
// other actions...
await browser.close();
});
2. 模拟点击输入
使用puppeteer
的童鞋大多数都是奔着,自动化测试,使用脚本自动操作页面内容来着,爬取动态加载网页;所以呢,模拟点击输入整个功能是非常重要,且十分方便的,非常类似于selenium
框架,但是比这个框架配置要简单得多,直接安装就可以使用了,好,接下来我们就来看看这个点击输入又是怎么完成的呢?
首先我们需要对点击输入分一下类别,分成 ==键盘==和==鼠标==操作,那我们分别来看下有哪些键盘和鼠标操作?
2-1. 键盘操作
首先我们列出常用的一些API,再罗列出常用的一些小案例:
- keyboard.down(key[, options]) :触发 keydown 事件
- keyboard.press(key[, options]) :按下某个键,key 表示键的名称,比如 ‘ArrowLeft’ 向左键,详细的键名映射* 请戳这里
- keyboard.sendCharacter(char) :输入一个字符
- keyboard.type(text, options) :输入一个字符串
- keyboard.up(key) :触发 keyup 事件
接下来展示一些常用到的一些小案例:
page.keyboard.press("Shift"); //按下 Shift 键
page.keyboard.sendCharacter('嗨'); // 输入一个字符
page.keyboard.type('Hello'); // 一次输入完成
page.keyboard.type('World', {delay: 100}); // 像用户一样慢慢输入

2-2. 鼠标操作
- mouse.click(x, y, [options]) :移动鼠标指针到指定的位置,然后按下鼠标,这个其实 mouse.move 和mouse.down 或 mouse.up 的快捷操作
- mouse.down([options]) :触发 mousedown 事件,options 可配置:
- options.button 按下了哪个键,可选值为 [left, right, middle], 默认是 left, 表示鼠标左键
- options.clickCount 按下的次数,单击,双击或者其他次数
- delay 按键延时时间
- mouse.move(x, y, [options]): 移动鼠标到指定位置, options.steps 表示移动的步长
- mouse.up([options]) :触发 mouseup 事件
3. 修改浏览器运行配置
在我们爬虫的过程中,经常会遇到各式各样请求头的问题,比较经常遇到的就是user-agent
等等这些参数,所以如果我们可以直接修改这些配置的话,就可以很好的进行爬虫工作了;而且呢,这个puppeteer
同时给我们提供了一些 API
可以让我们修改浏览器终端的配置:
- Page.setViewport() :修改浏览器视窗大小
- Page.setUserAgent() :设置浏览器的 UserAgent 信息
- Page.emulateMedia() :更改页面的CSS媒体类型,用于进行模拟媒体仿真。 可选值为 “screen”, “print”, “null”, 如果设置为 null 则表示禁用媒体仿真。
- Page.emulate() :模拟设备,参数设备对象,比如 iPhone, Mac, Android 等,爬H5页面,亲测很好用
再接着,我们来看一下一些常用的小案例:
page.setViewport({width:1920, height:1080}); //设置视窗大小为 1920x1080
page.setUserAgent('Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36');
page.emulateMedia('print'); //设置打印机媒体样式
除此之外我们还可以模拟非 PC 机设备, 比如下面这段代码模拟 iPhone 6
访问百度:
const puppeteer = require('puppeteer');
const devices = require('puppeteer/DeviceDescriptors');
const iPhone = devices['iPhone 6'];
puppeteer.launch().then(async browser => {
const page = await browser.newPage();
await page.emulate(iPhone);
await page.goto('https://www.baidu.com');
// other actions...
await browser.close();
});
4. 获取页面元素
这里呢,我们来探讨下,如何使用pupeteer
来获取页面的元素,以及元素里的内容及属性;因为这也是使用非常非常频繁的操作,但是呢,估计大家都比较熟悉,所以呢,把它放在后面进行讲解;
4-1. 获取页面的元素节点
(1) Page.$(selector)
获取单个元素,底层是调用的是 document.querySelector()
, 所以选择器的 selector
格式遵循 css
选择器规范
let inputElement = await page.$("#search", input => input);
//下面写法等价
let inputElement = await page.$('#search');
(2) Page.?(selector)
获取一组元素,底层调用的是 document.querySelectorAll()
. 返回 Promise(Array(ElemetHandle))
元素数组.
const links = await page.?("a");
//下面写法等价
const links = await page.?("a", links => links);
4-1. 获取页面的元素属性
Puppeteer
获取元素属性跟我们平时写前段的js的逻辑有点不一样,按照通常的逻辑,应该是现获取元素,然后在获取元素的属性。但是上面我们知道 获取元素的 API 最终返回的都是 ElemetHandle
对象,而你去查看 ElemetHandle 的 API 你会发现,它并没有获取元素属性的 API.
而 Puppeteer
专门提供了一套获取属性的 API, Page.$eval()
和 Page.?eval()
const value = await page.$eval('input[name=search]', input => input.value);
const href = await page.$eval('#a", ele => ele.href);
const content = await page.$eval('.content', ele => ele.outerHTML);

5. 执行自定义的 JS 脚本
执行自定义脚本也是目前来说爬虫中,比较常用的一些功能,通过自定义脚本去拿到接口的签名等等,都是比较一种非常不错的爬虫方式,好,那我们就一起来看看如何向页面动态植入自定义脚本呢?
Puppeteer
的 Page
对象提供了一系列 evaluate 方法,你可以通过他们来执行一些自定义的 js 代码,主要提供了下面三个 API
5-1. page.evaluate(pageFunction, …args)
这个page.evaluate
返回一个可序列化的普通对象,pageFunction 表示要在页面执行的函数, args
表示传入给 pageFunction
的参数, 下面的 pageFunction 和 args 表示同样的意思。
const result = await page.evaluate(() => {
return Promise.resolve(8 * 7);
});
console.log(result); // 56
5-2. Page.evaluateHandle(pageFunction, …args)
这个evaluateHandle
在 Page 上下文执行一个 pageFunction, 返回 JSHandle 实体
const aWindowHandle = await page.evaluateHandle(() => Promise.resolve(window));
aWindowHandle; // Handle for the window object.
const aHandle = await page.evaluateHandle('document'); // Handle for the 'document'.
下面这段代码实现获取页面的动态(包括js动态插入的元素) HTML 代码:
const aHandle = await page.evaluateHandle(() => document.body);
const resultHandle = await page.evaluateHandle(body => body.innerHTML, aHandle);
console.log(await resultHandle.jsonValue());
await resultHandle.dispose();
5-3. Page.exposeFunction
Page.exposeFunction
,这个 API 用来在页面注册全局函数,非常有用:
因为有时候需要在页面处理一些操作的时候需要用到一些函数,虽然可以通过 Page.evaluate()
API 在页面定义函数,比如下面代码实现给 Page 上下文的 window 对象添加 md5 函数:
const puppeteer = require('puppeteer');
const crypto = require('crypto');
puppeteer.launch().then(async browser => {
const page = await browser.newPage();
page.on('console', msg => console.log(msg.text));
await page.exposeFunction('md5', text =>
crypto.createHash('md5').update(text).digest('hex')
);
await page.evaluate(async () => {
// use window.md5 to compute hashes
const myString = 'PUPPETEER';
const myHash = await window.md5(myString);
console.log(`md5 of ${myString} is ${myHash}`);
});
await browser.close();
});
可以看出,Page.exposeFunction API
使用起来是很方便的,也非常有用,在比如给 window
对象注册 readfile
全局函数:
const puppeteer = require('puppeteer');
const fs = require('fs');
puppeteer.launch().then(async browser => {
const page = await browser.newPage();
page.on('console', msg => console.log(msg.text));
await page.exposeFunction('readfile', async filePath => {
return new Promise((resolve, reject) => {
fs.readFile(filePath, 'utf8', (err, text) => {
if (err)
reject(err);
else
resolve(text);
});
});
});
await page.evaluate(async () => {
// use window.readfile to read contents of a file
const content = await window.readfile('/etc/hosts');
console.log(content);
});
await browser.close();
});
6. 等待执行
等待执行相关的 API 主要由 Page.waitFor
所提供
page.waitFor(selectorOrFunctionOrTimeout[, options[, …args]])
,下面三个的综合 APIpage.waitForFunction(pageFunction[, options[, …args]])
,等待 pageFunction 执行完成之后page.waitForNavigation(options)
,等待页面基本元素加载完之后,比如同步的 HTML, CSS, JS 等代码page.waitForSelector(selector[, options])
,等待某个选择器的元素加载之后,这个元素可以是异步加载的,这个 API 非常有用,你懂的。

比如我想获取某个通过 js 异步加载的元素,那么直接获取肯定是获取不到的。这个时候就可以使用 page.waitForSelector
来解决:
await page.waitForSelector('.gl-item'); //等待元素加载之后,否则获取不到异步加载的元素
const links = await page.?eval('.gl-item > .gl-i-wrap > .p-img > a', links => {
return links.map(a => {
return {
href: a.href.trim(),
name: a.title
}
});
});
7. 自动化网页性能测试
通过 page.getMetrics()
可以得到一些页面性能数据, 捕获网站的时间线跟踪,以帮助诊断性能问题。
- Timestamp 度量标准采样的时间戳
- Documents 页面文档数
- Frames 页面 frame 数
- JSEventListeners 页面内事件监听器数
- Nodes 页面 DOM 节点数
- LayoutCount 页面布局总数
- RecalcStyleCount 样式重算数
- LayoutDuration 所有页面布局的合并持续时间
- RecalcStyleDuration 所有页面样式重新计算的组合持续时间。
- ScriptDuration 所有脚本执行的持续时间
- TaskDuration 所有浏览器任务时长
- JSHeapUsedSize JavaScript 占用堆大小
- JSHeapTotalSize JavaScript 堆总量
总结
总的来说, puppeteer
是一款非常不错的 headless
工具,操作简单,功能强大。用来做UI自动化测试,和一些小工具都是很不错的。
转载自:https://juejin.cn/post/6844903997845962759