本文适用于对docker,node有一定了解的童鞋
Puppeteer简介
今年5月在github上创建的项目,属于比较新的chromium无头浏览器类库。
Puppeteer在项目中的实际使用
基础安装
选用Puppeteer的主要原因有两点,
- 1:GOOGLE官方维护,活跃度很高,个人觉得前途光明。
- 2:我们的产品在chrome上适配最好。目前最新版本是
0.13.0
,我们采用0.12.0
版本,因0.13.0
版本API做了一些变化无法满足我们的需求。我们截图时有如下两个必须解决的场景- 网站需要等待当前仪表盘所有查询都完成才可以进行截图操作
- 我们并不知道所有仪表盘发起的查询会查询多久结束
npm安装puppeteer时会从google一个网站上下载chromium,因为墙的原因会下载失败。我们采用的方式先设置环境变量
set PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=1
复制代码
阻止install的时候自动下载,然后手工下载chromium后通过docker build打包成一个基础镜像。我们在Dockerfile中From此镜像,然后再做后续操作。
npm instal [email protected] --save
复制代码
现在可通过docker很快速的进行打包。最终打包后的image里/usr/src/node/包含node代码及chromium目录
基本操作
调用puppeteer
我们手动指定chromium目录来运行。
const browser = await puppteer.launch({
args: ['--no-sandbox', '--disable-setuid-sandbox'], // docker中运行需要加上这两个args
executablePath: 'chromium/chrome', // 基础镜像已将chromium复制到/usr/src/node/chromium目录下
});
复制代码
保存图片
通过URL打开网站
await page.goto(fullUrl, {
waitUntil: 'networkidle',
networkIdleTimeout: 15000,
timeout: 240000
});
复制代码
networkIdleTimeout: 15000
参数代表当前页面网络处于idle状态至少15秒
时导航完毕,避免导出的截图数据不全。
如果直接保存整个页面为图片或PDF是很简单的,有现成的API直接调用。但这次我们只将某一区域保存为图片,
let rect = await page.evaluate(() => {
const element = document.querySelector(
'.class1'
); // 选择包含指定class属性的dom节点
const { x, y, width, height } = element.getBoundingClientRect();
return {
left: x,
top: y,
width,
height,
};
});
await page.screenshot({
path: imagePath,
clip: {
x: rect.x,
y: rect.y,
width: actualWidth,
height: actualHeight
}
});
复制代码
可以在page.evaluate中操作页面元素,所以可以获取指定区域的长宽等信息。这样我们只需截取那一区域即可。完整的API地址还是请参阅github官方API文档
保存PDF
如上节所说,如果保存整个页面为PDF很简单,因为我们只保存某一区域,然而保存pdf的API中没有类似page.screenshot中clip参数,我的处理方式就是将上一步保存的图片转为PDF即可。转换方式很多,我采用pdfkit
类库实现。代码就不赘述,可以参考很多DEMO。
总结
因为我们通过docker+CICD+devops打包部署node服务,puppeteer在docker中也有一些坑,好在官方给出了一系列解决方案。我在实际使用中还是偶尔发生页面加载失败的情况,期望在未来版本会变得更加强大和稳定。