Puppeteer 爬虫工具:专业的无头浏览器(Chrome / Chromium)
Puppeteer
Puppeteer 是一个 Node 库,它提供了一个高级 API 来通过 DevTools 协议控制 Chromium 或 Chrome。Puppeteer 默认以 headless模式运行,但是可以通过修改配置文件运行「有头」模式。
它能做什么?
你可以在浏览器中手动执行的绝大多数操作都可以使用 Puppeteer 来完成! 下面是一些示例:
- 生成页面截屏和 PDF。
- 抓取 SPA(单页应用)并生成预渲染内容(即「SSR」(服务器端渲染))。
- 自动提交表单,进行 UI 测试,键盘输入等。
- 创建一个时时更新的自动化测试环境。 使用最新的 JavaScript 和浏览器功能直接在最新版本的Chrome 中执行测试。
- 捕获网站的 timeline trace,用来帮助分析性能问题。
- 测试浏览器扩展。
演示地址: try-puppeteer.appspot.com/
开始使用
安装
在项目中使用 Puppeteer:
npm i puppeteer
# or
yarn add puppeteer
Note: 当你安装 Puppeteer 时,它会下载最新版本的Chromium(~170MB Mac,~282MB Linux,~280MB Win),以保证可以使用 API。 如果想要跳过下载,请阅读环境变量。
puppeteer-core
自 1.7.0 版本以来,我们都会发布一个 puppeteer-core
包,这个包默认不会下载 Chromium。
npm i puppeteer-core
# or
yarn add puppeteer-core
puppeteer-core
是一个的轻量级的 Puppeteer 版本,用于启动现有浏览器安装或连接到远程安装。确保您安装的 puppeteer-core 版本与您打算连接的浏览器兼容。
具体见 puppeteer vs puppeteer-core.
参见 puppeteer vs puppeteer-core。
用法
Puppeteer 遵循 Node 的最新 maintenance LTS 版本。
注意:在 v1.18.1 之前,Puppeteer 至少需要 Node v6.4.0。从 v1.18.1 到v2.1.0 的版本都依赖于 Node 8.9.0+。从 v3.0.0 开始,Puppeteer 开始依赖于 Node 10.18.1+。以下所有示例均使用 async / await,只有 Node v7.6.0 或更高版本才支持。
使用其他浏览器测试框架的人会熟悉 Puppeteer 。您创建一个Browser
实例,打开页面,然后使用 Puppeteer's API 操作页面。
示例 -导航至 example.com 并将截屏另存为 example.png:
将文件另存为 example.js
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();
}
)();
在命令行执行脚本 hn.js
const puppeteer = require('puppeteer');
(async () => {
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.goto('https://news.ycombinator.com', {waitUntil: 'networkidle2'});
await page.pdf({path: 'hn.pdf', format: 'A4'});
await browser.close();
}
)();
在命令行执行脚本
node hn.js
更多有关创建 pdf 的信息,请参见 Page.pdf()
。
示例 -在页面上下文中运行脚本
将文件另存为 get-dimensions.js
const puppeteer = require('puppeteer');
(async () => {
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.goto('https://example.com');
// 获取页面视图大小,返回给页面。
const dimensions = await page.evaluate(() => {
return {
width: document.documentElement.clientWidth,
height: document.documentElement.clientHeight,
deviceScaleFactor: window.devicePixelRatio
};
});
console.log('Dimensions:', dimensions);
await browser.close();
}
)();
在命令行上执行脚本
node get-dimensions.js
请参阅 Page.evaluate()
了解有关 evaluate
的方法,例如evaluateOnNewDocument
和exposeFunction
。
默认运行时设置
1. 使用无头模式
Puppeteer 以无头模式启动 Chromium 。要启动 Chromium 的完整版本,请在启动浏览器时设置无头
选项:
const browser = await puppeteer.launch({headless: false}); // default is true
2. 运行版本捆绑的 Chromium
默认情况下,Puppeteer 下载并使用特定版本的 Chromium ,因此可以保证其 API 可以直接使用。要将 Puppeteer 与其他版本的 Chrome 或 Chromium 一起使用,请在创建 Browser
实例时输入可执行文件的路径:
const browser = await puppeteer.launch({
executablePath: '/path/to/Chrome'
});
您也可以将 Puppeteer 与 Firefox Nightly 一起使用(实验支持)。更多有关信息,请参见 Puppeteer.launch()
。
请参阅这篇文章了解有关 Chromium 和 Chrome 之间的差异。 这篇文章描述了 Linux 用户的一些区别。
3. 创建新的用户个人资料
Puppeteer 创建自己的浏览器用户个人资料,并在每次运行时对其进行清理。
资源
调试技巧
-
关闭无头模式有时查看浏览器显示的内容很有用。不用以无头模式启动,而是使用
headless: false
启动完整版本的浏览器:const browser = await puppeteer.launch({headless: false});
-
降低它的速度
slowMo
选项将 Puppeteer 操作的速度降低指定的毫秒数。这是帮助了解发生了什么的另一种方法。const browser = await puppeteer.launch({ headless: false, slowMo: 250 // 减速 250ms});
-
捕获控制台输出您可以监听
console
事件。在page.evaluate()
中调试代码时,这也很方便:page.on('console', msg => console.log('PAGE LOG:', msg.text())); await page.evaluate(() => console.log(`url is ${location.href}`));
-
在应用程序代码浏览器中使用调试器
有两个执行上下文:运行测试代码的 node.js 和运行被测试的应用程序代码的浏览器。这使您可以在应用程序代码浏览器中调试代码。即在
evaluate()
中的代码。- 启动 Puppeteer 时使用
{devtools:true}
:
const browser = await puppeteer.launch({devtools: true});
-
更改默认测试超时时间:
jest:
jest.setTimeout(100000);
jasmine:
jasmine.DEFAULT_TIMEOUT_INTERVAL = 100000;
mocha:
this.timeout(100000);
(别忘了更改测试以使用 function 而不是 '=>') -
添加内部带有
debugger
的运行语句 将debugger
添加到现有的运行语句中:await page.evaluate(() => {debugger;});
该测试将在上述运行语句中停止执行,而 chromium 将在调试模式下停止。
- 启动 Puppeteer 时使用
-
在 node.js 中使用调试器
这将使您调试测试代码。例如,您可以跳过 node.js 脚本中的await page.click()
并在应用程序代码浏览器中查看单击的触发。
请注意,由于此Chromium bug,您将无法在 DevTools 控制台中运行await page.click()
。因此,如果您想尝试一下,则必须将其添加到测试文件中。-
在您的测试中添加
debugger;
,例如:debugger;await page.click('a[target=_blank]');
-
将
headless
设置为false
-
运行
node --inspect-brk
,例如node --inspect-brk node_modules/.bin/jest tests
-
在 Chrome 中打开
chrome://inspect#devices
,然后单击inspect
-
在新打开的测试浏览器中,键入
F8
以恢复测试执行 -
现在您的
debugger
将被点击,您可以在测试浏览器中进行调试
-
-
启用详细日志记录内部 DevTools 协议流量将通过
puppeteer
命名空间下的debug
模块进行记录。# 基本的详细日志 env DEBUG="puppeteer:*" node script.js # 协议流量可能比较杂。本示例过滤掉所有网络域消息 env DEBUG="puppeteer:*" env DEBUG_COLORS=true node script.js 2>&1 | grep -v 'Network'
-
使用ndb轻松调试 Puppeteer (node) 代码
npm install -g ndb
(使用 npx更好!)
-
将
debugger
添加到您的 Puppeteer(node) 代码中 -
在测试命令之前添加
ndb
(或npx ndb
)。例如:ndb jest
或ndb mocha
(或npx ndb jest
npx ndb mocha
) -
像大佬一样在 chromium 上调试测试!
给 Puppeteer 添砖加瓦
查看贡献指南了解Puppeteer开发概述。
常见问答
问:谁维护 Puppeteer?
Chrome DevTools 团队维护该库,但是我们很乐意为您提供项目方面的帮助和专业知识!参见贡献。
问:跨浏览器支持的状态如何?
Firefox 的官方支持目前处于试验阶段。与 Mozilla 正在进行的合作旨在支持常见的端到端测试用例,开发人员期望跨浏览器覆盖这些用例。 Puppeteer 团队需要用户的意见,以稳定Firefox支持并提请我们注意缺少的 API 。
从 Puppeteer v2.1.0 开始,您可以指定puppeteer.launch({product:'firefox'})
在 Firefox Nightly 中运行您的 Puppeteer 脚本,而无需任何其他自定义补丁。尽管一个较旧的实验 需要 Firefox 的修补版本,但当前方法可以使用「stock 」Firefox。
我们将继续与其他浏览器供应商合作,为 Safari 等浏览器提供 Puppeteer 支持。这项工作包括探索用于执行跨浏览器命令的标准(而不是依赖于 Chrome 使用的非标准 DevTools 协议)。
问:Puppeteer 的目标和原则是什么?
该项目的目标是:
- 提供一个小巧的规范库,凸显 DevTools 协议 的功能。
- 为类似的测试库提供参考实现。最终,这些其他框架可以采用 puppeter 作为其基础层。
- 增加无头/自动浏览器测试的采用。
- 帮助 dogfood 开发新的 DevTools 协议功能…并发现 bug!
- 进一步了解自动化浏览器测试的难点并帮助填补这些空白。
我们采用 Chromium 原则来帮助我们推动产品决策:
- 速度:Puppeteer 在自动化页面上的性能开销几乎为零。
- 安全性:Puppeteer 在 Chromium 的进程外运行,从而可以安全地自动处理潜在的恶意页面。
- 稳定性:Puppeteer 不应为片状,也不应内存泄漏。
- 简单:Puppeteer 提供了易于使用,理解和调试的高级 API 。
问:Puppeteer 是否正在取代 Selenium WebDriver ?
不。这两个项目都是有价值的,原因各有不同:
- Selenium / WebDriver 专注于跨浏览器自动化;它的价值主张是可在所有主流浏览器上使用的单一标准 API 。
- Puppeteer 专注于 Chromium ;其价值主张是更丰富的功能和更高的可靠性。
也就是说,您可以使用 Puppeteer 对 Chromium 进行测试,例如使用社区驱动的 jest -puppeteer。尽管这可能不应该是您唯一的测试解决方案,但与 WebDriver 相比,它确实有一些好处:
- Puppeteer 不需要设置,并且捆绑了最适合的 Chromium 版本,使其非常容易开始。折腾了一天, 虽然只用 Chromium 完成了几个测试, 总比啥都没做要好( 原文: At the end of the day, it’s better to have a few tests running chromium-only, than no tests at all ) 。
- Puppeteer 具有事件驱动的体系结构,从而消除了很多潜在的弱点。不需要在 puppeteer 脚本中运行万恶的「 sleep(1000) 」调用。
- Puppeteer 默认是无头模式运行的,因此运行起来很快。 Puppeteer v1.5.0 还公开了浏览器上下文,从而可以高效地并行化测试。
- Puppeteer 调试的闪光点在于:将「 headless 」设置为 false,添加「 slowMo」,您将看到浏览器在做什么。您甚至可以打开 Chrome DevTools 来检查测试环境。
问:Puppeteer v.XXX 为什么不能与 Chromium v.YYY 一起使用?
我们将 Puppeteer 视为 Chromium 的不可分割的实体。每个版本的Puppeteer 都捆绑了特定版本的 Chromium -保证可以使用的唯一版本。
这不是人为的限制:很多关于 puppeter 的工作实际上是在 Chromium 存储库中进行的。这是一个典型的事例:
- 一个 Puppeteer bug :github.com/puppeteer/puppeteer/iss...
- 事实证明,这是 DevTools 协议的问题,因此我们正在Chromium中修复它:chromium-review.googlesource.com/c...
1102154
- 上游修复程序完成后,我们会将更新的 Chromium 回滚更新到 Puppeteer 中:github.com/puppeteer/puppeteer/pul...
然而,人们往往希望 Puppeteer 与官方的 Google Chrome 搭配使用,而不是Chromium。为此,您应该安装与 Chrome 版本相对应的puppeteer-core
版本。
例如,为了使用 puppeteer-core 驱动 Chrome 71,请使用chrome-71
npm标签:
npm install puppeteer-core@chrome-71
问:Puppeteer 使用哪个 Chromium 版本?
在 package.json中查找chromium_revision
。要查找相应的 Chromium 提交和版本号,请在OmahaProxy 的「查找发行版」部分中搜索以r
为前缀的修订。
问:Puppeteer 使用哪个 Firefox 版本?
由于 Firefox 支持是试验性的,因此当PUPPETEER_PRODUCT
环境变量设置为firefox
时,Puppeteer 会下载最新的 Firefox Nightly。这就是为什么 package.json中firefox_revision
的值为latest
- - Puppeteer 与特定的 Firefox 版本无关。
要在 Puppeteer 安装过程中获取 Firefox Nightly,请执行以下操作:
PUPPETEER_PRODUCT=firefox npm i puppeteer
# or "yarn add puppeteer"
问:什么是「导航」
从 Puppeteer 的角度来看,「 导航 」是指更改页面网址的任何内容。除了常规导航(浏览器访问网络以从 Web 服务器获取新文档)之外,这还包括锚点导航 和 历史 API 的使用。
有了这个「 导航 」的定义,Puppeteer 可以与单页应用程序无缝协作。
问:「受信任」和 「 不受信任 」输入事件有什么区别?
在浏览器中,输入事件可以分为两大类:可信与不可信。
- 信任的事件:用户与页面互动产生的事件,例如使用鼠标或键盘。
- 不受信任的事件:由Web API生成的事件,例如
document.createEvent
或element.click()
方法。
网站可以区分这两组:
- 使用
Event.isTrusted
事件标志 - 嗅探伴随事件。例如,每个受信任的
click
事件之前都有mousedown
和mouseup
事件。
为了实现自动化,生成可信事件很重要。 使用 Puppeteer 生成的所有输入事件都是可信任的,并且会触发适当的伴随事件。 如果由于某种原因需要一个不可信的事件,则始终可以使用page.evaluate
产生伪造事件:
await page.evaluate(() => { document.querySelector('button[type=submit]').click();
});
问:Puppeteer 不支持哪些功能?
您可能会发现在控制包含音频和视频的页面时,Puppeteer 的行为不符合预期。 (例如,视频播放/屏幕截图可能会失败。)这有两个原因:
- Puppeteer 与 Chromium 捆绑在一起,而不是与 Chrome 捆绑在一起,因此默认情况下,它继承了Chromium 与媒体相关的所有限制。这意味着 Puppeteer 不支持AAC 或 H.264 之类的许可格式。 (但是,可以通过
executablePath
选项通过puppeteer.launch
强制 Puppeteer 使用单独安装的版本的 Chrome 而不是 Chromium。 仅在需要支持这些媒体格式的正式版 Chrome 时才应使用此配置。) - 由于 Puppeteer (在所有配置中)都控制 Chromium / Chrome 的桌面版本,因此不支持仅移动版 Chrome 支持的功能。这意味着 Puppeteer 不支持HTTP实时流(HLS)。
问:我在测试环境中无法安装/运行 Puppeteer。我应该在哪里寻求帮助?
我们为各种操作系统提供了疑难解答 指南,其中列出了所需的依赖项。
问:如何尝试测试 Puppeteer 的预发行版本?
您可以签出此仓库或从 npm 安装最新的预发行版:
npm i --save puppeteer@next
请注意,预发行版可能不稳定并且有 bug 。
本文中的所有译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。
原文地址:https://pptr.dev/