PhantomJS快速入門
本文簡要介紹了PhantomJS的相關基礎知識點,主要包括PhantomJS的介紹、下載與安裝、HelloWorld程序、核心模塊介紹等。由于鄙人才疏學淺,難免有疏漏之處,歡迎指正交流。
1、PhantomJS是什么?
PhantomJS是一個基于webkit的JavaScript API。它使用QtWebKit作為它核心瀏覽器的功能,使用webkit來編譯解釋執行JavaScript代碼。任何你可以在基于webkit瀏覽器 做的事情,它都能做到。它不僅是個隱形的瀏覽器,提供了諸如CSS選擇器、支持Web標準、DOM操作、JSON、HTML5、Canvas、SVG等, 同時也提供了處理文件I/O的操作,從而使你可以向操作系統讀寫文件等。PhantomJS的用處可謂非常廣泛,諸如網絡監測、網頁截屏、無需瀏覽器的 Web 測試、頁面訪問自動化等。
PhantomJS官方地址:http://phantomjs.org/。
PhantomJS官方API:http://phantomjs.org/api/。
PhantomJS官方示例:http://phantomjs.org/examples/。
PhantomJS GitHub:https://github.com/ariya/phantomjs/。
2、PhantomJS下載與安裝
官方下載地址:http://phantomjs.org/download.html。目前官方支持三種操作系統,包括windows\Mac OS\Linux這三大主流的環境。你可以根據你的運行環境選擇要下載的包,我的運行環境是Windows7。
下載完成后解壓文件,建議為方便使用,單獨放在一個文件夾里,如我放在D:\workspace\phantomjs里。
到這里,你已經成功下載安裝好PhantomJS了。那么,打開D:\workspace\phantomjs\bin文件夾,雙擊運行phantomjs.exe,出現如下界面,那么你就可以運行JS代碼了。
由于我們都比較懶,不喜歡為了運行一個程序總是跑到D:\workspace\phantomjs\bin文件夾打開 phantomjs.exe。那么,你可以將phantomjs.exe添加到環境變量里。具體如下:打開我的電腦->右鍵屬性->高級系統 設置->高級標簽->環境變量,在系統變量里找到Path,將你的phantomjs添加到環境變量里。比方說我的路徑添加的為 “;D:\workspace\phantomjs\bin”,切記不要少了前面那個分號。
3、第一個PhantomJS小程序HelloWorld
好了,到目前為止,可以開始我們的第一個PhantomJS程序了。打開你的工作目錄,新建文件hello.js,敲入以下代碼,Ctrl+S保存:
// a phantomjs example var page = require('webpage').create(); phantom.outputEncoding="gbk"; page.open("http://www.cnblogs.com/front-Thinking", function(status) { if ( status === "success" ) { console.log(page.title); } else { console.log("Page failed to load."); } phantom.exit(0); });
然后,打開CMD命令行工具,切換到你的當前目錄,敲入phantomjs hello.js,結果如下:
如果你的結果跟我的一樣,那么恭喜你,你已經成功跑起來屬于你的第一個PhantomJS程序了。那么我們簡要介紹下上面的代碼:第2 行,webpage是phantomjs的核心模塊之一,它給用戶提供了訪問、操作、選擇web文檔的接口。第3行,設置下編碼格式,否則輸出的可能是亂 碼。第4行,運行page.open函數,其中第一個參數是你要訪問的url,第二個參數是一個回調函數。在回調函數里我們檢查了下返回的狀態,如果是 success那么我們就將瀏覽的url制定文檔的title打印出來,如你所見,如果不是那么打印文檔加載出錯。最后一行退出phantomjs執行環 境。
4、PhantomJS核心API
webpage:如你所見,上面的例子我們已經見識了它的威力了。它的作用主要是提供了一套可以訪問和操作web文檔的核心方法,包括操作DOM、事件捕獲、用戶事件模擬等等。
system:該模塊提供了一些與操作系統相關的接口,例如訪問操作系統信息、訪問系統環境變量、接受命令行參數等等與程序執行相關的系統信息。
fs:即FileSystem。熟悉NodeJS的朋友都知道,NodeJS也內建了相關的核心模塊。fs提供了執行文件I/O操作的標準接口,如讀寫文件、刪除文件等。它使得你持久化一些文件(如logfile等)變得非常容易。
webserver:如其名字一樣,你可以基于它來實現自己的webserver,用來處理請求并且執行PhantomJS代碼等。
其它一些配置信息,執行PhantomJS的命令格式如下:
1 phantomjs [switches] [options] [script] [argument [argument [...]]]
其中,各種參數都是可選的。例如我們第一個程序的執行命令如下:
1 phantomjs hello.js
打開debug模式(該模式用于開發,可提供必要提示信息):
1 phantomjs --debug=yes hello.js
設置cookie路徑:
1 phantomjs --cookie-file=cookie.txt hello.js
5、操作page content
在helloworld中我們已經學會了如何訪問一個url并取出它的title。下面我們看看如何選擇并操作DOM元素:
DOM選擇器,常用的getElementById、getElementByClassName、getElementByName、getElementByTagName、querySelector(CSS選擇器)。
我們看一個使用querySelector的例子:
1 var content = page.evaluate(function () { 2 var element = document.querySelector('#elem'); 3 return element.textContent; 4 }); 5 console.log(content);
evaluate函數是個新東西,其實很簡單,就是在webpage環境下執行evaluate傳入的回調函數,在這里面執行與phantom相關的操作可以避免web頁面刺探phantom相關的設置信息。上面的代碼就比較簡單了,不啰嗦了。
模仿用戶點擊事件:
phantomJS提供了兩種模仿點擊事件的接口,一個是sendEvent,phantomJS事件觸發器;一個是DOM事件觸發器。
我們先看看第一個,語法如下:
1 sendEvent( eventType, Point X, Point Y, button='left' ) 2 eventType: mouseup mousedown mousemove click doubleclick 3 Point X : 觸發事件的X坐標 4 Point Y: 觸發事件的Y坐標
第二個,我們都應該比較熟悉了:
var evt = document.createEvent("MouseEvents"); evt.initMouseEvent( "click", // 事件類型 true, true, window, 1, 1, 1, 1, 1, // 事件的坐標 false, // Ctrl鍵標識 false, // Alt鍵標識 false, // Shift鍵標識 false, // Meta鍵標識 0, // Mouse左鍵 element); // 目標元素 element.dispatchEvent(evt);
6、事件處理
在真正的瀏覽器里,任何事件發生都可見,而在PhantomJS里都是不可見的。在PhantomJS里,我們可以捕獲這些事件并做出相應處理。由于涉及到的事件有很多種,那么我們今天僅僅把一個比較有用的事件作為例子,基于這個事件你可以監控一個頁面并做出分析:
1 var startTime = null; 2 page.onLoadStarted = function() { 3 startTime = new Date().getTime(); 4 }
監聽也沒開始加載事件,獲取初始加載時間;
var resources = []; page.onResourceRequested = function (request) { resource = { "startTime": request.time, "url": request.url }; resources[request.id] = resource; }; 監聽資源文件請求事件,獲取資源發起請求的時間;
page.onResourceReceived = function (response) { if(response.stage == "start") { resources[response.id].size = response.bodySize; } else if(response.stage == "end") { resources[response.id].endTime = response.time; } }; 監聽資源文件加載完成事件,獲取加載完成時間;
page.onLoadFinished = function () { endTime = new Date(); timeInSeconds = (endTime - startTime) / 1000; console.log("Loading takes " + timeInSeconds + " seconds."); resources.forEach(function (resource) { st = new Date(resource.startTime).getTime(); et = new Date(resource.endTime).getTime(); timeSpent = (et - st) / 1000; console.log(timeSpent + " seconds : " + resource.url); }); phantom.exit(0); }; 監聽文檔加載完成事件,記錄完成時間,并打印出所有資源文件的耗時。
上面的on+事件,做了四件事,監聽資源文件請求和加載完成事件,監聽文檔加載開始完成事件,獲取對應的時間,這樣我們就可以使用這些事件去分析這個頁面的性能問題了。
7、抓取頁面
將要訪問的頁面抓取保存為圖片或者PDF文件的格式,這在PhantomJS里非常簡單。我們下面就分別做一個保存圖片和PDF的例子:
保存為圖片:
// a phantomjs example, saved as img var page = require('webpage').create(); page.open("http://www.cnblogs.com/front-Thinking/", function(status) { if ( status === "success" ) { console.log(page.title); page.render("front-Thinking.png"); } else { console.log("Page failed to load."); } phantom.exit(0); });
注:render獲取一個參數,即保存文件的文件名。結果如下:
保存為pdf:
// a phantomjs example,saved as pdf file var page = require('webpage').create(); page.open("http://www.baidu.com", function(status) { if ( status === "success" ) { console.log(page.title); page.paperSize = { format: 'A4', orientation: 'portrait', border: '1cm' }; page.render("front-Thinking.pdf"); } else { console.log("Page failed to load."); } phantom.exit(0); });
注:其中,pagerSize設置pdf的格式。結果如下:
利用這些提供的特性,你完全可以做一個爬蟲去爬去別人的網站。
8、文件操作相關
文件操作在編碼中非常有用,例如你可以將一些配置信息放在文件中,在程序執行的過程中去讀取;你也可以將你程序執行過程中一些有用的信息保存為文件。因此文件I/O非常有用。我們舉個簡單的例子,讀取文件信息:
var filePath = '/workspace/file1.js';//文件路徑 //判斷文件是否存在,是文件還是文件夾 if( fs.exists(filePath) && fs.isFile(filePath) ) { var ins = fs.open(filePath, 'r');//打開文件 while(!ins.atEnd()) {//循環讀取文件內容 var buffer = ins.readLine();//一行行的讀取 console.log(buffer); } }
這里,讀取文件內容并逐行打印。文件操作有以下幾種方式:
1 r //讀取文件 2 w //寫文件,回覆蓋 3 a //寫文件,追加 4 rb //讀取二進制流 5 rw //寫入二進制流
9、模塊化
模塊化是沒個技術都涉及到的內容,這里不做詳細介紹了。具體可參考阮一峰前輩的博客:http://www.ruanyifeng.com/blog/2012/10/javascript_module.html
10、與jQuery等第三方的結合
有很多第三方非常優秀的庫函數,那么這里我們就舉一個大家都非常喜歡的jQuery庫函數來講講phantomJS與庫函數的結合。代碼如下:
var page = require('webpage').create(); page.open("http://www.cnblogs.com/front-Thinking/", function(status) { if ( status === "success" ) { page.render("before.png"); page.includeJs("http://code.jquery.com/jquery-1.10.1.min.js", function() { page.evaluate(function() { $('#Header1_HeaderTitle').html('My PhantomJS'); }); page.render("after.png"); phantom.exit();(); }); } });
以上代碼,訪問我的博客地址,并抓取截屏,加載jquery后修改我博客的標題,結果如下:
before.png
after.png
11、其它
PhantomJS可以做的事情太多了以至于我可能都介紹了只有它N分之一,N趨于無窮大。說了僅僅是入門的帖子,所以就不再深入介紹下去了, 當然我也只是個小白,暫時知道了解的也比較淺顯。其實,PhantomJS可以結合Jasmine來一起做測試,可以省去很大的人力和時間成本。同時,開 源社區有很多基于PhantomJS做的工具和應用,例如前端爬蟲等,有興趣的不妨去讀讀。