近來研究了下phantomjs,只是初涉,還談不上深刻研究,首先介紹下什麼是phantomjs。javascript
官網上的介紹是:」PhantomJS is a headless WebKit scriptable with a JavaScript API. It has fast and native support for various web standards: DOM handling, CSS selector, JSON, Canvas, and SVG.」翻譯過來就是:」PhantomJS 是一個基於 WebKit 的服務器端 JavaScript API。它全面支持web而不需瀏覽器支持,其快速,原生支持各類Web標準: DOM 處理, CSS 選擇器, JSON, Canvas, 和 SVG。 」 PhantomJS 能夠用於頁面自動化,網絡監測,網頁截屏,以及無界面測試等。html
本文結合nodejs利用phantomjs網頁截屏功能實現對多個URL進行批處理截圖操做,並將圖片上傳至七牛服務器,批量得到圖片下載地址後存儲在本地文件。java
下面就開始講講這個demo具體過程是怎麼實現的。node
1、安裝git
一、nodejsgithub
關於nodejs的安裝,在以前的文章中都有講過,這裏就再也不贅述。具體可參見nodejs官網:https://nodejs.org/en/;web
二、phantomjsnpm
關於phantomjs的安裝,這裏主要講windows環境下的安裝方式:windows
首先,進入官網 http://phantomjs.org/download.html 下載phantomjs壓縮包,並解壓至本地磁盤中,好比我本機上解壓後存放的地址是:D:\Program files\phantomjs-2.1.1;數組
其次,配置環境變量。將phantomjs解壓後目錄中的bin目錄的路徑(例如我本機bin目錄的位置是:D:\Program files\phantomjs-2.1.1\bin )加到系統變量Path變量中;
而後,打開cmd,輸入 「phantomjs --version」 命令,查看phantomjs是否安裝成功,若是出現版本號信息則說明安裝成功,若是報錯,那麼你須要重啓一下電腦。
結果以下所示:
2、設計思路
首先說說寫這個demo的初衷。由於在工做中每次發郵件時須要用到一些截圖,不想多個圖片每次都本身手動去截取,因此就想用個自動化的批處理工具來自動截圖,可是這樣也僅僅是完成了截圖,在使用的時候仍是得上傳圖片,我仍是以爲麻煩,因此就想截圖完成後將這些圖片自動上傳到七牛服務器上,而後從服務器上獲取圖片下載地址,以後就能夠直接使用圖片的下載地址就ok了。下面是具體的設計思路。
針對上圖中的截圖器而言,具體的程序流程是:
3、編碼
一、關於模擬生成Echarts圖表的工程代碼及啓動方法,不詳述,可參見我在github上發佈的源碼:https://github.com/zhunaoke/nodejs_phantomjs/tree/master/phantom_pic
二、截圖器
2.一、capture.js
主要利用phantomjs進行截圖操做
1 var page=require('webpage').create();//建立一個網頁對象; 2 var system=require('system'); 3 var address,fileName; 4 // page.viewportSize={width:1024,height:800};//設置窗口的大小爲1024*800; 5 // page.clipRect={top:0,left:0,width:1024,height:800};//截取從{0,0}爲起點的1024*800大小的圖像; 6 // //禁止Javascript,容許圖片載入; 7 // // 並將userAgent改成"Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.31 (KHTML, like Gecko) PhantomJS/19.0"; 8 // page.settings={ 9 // javascriptEnabled: false, 10 // loadImages: true, 11 // userAgent: 'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.31 (KHTML, like Gecko) PhantomJS/19.0' 12 // }; 13 14 if (system.args.length === 1) { 15 console.log('Try to pass some args when invoking this script!'); 16 phantom.exit(1); 17 }else{ 18 //獲取指令傳遞的參數,參數是以數組的形式傳遞的; 19 address=system.args[1]; 20 fileName=system.args[2]; 21 count=system.args[3]; 22 max=system.args[4]; 23 //打開一個網頁; 24 page.open(address,function(status){ 25 console.log(status); 26 if(status==='success'){ 27 //成功後將頁面存儲爲圖片並放在指定的位置; 28 page.render('./pictures/'+fileName+'.png'); 29 } 30 // page.close();//釋放; 31 //退出; 32 phantom.exit(); 33 }); 34 }
2.二、phantom.js
Nodejs開啓新的子進程,發出phantomjs指令進行截圖操做,截圖成功後併發出上傳圖片的指令進行圖片上傳:
1 /** 2 * Created by Administrator on 2016/5/5. 3 */ 4 var urls=["http://localhost:3000/","http://localhost:3000/table","http://www.baidu.com"]; 5 var count=0; 6 var max=urls.length; 7 if(urls.length!=0){ 8 capture(urls[0]); 9 } 10 //生成隨機字符串做爲圖片名稱; 11 function createRandomName(len){ 12 len = len || 32; 13 /****默認去掉了容易混淆的字符oOLl,9gq,Vv,Uu,I1****/ 14 var $chars = 'ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678'; 15 var maxPos = $chars.length; 16 var pwd = ''; 17 for (i = 0; i < len; i++) { 18 pwd += $chars.charAt(Math.floor(Math.random() * maxPos)); 19 } 20 return pwd; 21 } 22 //開始執行截圖命令; 23 function capture(url){ 24 var randomPicName='test'+createRandomName(Math.random()*8); 25 console.log("獲取的隨機名稱="+randomPicName); 26 var spawn=require('child_process').spawn; 27 var process=spawn('phantomjs',['capture.js',url,randomPicName,count,max],{cwd:'./routes/'}); 28 process.stdout.setEncoding('utf8'); 29 30 process.stdout.on("data",function(data){ 31 console.log(data); 32 console.log("spawnSTDOUT:"+JSON.stringify(data)); 33 var code=data.replace(/[\r\n]/g,""); 34 console.log(code); 35 if(code=='success'){ 36 var execFile=require('child_process').execFile; 37 var filePath='./pictures/'+randomPicName+'.png'; 38 var execProcess=execFile('node',['upload.js',filePath,randomPicName,count,JSON.stringify(urls)],{cwd:'./routes/'}, 39 function(err,stdout,stderr){ 40 console.log("execFileSTDOUT:", stdout); 41 console.log("execFileSTDERR:", stderr); 42 }); 43 } 44 }); 45 process.stderr.on('data',function(data){ 46 console.log("stderr"+data); 47 }); 48 process.on('close',function(code){ 49 if (code == 1) { 50 console.log('child process異常結束。目標:' + url); 51 } 52 }); 53 process.on('exit',function(code){ 54 console.log('child process exited with code ' + code); 55 count++; 56 if(count!=urls.length){ 57 capture(urls[count]); 58 } 59 }); 60 }
2.三、upload.js
主要是將圖片上傳至七牛並獲取圖片的下載地址,並將結果存儲在本地txt文件中:
1 /** 2 * Created by Administrator on 2016/5/6. 3 */ 4 var qiniu = require("qiniu"); 5 var config=require('./config'); 6 var argvs=process.argv.splice(2); 7 var fs=require("fs"); 8 console.log(argvs); 9 10 filePath=argvs[0]; 11 key=argvs[1]+'.png'; 12 //count; 13 var count=parseInt(argvs[2]); 14 //urls; 15 var urls=JSON.parse(argvs[3]); 16 var max=urls.length; 17 console.log("get the arguments:"+filePath+"---"+key+"--"+count+"---"+max); 18 /** 19 * 第一步:初始化 20 * @type {string} 21 */ 22 //須要填寫你的 Access Key 和 Secret Key 23 qiniu.conf.ACCESS_KEY = config.qiniu.ACCESS_KEY; 24 qiniu.conf.SECRET_KEY = config.qiniu.SECRET_KEY; 25 //要上傳的空間 26 bucket = config.qiniu.Bucket_Name; 27 28 /** 29 * 第二步:獲取上傳的token 30 * @param bucket 31 * @param key 32 */ 33 //構建上傳策略函數,設置回調的url以及須要回調給業務服務器的數據 34 function uptoken(bucket, key) { 35 var putPolicy = new qiniu.rs.PutPolicy(bucket+":"+key); 36 console.log("token= "+putPolicy.token()); 37 return putPolicy.token(); 38 } 39 //生成上傳 Token 40 token = uptoken(bucket, key); 41 /** 42 * 第三步:上傳圖片 43 * @type {string} 44 */ 45 46 //構造上傳函數 47 function uploadFile(uptoken, key, localFile,count,max) { 48 var extra = new qiniu.io.PutExtra(); 49 qiniu.io.putFile(uptoken, key, localFile, extra, function(err, ret) { 50 if(!err) { 51 console.log("上傳成功-------------------"); 52 // 上傳成功, 處理返回值 53 // console.log(ret.hash, ret.key, ret.persistentId); 54 //構建私有空間的連接 55 url = config.qiniu.Domain+ret.key; 56 var policy = new qiniu.rs.GetPolicy(); 57 //生成下載連接url 58 var downloadUrl = policy.makeRequest(url); 59 //打印下載的url 60 console.log("downloadUrl= "+downloadUrl); 61 var date=new Date(); 62 var dateString=date.toLocaleDateString();//日期; 63 var timeString=date.toLocaleTimeString();//時間; 64 var time=date.toLocaleDateString()+" "+date.toLocaleTimeString(); 65 console.log(time); 66 var signalArray={ 67 "編號":count+1, 68 "被截屏的路徑地址":urls[count], 69 "上傳七牛後的圖片名稱":key, 70 "下載地址":downloadUrl, 71 "截圖時間":time 72 }; 73 if(count==0){ 74 // fs.appendFile(__dirname+'/downloadUrl.txt',"\r\n-----------------"+dateString+" "+timeString+"------------操做開始----------------------\r\n",function(err){ 75 // if(err){console.log('fail')} 76 // }); 77 fs.appendFileSync(__dirname+'/downloadUrl.txt',"\r\n-----------------"+dateString+" "+timeString+"------------操做開始----------------------\r\n",{encoding:'utf8'}); 78 } 79 fs.appendFile(__dirname+'/downloadUrl.txt',JSON.stringify(signalArray)+'\r\n',function(err){ 80 if(err){console.log("fail")} 81 }); 82 // fs.appendFileSync(__dirname+'/downloadUrl.txt',JSON.stringify(signalArray)+'\r\n',{encoding:'utf8'}); 83 84 // if((count+1)==max){ 85 // fs.appendFile(__dirname+'/downloadUrl.txt',"\r\n-----------------"+dateString+" "+timeString+"------------操做結束----------------------\r\n",function(err){ 86 // if(err){console.log('fail')} 87 // }); 88 // fs.appendFileSync(__dirname+'/downloadUrl.txt',"\r\n-----------------"+dateString+" "+timeString+"------------操做結束----------------------\r\n\n",{encoding:'utf8'}); 89 // } 90 } else { 91 // 上傳失敗, 處理返回代碼 92 console.log(err); 93 } 94 }); 95 } 96 //調用uploadFile上傳,並返回下載地址; 97 uploadFile(token, key, filePath,count,max);
2.四、執行:
先 npm install 安裝須要的包,其次,直接輸入「node routes/phantom.js」,回車,程序開始執行,下面來看看執行的結果:
2.4.一、/pictures目錄下:
該目錄下多了圖片文件,這些就是phantomjs截圖而來的圖片;
2.4.二、七牛服務器
網頁登錄七牛後,在我本身的bucket中能夠看到,新增了不少圖片文件,表示咱們上傳成功了:
2.4.三、本地downloadUrl.txt文件
而後咱們測試下下載地址是否能正確下載圖片:
以上就是整個利用nodejs+phantomjs+七牛 實現截圖操做,將截圖上傳七牛並將下載地址存儲在本地磁盤的作法。
PS:可是,有個問題就是,七牛的token設置了有效期,也就說時效過去後,以前的url就不能用了,能夠再從新上傳一次,或者直接在七牛上下載以前的圖片。
若是有須要源碼的小夥伴們能夠在我github上進行下載,下載地址是:
Phantomjs_pic工程(生成echarts圖表等):https://github.com/zhunaoke/nodejs_phantomjs/tree/master/phantom_pic;
phantomjsScreenCapture工程(實現截圖並上傳圖片):https://github.com/zhunaoke/nodejs_phantomjs/tree/master/phantomScreencapture;
ps:這次只是對phantomjs的簡單應用,若有意見和建議,歡迎廣大朋友指出,謝謝!