使用node+puppeteer+express搭建截图服务
使用node+puppeteer+express搭建截图服务
写在之前
一开始我们的需求是打开报表的某个页面然后把图截出来,然后调用企业微信发送给业务群
这中间我尝试了多种技术,比如html2image,pdf2image、selenium这些,这其中截图
比体验较好的也就selenium了,不过我们有些页面加载的时间较长,selenium似乎对html互操作性
也不是很完美(通过Thread.sleep并不能完美的兼容绝大多数报表),另外还有一个比较要命的
是Chromium渲染出来的页面似乎也有不同程度的问题(就是不好看),当然后面一个偶然的机会在
某不知名网站看到有网友用puppeteer来实现截图,遂~,一通骚操作就搭了一套出来(虽然最终方案并不是这个
,当然这是后话哈~),这里就拿出来说说哈~
准备
由于整个系统是基于node+express的web服务,puppeteer只是node的一个plugin,所以需要做的准备大致有下
- 一台linux服务器,这里实用centos
- node安装包(用于搭建node环境)
- 字体文件
安装node环境
wget https://nodejs.org/dist/v14.15.3/node-v14.15.3-linux-x64.tar.xztar --strip-components 1 -xvJf node-v* -C /usr/localnpm config set registry https://registry.npm.taobao.org
安装pm2(用于守护node服务)
【注意:安装pm2前必须安装npm,如果只是非正式环境可以不用安装pm2】
npm install pm2 -g- 其它操作请见https://pm2.keymetrics.io
安装字体
【这个其实很重要,我也绕了弯,原本以为改改字体编码就可以了,后来发现不是】
- step1: 将window字体复制到linux下
- windows: C:\Windows\Fonts
- Linux: /usr/share/fonts/
- step2: 建立字体索引信息并更新字体缓存
- cd /usr/share/fonts/
- mkfontscale
- mkfontdir
- fc-cache
准备代码
- index.js
// 引入express module
// 引入puppeteer module
const express = require('express'),
app = express(),
puppeteer = require('puppeteer');
// 函数::页面加载监控
const waitTillHTMLRendered = async (page, timeout = 30000) => {
const checkDurationMsecs = 1000;
const maxChecks = timeout / checkDurationMsecs;
let lastHTMLSize = 0;
let checkCounts = 1;
let countStableSizeIterations = 0;
const minStableSizeIterations = 3;
while(checkCounts++ <= maxChecks){
let html = await page.content();
let currentHTMLSize = html.length;
let bodyHTMLSize = await page.evaluate(() => document.body.innerHTML.length);
console.log('last: ', lastHTMLSize, ' <> curr: ', currentHTMLSize, " body html size: ", bodyHTMLSize);
if(lastHTMLSize != 0 && currentHTMLSize == lastHTMLSize)
countStableSizeIterations++;
else
countStableSizeIterations = 0; //reset the counter
if(countStableSizeIterations >= minStableSizeIterations) {
console.log("Page rendered fully..");
break;
}
lastHTMLSize = currentHTMLSize;
await page.waitFor(checkDurationMsecs);
}
};
//创建一个 `/screenshot` 的route
app.get("/screenshot", async (request, response) => {
try {
const browser = await puppeteer.launch({ args: ['--no-sandbox'] });
const page = await browser.newPage();
await page.setViewport({
width:!request.query.width?1600:Number(request.query.width),
height:!request.query.height?900:Number(request.query.height)
});
// 这里执行登录操作(非公共页面需要登录)
if(request.query.login && request.query.login=="true"){
// wait until page load
await page.goto('认证(登录)地址', { waitUntil: 'networkidle0' });
await page.type('#username', '登录用户名');
await page.type('#password', '登录密码');
// click and wait for navigation
await Promise.all([
page.click('#loginBtn'),
page.waitForNavigation({ waitUntil: 'networkidle0' }),
]);
}
await page.goto(request.query.url,{'timeout': 12000, 'waitUntil':'load'});
await waitTillHTMLRendered(page);
const image = await page.screenshot({fullPage : true,margin: {top: '100px'}});
await browser.close();
response.set('Content-Type', 'image/png');
response.send(image);
} catch (error) {
console.log(error);
}
});
// listener 监听 3000端口
var listener = app.listen(3000, function () {
console.log('Your appliction is listening on port ' + listener.address().port);
});
- package.json
{
"name": "funnyzpc",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC"
}
依赖安装
npm i --save puppeteer express[注意:如果安装失败 请检查是否更改为taobao源]
启动及管理
- 直接使用node启动服务
node index.js
- 使用pm2启动(如果安装了pm2)
- 启动:
pm2 start index.js - 进程:
pm2 list - 删除:
pm2 delete 应用ID
- 启动:
使用
由于以上代码已经对截图的加载做过处理的,所以无需在使用线程睡眠
同时代码也对宽度(width)和高度(height)做了处理,所以具体访问地址如下
http://127.0.0.1:3000/screenshot/?login=[是否登录true or false]&width=[页面宽度]&height=[页面高度]&url=[截图地址]
最后
虽然我们我们使用puppeteer能应对绝大多数报表,后来发现puppeteer对多组件图表存在渲染问题,所以就要求
提供商提供导出图片功能(用户页面导出非api),所以最终一套就是 http模拟登录+调用截图接口+图片生成监控+推送图片
好了,关于截图就分享到这里了,各位元旦节快乐哈~《@.@》
使用node+puppeteer+express搭建截图服务的更多相关文章
- node+express 搭建本地服务
首先,得有node环境,其次建个项目 目录例如 酱紫! 再次 写server.js,当然你可以换个名字a.js .b.js.why.js随你喜欢 var express = require('exp ...
- 最近学习了Node,利用Express搭建了个人博客,总结下吧
node+express+jade+mongodb搭建了一套个人博客,我来总结下这几个家伙的使用感受吧! [node] 成熟插件库众多,真的是只有你想不到,没有它做不到的.而且对于有前端JS基础的童鞋 ...
- Node.js+Express搭建博客系统基本环境安装
1.下载安装node.js 官网下载地址:https://nodejs.org/en/download/ 2.安装express. 打开node命令行工具,在命令行中输入:npm install -g ...
- Node.js express模块 http服务
var express = require('express'); var app = express(); app.get('/', function(req, res){ res.send('he ...
- Kubernetes实战 - 从零开始搭建微服务 1 - 使用kind构建一个单层架构Node/Express网络应用程序
使用kind构建一个单层架构Node/Express网络应用程序 Kubernetes实战-从零开始搭建微服务 1 前言 准备写一个Kubernetes实战系列教程,毕竟cnblogs作为国内最早的技 ...
- Kubernetes实战 - 从零开始搭建微服务 - 1.5 提高可用性-发布多节点的Node/Express网络应用程序
1.5 提高可用性-发布多节点的Node/Express网络应用程序 Kubernetes实战 - 从零开始搭建微服务 前言 在上一篇文章中,已经学习了如何简单地开发一个单层网络应用.[Kuberne ...
- 建立一个node.js服务器(使用express搭建第一个Web环境)
一.官网下载node.js 下载地址:https://nodejs.org/en/download/ 根据向导,下一步安装就可以了! 二.使用express搭建Web环境 express是一个开源的n ...
- 使用 Node.js 搭建微服务网关
目录 Node.js 是什么 安装 node.js Node.js 入门 Node.js 应用场景 npm 镜像 使用 Node.js 搭建微服务网关 什么是微服务架构 使用 Node.js 实现反向 ...
- 使用nodejs和express搭建http web服务
目录 简介 使用nodejs搭建HTTP web服务 请求nodejs服务 第三方lib请求post 获取http请求的正文 Express和使用express搭建http web服务 express ...
随机推荐
- 关于javaSMTP协议发邮件你必须知道的知识点
1.阅读官方吐槽 Note also that THERE IS NOT SUFFICIENT DOCUMENTATION HERE TO USE THESE FEATURES!!! You will ...
- Python中可迭代对象是什么?
Python中可迭代对象(Iterable)并不是指某种具体的数据类型,它是指存储了元素的一个容器对象,且容器中的元素可以通过__iter__( )方法或__getitem__( )方法访问. __i ...
- PyQt(Python+Qt)学习随笔:QListWidget的sortingEnabled属性
老猿Python博文目录 专栏:使用PyQt开发图形界面Python应用 老猿Python博客地址 QListWidget的sortingEnabled属性用于控制列表部件中的项是否可以排序,如果为T ...
- 初识Flask——基于python的web框架
参考教程链接: https://dormousehole.readthedocs.io/en/latest/ (主要)https://www.w3cschool.cn/flask/ 目录: 1.写了一 ...
- ajax的五种状态
ajax的五种状态(readyState ) 0 - (未初始化)还没有调用send()方法 1 - (载入)已调用send()方法,正在发送请求 2 - (载入完成)send()方法执行完成,已经接 ...
- Java并发编程的艺术(六)——中断、安全停止线程
什么是中断 Java的一种机制,用于一个线程去暂停另一个线程的运行.就是一个正在运行的线程被其他线程给打断,停止运行挂起了. 我觉得,在Java中,这种中断机制只是一种方便程序员编写进程间的通信罢了. ...
- Python Windows开发环境搭建
一.下载python安装包 python官网地址:https://www.python.org/,下载windows平台包并安装 二.在Windows设置环境变量 计算机右键,选择属性,在高级系统设置 ...
- Mysql常用函数合集
1. 字符函数 length(获取字节数,UTF-8编码中 一个汉字占3个字节,GBK编码中一个汉字占2个字节) select length('abc'); #结果:3 select length(' ...
- C#跳过工作日,计算几个工作日之后到期的方法
需求:消费者投诉企业,企业在2个工作日之内做出应答. 分析:1.工作日要刨去周末和法定节假日,而且每年的节假日不一样. 2.消费者可以在任意时间发起投诉,如果在非工作日发起了投诉,那么计算时间应该从工 ...
- elementUI的动态tabs页的使用,vue的动态组件的操作
elementUI的动态tabs页的使用,vue的动态组件的操作 有时候我们需要用到动态的tab页,结合不同的页面内容来显示.这里是使用了elementUI的动态tabs页来实现的 <div c ...