大家好,很高兴又见面了,我是"高级前端进阶",由我带着大家一起关注前端前沿、深入前端底层技术,大家一起进步,也欢迎大家关注、点赞、收藏、转发!
前言
最近在研究将 DOM 内容转化为图片的方法,尝试过 phantomJs、webshot、html2canvas、dom-to-image 等诸多方案,但是遇到的问题一个比一个多。比如常见的:背景图无法渲染到最终生成的图片上、绝对定位的限制、图片尺寸的限制等等。幸运的是最终遇到了 Puppeteer 这个库,本地测试了一下,发现和预期非常契合。因此书写此文,将这个好东西分享给大家。
1.Puppeteer 取代 phantomJs
以前用过 phantomJs,研究几天后发现 phantomJs 虽然在业内有一定的影响力,但后继乏力,主要还是缺乏维护人员,导致项目依赖的 chrome 内核版本太低,无人解决的 BUG 太多,现在已经越来越满足不了真实的前端模拟以及各种新的特性需求(比如高版本 Chrome 的执行环境特性,比如 JS 执行和渲染等都相差很大)。
谷歌浏览器在 17 年开发了 Chrome Headless 特性,并同时推出了 puppeteer,可以理解成日常使用的 Chrome 的无界面版本以及对其进行操控的 js 接口套装。 借助 puppeteer,实际上是通过调用 Chrome DevTools 开放的接口与 Chrome 通信,Chrome DevTools 的接口很复杂,但 puppeteer 对其进行了封装,开发者调用起来还是很方便的。
2.puppeteer vs. puppeteer-core
自 v1.7.0 以后的每个版本,puppeteer 团队都会发布两个软件包,分别为 puppeteer 和 puppeteer-core,两者的使用场景有明显的差异。
puppeteer
puppeteer 是用于浏览器自动化的产品。安装后,它将下载一个版本的 Chromium, 然后使用 puppeteer-core 驱动。
作为最终用户产品,puppeteer 支持大量方便的 PUPPETEER _ * env 变量来调整其默认行为。
puppeteer-core
puppeteer-core 是一个库,可以帮助驱动任何支持 DevTools 协议的产品。 安装了 puppeteer-core 不会自动下载 Chromium。 作为库,puppeteer-core 是通过编程接口完成驱动的,而忽略所有 PUPPETEER_ * env 变量。
puppeteer 和 puppeteer-core 异同
puppeteer-core 和 puppeteer 之间的区别主要包括以下两个:
- puppeteer-core 在安装后不会自动下载 Chromium。
- puppeteer-core 忽略所有 PUPPETEER _ * env 变量。
在大多数情况下,开发者直接使用 puppeteer 包即可。不过,如果想在 DevTools 协议的基础上构建另一个终端用户产品或库,则应该使用 puppeteer-core。比如:
- 使用 puppeteer-core 构建一个 PDF 生成器,然后编写一个自定义的 install.js 脚本,下载 headless_shell 而不是 Chromium 来节省磁盘空间。
- 将 Puppeteer 打包在 Chrome 插件 / 浏览器中使用 DevTools 协议,在这里不需要下载额外的 Chromium 二进制文件。
- 构建一套工具,其中 puppeteer-core 是核心组成,并且希望将 install.js 脚本的执行推迟到即将使用 Chromium 之前。
3.使用 puppeteer-core
使用 puppeteer-core 时,需要首先导入它:
const puppeteer = require('puppeteer-core');
然后,需要使用时显式调用 puppeteer.connect([options])或 puppeteer.launch([options])。下面的示例首先打开 google 官网,然后使用 puppeteer 进行截图操作。
const puppeteer = require('puppeteer');
const browser = await puppeteer.launch();
// 启动Chrome实例
const page = await browser.newPage();
// 创建page实例
await page.goto('https://google.com');
//打开页面地址
await page.screenshot({ path: 'google.png' });
// 页面截图
await browser.close();
//关闭浏览器
以下示例在 developer.chrome.com 中搜索带有文本“automate beyond recorder”的博文,单击第一个结果并打印博文的完整标题。
import puppeteer from 'puppeteer';
(async () => {
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.goto('https://developer.chrome.com/');
// 设置屏幕尺寸
await page.setViewport({width: 1080, height: 1024});
// 在搜索框中输入内容
await page.type('.search-box__input', 'automate beyond recorder');
// 等待并点击第一个结果
const searchResultSelector = '.search-box__link';
await page.waitForSelector(searchResultSelector);
await page.click(searchResultSelector);
// 使用唯一字符串找到完整标题
const textSelector = await page.waitForSelector(
'text/Customize and automate'
);
const fullTitle = await textSelector.evaluate(el => el.textContent);
// 打印完整标题
console.log('The title of this blog post is "%s".', fullTitle);
await browser.close();
})();
3.puppeteer vs. puppeteer-core 数据对比
目前 puppeteer 在 Github 上有 88.2k 的 star,8.8K 的 fork,有超过 370K 的项目使用它。同时对比过去一年 puppeteer vs. puppeteer-core 的下载数据,如下图所示,两者几乎都处于同步上升状态。
根据 NPM 的最新下载数据,puppeteer 的周平均下载量大约 3960K,而 puppeteer-core 的周平均下载量大约为 3271K,两者不分伯仲。因此,开发者可以根据自己的需求来选择到底使用哪一个库。在文章前面部分还提到过 phantomjs,我们将三者放在一起来看,如下图所示:
总体来看,phantomjs 在 puppeteer、puppeteer-core 之间几乎毫无竞争优势。当然,数据只是代表过去一年的时间,考虑到 phantomjs 项目的诸多问题,比如不再维护,衰减也在情理之中,但是可以确信的是 phantomjs 曾经也疯狂过。
4.本文总结
本文主要和大家介绍PhantomJS的替代品Puppeteer,同时和Puppeteer-Core进行了对比,讲述了为什么会有Puppeteer-Core的存在。因为篇幅有限,文章并没有过多展开,如果有兴趣,文末的参考资料提供了优秀文档以供学习。最后,欢迎大家点赞、评论、转发、收藏!
参考资料
https://learnku.com/docs/puppeteer/3.1.0/puppeteer-vs-puppeteer-core/8538
https://codeburst.io/a-guide-to-automating-scraping-the-web-with-javascript-chrome-puppeteer-node-js-b18efb9e9921
https://learnku.com/f2e/t/44845#94a9d3
https://github.com/ariya/phantomjs
https://www.jianshu.com/p/56babda610f9
https://www.educative.io/answers/puppeteer-vs-puppeteer-core
https://semaphoreci.com/blog/2018/03/27/phantomjs-is-dead-use-chrome-headless-in-continuous-integration.html
封面图片:来自作者“Sam Crowther”的文章:https://www.kasada.io/what-is-puppeteer-developers-fraudsters-love-it/
本文暂时没有评论,来添加一个吧(●'◡'●)