一、背景需求
1、因为数据包含机密信息,所以得自己搭建图表导出服务器;在后台生成对应 Highcharts 图表、以图片的形式导出保存。
2、图表个性化程度较高,如一些图列是 Highchart 没有的,但在前端可以利用 css 实现。
3、每周定时执行上述生成图表的任务,保存到指定位置。
4、需求已经上线一个月,生产上运行良好,时间有限,只能在这简单记录下,理一下思路也方便以后查阅。
二、实现思路
1、经过一番了解,发现 Puppeteer,PhantomJs 等可以实现上述 Highchart 图表以图片形式导出的功能,它们也常常用于:
- 爬虫
- 生成网页截图 /PDF
- 测试等
2、这个需求选用了 Puppeteer 去完成,原因如下:
- 官方的文档也较为详细,相关 API,另外其他项目用它实现 PDF 生成的实践,迁移到本项目爬的坑也会少点。
- 截出来的图片质量清晰,也满足业务的要求。
3、定时任务的需求则用了 Cron 实现;在设定的时间点,在后台用 Puppeteer 打开我们网页,实现特定区域截图。
三、Puppeteer 使用
1、安装,安装 puppeteer 同时,也会下载 Chromium,安装地址为外国网站,下载失败的话多尝试几次、切换到 cnpm 或者手动下载。如果是部署再 Linux 上的话,还得安装依赖包才能启动 Chromium,具体操作可以查看下面。
# 安装
npm i puppeteer --save
2、任意区域截图
第一张图为图表的 HTML 页面,第二张图是指定区域的截图,代码如下:
const express = require('express');
const puppeteer = require('puppeteer');
const app = express();
app.use(express.static('public'));
async function screenshot() {
try {
// 添加启动参数 '--no-sandbox', '--disable-setuid-sandbox'
// 解决 Linux 环境下 "no use sandbox" 报错
const browser = await puppeteer.launch({args: ['--no-sandbox', '--disable-setuid-sandbox'],
headless: true
});
const page = await browser.newPage();
await page.goto('http://localhost:3008/');
let clip = await page.evaluate(() => {
// 获取指定容器的坐标信息
let {x, y, width, height} = document.getElementById('container').getBoundingClientRect();
return {x, y, width, height};
});
await page.screenshot({
path:'chart.png',
clip:clip // 设置 clip 属性
});
await page.close();
await browser.close();} catch (error) {throw error;}
}
// 访问 http://localhost:3008/screenshot 进行截图
app.get('/screenshot', (req, res) => {screenshot()
.then(data => res.json('clip successed'))
.catch(err => res.json('clip failed'));
});
app.listen(3008);
四、定时任务
const CronJob = require('cron').CronJob;
// 每天 9 点钟执行定时任务,其他时间可查找 corn 表达是或者使用 corn 表达式生成工具
new CronJob({
cronTime: '0 0 9 * * *',
onTick: function () {screenshot();
},
start: true
});
五、Linux 上部署问题
至此,我们实现了导出 Highcharts 图表的功能,但是这只是在 windows 系统的开发机上把这个流程跑通,部署到 linux 机器上是仍需解决以下几点问题
- Chromium 依赖包安装:官网列出了 Debian 和 Centos 依赖包列表,点击查看,按照上述列表按住即可
-
中文乱码问题:linux 默认没有中文字体,所以我们页面上的中文全是乱码,以 Debian 系统为例安装字体
# 安装文泉驿字体 apt-get update apt-get install -y wqy*
- 其他字体安装:由于项目对图表文字显示要求苛刻,要求中文以楷体显示,英文以 new times roman 显示,所以还得从 windows 上把字体拷贝过去,详细 Debian 安装 windows 字体戳这