puppeteer的使用,网页转长图和pdf

最近做网页转换成长图和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

puppeteer的使用,网页转长图和pdf
准备images文件夹

启动服务,我自己的是example,本文章是index.js
puppeteer的使用,网页转长图和pdf
访问:type:转换类型,name:文件名称,url:网页地址

http://localhost:60999/screenshot?type=img&&name=daweige&&url=https://blog.csdn.net/qq_35168861?orderby=ViewCount

puppeteer的使用,网页转长图和pdf
转换完成
puppeteer的使用,网页转长图和pdf
部署到服务器上可能会出现的问题:

报错
…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

这样基本就可以使用了!

上一篇:首页>Python>如何创建一个属性,其名称在一个字符串?


下一篇:SEO大杀器rendertron安装