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 的方法,例如evaluateOnNewDocumentexposeFunction

默认运行时设置

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 创建自己的浏览器用户个人资料,并在每次运行时对其进行清理

资源

调试技巧

  1. 关闭无头模式有时查看浏览器显示的内容很有用。不用以无头模式启动,而是使用 headless: false 启动完整版本的浏览器:

    const browser = await puppeteer.launch({headless: false});
  2. 降低它的速度slowMo选项将 Puppeteer 操作的速度降低指定的毫秒数。这是帮助了解发生了什么的另一种方法。

    const browser = await puppeteer.launch({  headless: false,  slowMo: 250 // 减速 250ms});
  3. 捕获控制台输出您可以监听console事件。在page.evaluate()中调试代码时,这也很方便:

    page.on('console', msg => console.log('PAGE LOG:', msg.text()));  
    await page.evaluate(() => console.log(`url is ${location.href}`));
  4. 在应用程序代码浏览器中使用调试器

    有两个执行上下文:运行测试代码的 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 将在调试模式下停止。

  5. 在 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将被点击,您可以在测试浏览器中进行调试

  6. 启用详细日志记录内部 DevTools 协议流量将通过puppeteer命名空间下的debug模块进行记录。

     # 基本的详细日志
     env DEBUG="puppeteer:*" node script.js
    
     # 协议流量可能比较杂。本示例过滤掉所有网络域消息
     env DEBUG="puppeteer:*" 
     env DEBUG_COLORS=true 
     node script.js 2>&1 | grep -v 'Network'
  7. 使用ndb轻松调试 Puppeteer (node) 代码

    • npm install -g ndb (使用 npx更好!)
  • debugger添加到您的 Puppeteer(node) 代码中

  • 在测试命令之前添加ndb(或npx ndb)。例如:
    ndb jestndb 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 与官方的 Google Chrome 搭配使用,而不是Chromium。为此,您应该安装与 Chrome 版本相对应的puppeteer-core版本。

例如,为了使用 puppeteer-core 驱动 Chrome 71,请使用chrome-71npm标签:

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.jsonfirefox_revision 的值为latest- - Puppeteer 与特定的 Firefox 版本无关。

要在 Puppeteer 安装过程中获取 Firefox Nightly,请执行以下操作:

PUPPETEER_PRODUCT=firefox npm i puppeteer
# or "yarn add puppeteer"

问:什么是「导航」

从 Puppeteer 的角度来看,「 导航 」是指更改页面网址的任何内容。除了常规导航(浏览器访问网络以从 Web 服务器获取新文档)之外,这还包括锚点导航历史 API 的使用。

有了这个「 导航 」的定义,Puppeteer 可以与单页应用程序无缝协作。

问:「受信任」和 「 不受信任 」输入事件有什么区别?

在浏览器中,输入事件可以分为两大类:可信与不可信。

  • 信任的事件:用户与页面互动产生的事件,例如使用鼠标或键盘。
  • 不受信任的事件:由Web API生成的事件,例如document.createEventelement.click()方法。

网站可以区分这两组:

  • 使用 Event.isTrusted 事件标志
  • 嗅探伴随事件。例如,每个受信任的click事件之前都有mousedownmouseup 事件。

为了实现自动化,生成可信事件很重要。 使用 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/

译文地址:https://learnku.com/f2e/t/44844

本文为协同翻译文章,如您发现瑕疵请点击「改进」按钮提交优化建议
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!