一開始咱們的需求是打開報表的某個頁面而後把圖截出來,而後調用企業微信發送給業務羣
這中間我嘗試了多種技術,好比html2image
,pdf2image
、selenium
這些,這其中截圖
比體驗較好的也就selenium
了,不過咱們有些頁面加載的時間較長,selenium彷佛對html互操做性
也不是很完美(經過Thread.sleep並不能完美的兼容絕大多數報表),另外還有一個比較要命的
是Chromium渲染出來的頁面彷佛也有不一樣程度的問題(就是很差看),固然後面一個偶然的機會在
某不知名網站看到有網友用puppeteer
來實現截圖,遂~,一通騷操做就搭了一套出來(雖然最終方案並非這個
,固然這是後話哈~),這裏就拿出來講說哈~node
因爲整個系統是基於node+express的web服務,puppeteer只是node的一個plugin,因此須要作的準備大體有下linux
wget https://nodejs.org/dist/v14.15.3/node-v14.15.3-linux-x64.tar.xz
tar --strip-components 1 -xvJf node-v* -C /usr/local
npm config set registry https://registry.npm.taobao.org
【注意:安裝pm2前必須安裝npm,若是隻是非正式環境能夠不用安裝pm2】web
npm install pm2 -g
【這個其實很重要,我也繞了彎,本來覺得改改字體編碼就能夠了,後來發現不是】express
// 引入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); });
{ "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
npm
[注意:若是安裝失敗 請檢查是否更改成taobao源]json
node index.js
pm2 start index.js
pm2 list
pm2 delete 應用ID
因爲以上代碼已經對截圖的加載作過處理的,因此無需在使用線程睡眠
同時代碼也對寬度(width)和高度(height)作了處理,因此具體訪問地址以下windows
http://127.0.0.1:3000/screenshot/?login=[是否登陸true or false]&width=[頁面寬度]&height=[頁面高度]&url=[截圖地址]
centos
雖然咱們咱們使用puppeteer
能應對絕大多數報表,後來發現puppeteer
對多組件圖表存在渲染問題,因此就要求
提供商提供導出圖片功能(用戶頁面導出非api),因此最終一套就是 http模擬登陸+調用截圖接口+圖片生成監控+推送圖片
好了,關於截圖就分享到這裏了,各位元旦節快樂哈~《@.@》api