Puppeteer 入门使用教程
Puppeteer 介绍
Puppeteer 是什么
Puppeteer 是一个 NodeJs 库,它提供了一个高级 API 来通过 DevTools 协议控制 Chromium 或 Chrome。相比较 Selenium 或是 PhantomJs,它最大的特点就是完全可以在内存中模拟 DOM 操作,即在 V8 引擎中处理而不打开浏览器,而且关键的是该项目是 Chrome 团队在维护,会拥有更好的兼容性和前景,更多资料可参考以下站点:Puppeteer Github、Puppeteer 中文文档、DevTools Protocol 文档、Chromium 命令行启动参数。
Puppeteer 的功能
- 生成页面的截图和 PDF
- 自动提交表单,进行 UI 测试,键盘输入等
- 捕获网站的时间线跟踪,用来帮助分析性能问题
- 抓取 SPA(单页应用),并生成预渲染内容,即 “SSR”(服务器端渲染)
- 创建一个最新的自动化测试环境,使用最新的 JavaScript 和浏览器功能,直接在最新版本的 Chrome 中运行测试
- 测试浏览器扩展,Chrome / Chromium 扩展当前只能在非无头模式下使用,目前还无法测试扩展弹出窗口或内容脚本
Puppeteer VS Puppeteer-Core
使用区别
自 v1.7.0 以来的 Puppeteer 每个版本都会发布两个包:puppeteer、puppeteer-core,两者的区别如下:
- puppeteer 是浏览器自动化的产品,安装后它会下载一个最新版本的 Chromium,然后使用 puppeteer-core 驱动工作。作为最终用户产品,puppeteer 支持一堆方便的
PUPPETEER_*
环境变量来调整运行行为 - puppeteer-core 是一个库来帮助驱动任何支持 DevTools 协议的东西。puppeteer-core 在安装时不会下载 Chromium,作为一个库,puppeteer-core 完全是通过其编程接口驱动的,并且会忽略所有
PUPPETEER_*
环境变量
使用建议
在大多数情况下,可以使用 puppeteer 包,如果是下面这些情况,那可以使用 puppeteer-core:
- 正在构建使用 DevTools 协议的另一个最终用户产品或库;例如,可以使用 puppeteer-core 构建 PDF 生成器,并编写下载
headless_shell
的自定义install.js
脚本,而不是使用 Chromium 来节省磁盘空间 - 正在打包 Puppeteer 用在 Chrome 上的扩展应用或者浏览器中以使用 DevTools 协议,因为下载额外的 Chromium 二进制文件不是必须的
当需要使用 puppeteer-core 时,使用下面这行代码代替原来的引入方式即可:
1 | const puppeteer = require('puppeteer-core'); |
Puppeteer 运行环境与安装
Puppeteer 运行环境
Puppeteer 运行依赖于 NodeJs v6.4.0+,如果要使用 async /await,只有 NodeJs v7.6.0 或更高版本才支持,NodeJs 可以点击这里下载。
Puppeteer 安装
Puppeteer 安装的过程默认会执行 install.js
脚本来下载最新版本的 Chromium(请自备梯子),可以使用 --ignore-scripts
参数跳过 Chromium 的下载,也可以通过设置环境变量 PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=1
来跳过下载。
1 | # 安装puppeteer |
手动下载 Chromium 并解压在本地磁盘,下载可以点击这里(请自备梯子):
Puppeteer 入门案例
入门案例
初始化项目:
1 | $ npm init |
创建 index.js
文件,代码如下,executablePath
是 Chromium 或者 Chrome 可执行文件的路径:
1 | const puppeteer = require('puppeteer'); |
执行 index.js
脚本,运行成功后,会在当前目录下生成网页的截图文件 baidu.png
:
1 | $ node index.js |
启动参数
Puppeteer Launch 的启动参数如下:
- executablePath:Chromium 或 Chrome 可执行文件的路径
- headless:是否运行在浏览器
headless
模式,true 表示不打开浏览器执行,默认为 true - timeout:等待浏览器实例启动的最长时间(以毫秒为单位),默认为 30000,当值为 0 时表示禁用超时
- args:传递给浏览器实例的其他参数
Puppeteer 实战
Puppeteer 环境变量
Puppeteer 的环境变量如下,在使用 puppeteer-core 时,下述环境变量中以 PUPPETEER_*
开头的会被忽略:
- HTTP_PROXY、HTTPS_PROXY, NO_PROXY - 定义用于下载和运行 Chromium 的 HTTP 代理设置
- PUPPETEER_SKIP_CHROMIUM_DOWNLOAD - 请勿在安装步骤中下载绑定的 Chromium
- PUPPETEER_DOWNLOAD_HOST - 覆盖用于下载 Chromium 的 URL 的主机部分
- PUPPETEER_CHROMIUM_REVISION - 在安装步骤中指定一个 puppeteer 使用的特定版本的 Chromium
- PUPPETEER_EXECUTABLE_PATH - 指定一个 Chrome 或者 Chromium 可执行文件的路径,会被用于
puppeteer.launch
Puppeteer 的选择器
Puppeteer 中获取元素的方法和浏览器里面的一样,但是获取元素的属性的办法和浏览器不一样,它有一套 API 用来获取界面中的元素,还有一套 API 用来获取元素的属性。
获取元素的操作如下:
1 | // Page.$(selector) 获取单个元素,底层是调用的是 document.querySelector(),所以选择器的 selector 格式遵循 CSS 选择器规范 |
获取元素的属性的操作如下:
1 | // Puppeteer 获取元素属性跟平时写 JavaScript 的逻辑有点不一样,按照通常的逻辑,应该是现获取元素,然后再获取元素的属性 |
常用的元素选择器:
选择器 | 示例 | 示例说明 |
---|---|---|
id 选择器 | #id | 选择匹配 id 的元素,仅存在一个 |
class 选择器 | .class | 同时匹配多个 class 元素 |
属性选择器 | div[attr] | 匹配具有 attr 的属性,不考虑具体的值 |
属性选择器 | div[attr=‘122‘] | 匹配具有 attr 的属性,值为 122 |
后代选择器 | div span | 后代选择器,匹配所有 div 后面的 span 标签,div 与 span 之间用空格隔开 |
子元素选择器 | div > span | 子元素选择器,匹配 div 后所有的 span |
匹配父元素下的第 n 个子元素 | div:nth-child(2) | 匹配父元素下的第 2 个元素 |
SegmentFault 模拟登录
1 | const puppeteer = require('puppeteer'); |
Puppeteer 结合 Jest 使用
Puppeteer 周边的开源项目
- jvppeteer,Java 版的 Puppeteer
- pyppeteer,Python 版的 Puppeteer
- awesome-puppeteer,Puppeteer 相关的开源项目整理
- docker-puppeteer,A minimal Docker image for Puppeteer
- puppeteer-cluster,Puppeteer Pool, run a cluster of instances in parallel
- puppeteer-deep,爬取《es6 标准入门》、自动推文到掘金、站点性能分析;高级爬虫、自动化 UI 测试、性能分析的实践案例
- puppeteer-recorder,Puppeteer recorder is a Chrome extension that records your browser interactions and generates a Puppeteer script