1. 程式人生 > >使用Phantomjs和Node完成網頁的截圖快照

使用Phantomjs和Node完成網頁的截圖快照

由於甲方爸爸的需要,最近使用phantomjs和Node寫了一個對網頁內容截圖的功能,為了避免忘記,現在將程式碼內容及配置流程大概描述一下.

1.首先Node是必須安裝的,而且網上安裝教程一大堆,在此不再贅述,Nodejs官網連結

2.然後,第二個主人公是phantomjs,官網下載地址,選擇對應的系統下載對應的安裝包

3.將phantomjs配置為系統變數,下面是Windows配置為環境變數:

配置完成之後,在cmd命令列中輸入 phantomjs -v 檢驗是否配置成功,配置成功之後,如下圖所示:

4.擼程式碼,通過查閱phantomjs入門程式碼之後,瞭解到使用phantomjs可以預覽一個網頁生成圖片,PDF,base64格式等等,而我們的專案需要的並不是一個完整的網頁,而是網頁中的一部分內容,所以在此基礎之上要改造部門內容,現在講解一下程式碼:

  4.1)首先是express的一些設定,由於需要執行phantomjs的命令,所以需要引入child_process模組,具體程式碼如下:

var process = require('child_process');//執行命令列所需
var express = require('express');//express
var bodyParser = require('body-parser');
var fs = require("fs");//檔案操作
var app = express();

app.use('/pages',express.static('pdfs'));//設定靜態資源目錄
app.use(bodyParser.json({limit:'50mb'}));//請求內容大小限制
app.use(bodyParser.urlencoded({limit:'50mb',extended:false})); 

//設定允許跨域訪問
var allowCrossDomain = function(req, res, next) {
    res.header('Access-Control-Allow-Origin', '*');
    res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE');
    res.header('Access-Control-Allow-Headers', 'Content-Type');
    res.header('Access-Control-Allow-Credentials','true');
    next();
};

app.use(allowCrossDomain);

  4.2)然後就是生成頁面的base64介面的方法,如下:

app.get('/getBase64',function(req,res){
	var url=req.query.url;//讀取請求中的url引數,然後訪問這個url
    url=url.replace(/&/g,'%26');//將請求中的&轉換 
	var resp={
	   "status":'200'
	}
	res.writeHead(200,{'Content-Type':'text/html;charset=utf-8'});//設定響應頭
	if(url==''){
       resp.msg='url引數不能為空';
       res.end(JSON.stringify(resp));    
	}
	else{
        //phantomjs執行的命令列 index.js在後文中給出
		var strShell='phantomjs --disk-cache=true --disk-cache-path=. index.js '+url;
        process.exec(strShell,{
        	maxBuffer:5000*1024,
        },function(error,stdout,strerr){
        	if(error!==null){
                console.log(error);
        		resp.msg='轉換失敗,稍後重試';
        		res.end(JSON.stringify(resp));
        	}else{
                //執行成功則返回base64的資料
        		resp.data=stdout;
        		res.end(JSON.stringify(resp));
        	}
        })
	}

})

  4.3)phantomjs執行的指令碼,即index.js,如下:

var page = require('webpage').create();//獲取webpage
var system = require('system'),
    address;

if (system.args.length === 1) {//執行的命令應該包括請求的URL,否則退出phantom
    console.log('Usage: URL error');
    phantom.exit();
}
address = system.args[1];//請求的地址
address = address.replace(/%26/g, '&');//phantom不能識別%26,所以轉為&
page.viewportSize = {//設定viewport
    width: 1920,
    height: 1080,
}
page.open(address, function(status) {//開啟頁面
    setTimeout(function() {//2s之後獲取base64結果,如果直接生成有可能頁面還沒有載入完成
        if (status == 'success') {
            var base64 = page.renderBase64('PNG');
            console.log(base64);//將base64結果輸出之後,在上邊的getBase64介面中獲取
            phantom.exit();
        }
    }, 2000);
})

  4.4)獲取頁面中部分內容的截圖,可以將需要截圖的DOM字串,傳送至後臺,然後新建一個空的頁面,使用phantom訪問該空白頁面,並將DOM字串新增到預覽的頁面,然後生成截圖,具體程式碼如下:

app.post('/getPartPage', function(req, res) {
    var xmlObj = req.body.xmlObj;//獲取DOM字串
    const reqUrl = 'http:example.com/tmp.html';//要訪問的空頁面
    var response = {
        "status": '200',
    };
    if (xmlObj == undefined || xmlObj == '' || xmlObj == null) {
        response.msg = 'DOM字串內容未輸入';
        res.end(JSON.stringify(response));
    }else {
        fs.writeFile('tmp.txt', xmlObj, function(err) { //由於dom字串內容過多,所以寫入txt文字
            if (err) {
                response.msg = '生成頁面失敗,請稍後重試';
                return res.end(JSON.stringify(response));
            }

            var strShell = 'phantomjs pages/index.js ' + reqUrl;//phantomjs執行的命令
            process.exec(strShell, {
                maxBuffer: 5000 * 1024,
            }, function(error, stdout, strerr) {
                if (error !== null) {
                    response.msg = '指令碼執行錯誤,請稍後重試';
                    res.end(JSON.stringify(response));
                } else {
                    response.data = stdout.replace("\r\n", "");
                    res.end(JSON.stringify(response));//返回結果
                }

            })

        })

    }

})

var server = app.listen(8808,function(){ //介面監聽,訪問的埠
	var host = server.address().address
	var port = server.address().port
    console.log('http://%s:%s',host,port);
})

  4.5)pages下的index.js內容如下所示:

var page = require('webpage').create();//獲取webpage
var fs = require('fs');
var system = require('system'),
    address,filename;

if (system.args.length === 1) {
    console.log('Usage: URL error');
    phantom.exit();
}
address = system.args[1];//請求的路徑
address = address.replace(/%26/g, '&');
filename = (new Data()).getTime();
page.viewportSize = {
    width: 750,
}
page.paperSize = { //生成A4大小的PDF檔案
    format: 'A4',
    orientation: 'portrait',
    margin: '0.8cm'
}
page.open(address, function(status) {
    var info = fs.read('tmp.txt');//讀取DOM字串
    var result = page.evaluate(function(info) {
        try {
            document.querySelector('#dom').innerHTML = info;//將dom字串拼接
        } catch (e) {
            console.log(e);
        }

        return document.querySelector('#dom').innerHTML;//返回頁面
    }, info);
    setTimeout(function() {
        page.paperSize = {
            format: 'A4',
            orientation: 'portrait',
            margin: '0.8cm'
        };
        page.viewportSize = {
            width: 750,
        };
        //生成PDF檔案 
        page.render('pages/' + filename + '.pdf', { format: 'pdf', quality: '100' });
        console.log('http://example.com/pages/' + filename + '.pdf');//返回PDF檔案的訪問路徑
        phantom.exit();
    }, 500);
})