使用 puppeteer 创建一个自动化导出 PDF 的服务

 最近在基于 RAP2 做内网的一个 API 管理平台,涉及到与外部人员进行协议交换,需要提供 PDF 文档。

在设置完成 CSS 后已经可以使用浏览器的打印功能实现导出 PDF,但全手动,总是觉得不爽,
所以尝试使用了 PUPPETEER 实现 PDF 自动生成。

PUPPETEER 功能介绍

puppeteer 是 chrome 提供的一个无头浏览器,它是替代 phantomjs 的一个替代品,
多用于实现自动化测试。官方仓库地址:https://github.com/GoogleChrome/puppeteer

它和传统的 phantomjs、zombiejs 等主要区别在于:

  • 基于 chromuim,页面渲染完全使用最新浏览器,保证和实际页面完全一致
  • 可进行有头和无头切换,调试更为方便
  • 基本上等同于浏览器控制台的操作,扩展功能强大

它实际上是基于 chromium 实现的一个 Nodejs 引擎,所以想要运行 puppeteer 就必须能够运行 chromium。
对于 centos6 等低版本的系统就无法安装 chromium,就需要考虑使用其他方式。

使用它的主要流程为:启动浏览器 -> 打开tab -> 加载 url -> 加载完成后的操作 -> 关闭页面 -> 关闭浏览器

API 地址是:https://github.com/GoogleChrome/puppeteer/blob/v1.8.0/docs/api.md#

导出服务的实现思路

鉴于公司内部的服务器是 centos6.9,也就意味着无法安装 chromuim,所以想要实现安装就得使用容器技术。

导出服务的要求:

  • 单页面,加载完成后直接导出
  • 多页面,多用于类似页面,加载完成后按照传入顺序导出PDF,并合并成一个 PDF 后返回
  • 以容器技术部署

单页面

实现比较方便,可以在页面加载完成后执行

await page.pdf({path: 'page.pdf'});

各种配置请参考 https://github.com/GoogleChrome/puppeteer/blob/v1.8.0/docs/api.md#pagepdfoptions

多页面

实现思路是类似的,先调用单页面创建并写入 PDF 至临时目录中(不要写入任意目录,在 docker 中未必有权限),
然后合并 PDF 即可。Nodejs 目前没有原生合并 PDF,只能使用现成的库实现。PDFTK 是目前一个首选,nodejs 中也有相关集成的包。
调用方式为:

pdf.merge([file1,file2])

注意: PDFtk 包中创建完成 PDF 会删除临时文件,所以我们单页面创建的也需要最终删除文件,不然到最后你的磁盘会直接爆掉。

部署

使用 docker 创建 image,涉及的依赖有:puppeteer(chromuim),pdftk,nodejs。

代码实现

puppeteer 封装

为了方便使用,对 puppeteer 进行封装

'use strict' const puppeteer = require('puppeteer')  class Browser {   constructor (option) {     this.option = {       args: ['--no-sandbox', '--disable-setuid-sandbox'],       ignoreHTTPSErrors: true,       executablePath: process.env.CHROME_PUPPETEER_PATH || undefined,       dumpio: false,       ...option     }   }   async start () {     if (!this.browser) {       this.browser = await puppeteer.launch(this.option)       this.browser.once('disconnected', () => {         this.browser = undefined       })     }     return this.browser   }   async exit () {     if (!this.browser) {       return     }     await this.browser.close()   }   async open (url, { cookie }) {     await this.start()     const page = await this.browser.newPage()     // 缓存状态下多页面可能不正常     await page.setCacheEnabled(false)     if (cookie) {       const cookies = Array.isArray(cookie) ? cookie : [cookie]       await page.setCookie(...cookies)     }      await page.goto(url, {       waitUntil: 'networkidle0'     })     return page   } }  const browser = 
                        
关键字:
50000+
5万行代码练就真实本领
17年
创办于2008年老牌培训机构
1000+
合作企业
98%
就业率

联系我们

电话咨询

0532-85025005

扫码添加微信