最近做网页转换成长图和pdf的功能,一开始准备canvas做转长图的功能,在当前网页操作是可行的,但是需求是需要可以截其他网站,想法是用iframe展示网站再进行截图,但是这是行不通的,一个跨域的问题就要搞死人,更何况就算截出来效果也是不是很好的,pdf功能还实现不了,最终是决定用puppeteer
Puppeteer 是 Chrome 开发团队在 2017 年发布的一个 Node.js 包,用来模拟 Chrome 浏览器的运行
Puppeteer 是 Node.js 工具引擎
Puppeteer 提供了一系列 API,通过 Chrome DevTools Protocol 协议控制 Chromium/Chrome 浏览器的行为
Puppeteer 默认情况下是以 headless 启动 Chrome 的,也可以通过参数控制启动有界面的 Chrome
Puppeteer 默认绑定最新的 Chromium 版本,也可以自己设置不同版本的绑定
Puppeteer 让我们不需要了解太多的底层 CDP 协议实现与浏览器的通信
代码:
index.js
const puppeteer = require('puppeteer'); // 引入puppeteer模块
const fs = require('fs'); // 引入fs模块
const path = require('path'); //引入path模块
const express = require('express');
const app = express();
// const request = require("request"); //引入request模块
const workDir = path.resolve('.'); // 获取当前绝对路径
// 函数::页面加载监控
const waitTillHTMLRendered = async (page, timeout = 30000) => {
console.log('页面加载中...')
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("页面完成加载...");
break;
}
lastHTMLSize = currentHTMLSize;
await page.waitFor(checkDurationMsecs);
}
};
// 添加路由
app.get("/screenshot", async (request, response) => {
console.log("开始转换")
try{
const ids = request.query.url; // 循环截图的id
const type = request.query.type; // 循环截图的类型
const name = request.query.name; // 循环截图的名字
// 创建浏览器
const browser = await puppeteer.launch({
headless: true, // 是否无头浏览器(true则是无头浏览器,整个截图过程看不到,false就可以看得到自动化的过程,建议可以先设置为false试试看)
args: ['--no-sandbox', '--disable-setuid-sandbox'] ,
});
const page = await browser.newPage(); // 创建一个page
// await page.setViewport({width: 1920, height: 1200}); // 设置page显示的大小
await page.setViewport({
width:!request.query.width?1800:Number(request.query.width),
height:!request.query.height?1600:Number(request.query.height)
});
// 打开指定网页
await page.goto(ids,{
waitUtil: 'networkidle2'
});
// 暂停1秒,等待加载完成
// await page.waitFor(5000);
await waitTillHTMLRendered(page);
// const inputElement = await page.$('a[aria-expanded=false]');
// 截图生成图片的路径new Date().getTime()
let image_path
if(type=="img"){
image_path= await './images/'+name+'.png';
// 页面截图screenshot pdf
await page.screenshot({
path: image_path, // 保存路径及名字
fullPage: true // 是否截取全屏幕
});
}else{
image_path = await './images/'+name+'.pdf';
await page.pdf({
printBackground: true, //是否显示背景色
path: image_path
});
}
// 准备读取截图上传到服务器
// let filePath = await path.join(workDir, image_path); // 获取文件绝对路径
// const formData = await { // 创建输入流
// my_file: fs.createReadStream(filePath),
// };
console.log("转换完成")
// response.send({status:1})
await page.close()
// 关闭浏览器
await browser.close();
}catch (error){
console.log(error);
// response.send({status:0})
}
});
// listener 监听 60999端口
var listener = app.listen(60999, function () {
console.log('正在监听端口: ' + listener.address().port);
});
package.json
{
"name": "ceshijietu",
"version": "1.0.0",
"description": "",
"main": "index.js",
"dependencies": {
"_fs-constants@1.0.0@fs-constants": "^1.0.0",
"_fs.realpath@1.0.0@fs.realpath": "^1.0.0",
"_progress@2.0.3@progress": "^2.0.3",
"_puppeteer@8.0.0@puppeteer": "^8.0.0"
},
"devDependencies": {},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC"
}
如果npm install 失败可以手动安装puppeteer 这里推荐使用cnpm,npm可能会安装失败
npm i --save puppeteer express
准备images文件夹
启动服务,我自己的是example,本文章是index.js
访问:type:转换类型,name:文件名称,url:网页地址
http://localhost:60999/screenshot?type=img&&name=daweige&&url=https://blog.csdn.net/qq_35168861?orderby=ViewCount
转换完成
部署到服务器上可能会出现的问题:
报错
…node_modules/puppeteer/.local-chromium/linux-496140/chrome-linux/chrome: error while loading shared libraries: libpangocairo-1.0.so.0: cannot open shared object file: No such file or directory
这是因为缺少依赖,chromium其实失败
执行:
#依赖库
yum install pango.x86_64 libXcomposite.x86_64 libXcursor.x86_64 libXdamage.x86_64 libXext.x86_64 libXi.x86_64 libXtst.x86_64 cups-libs.x86_64 libXScrnSaver.x86_64 libXrandr.x86_64 GConf2.x86_64 alsa-lib.x86_64 atk.x86_64 gtk3.x86_64 -y
转换乱码,服务器上没有字体包
执行:
#字体
yum install ipa-gothic-fonts xorg-x11-fonts-100dpi xorg-x11-fonts-75dpi xorg-x11-utils xorg-x11-fonts-cyrillic xorg-x11-fonts-Type1 xorg-x11-fonts-misc -y
这样基本就可以使用了!