phantomjs快速入門和使用說明
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 測試、頁面訪問自動化等。
官方下載地址: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的例子:
var content = page.evaluate(function () {
var element = document.querySelector('#elem');
return element.textContent;
});
console.log(content);
evaluate函式是個新東西,其實很簡單,就是在webpage環境下執行evaluate傳入的回撥函式,在這裡面執行與phantom相關的操作可以避免web頁面刺探phantom相關的設定資訊。上面的程式碼就比較簡單了,不囉嗦了。
模仿使用者點選事件:
phantomJS提供了兩種模仿點選事件的介面,一個是sendEvent,phantomJS事件觸發器;一個是DOM事件觸發器。
我們先看看第一個,語法如下:
sendEvent( eventType, Point X, Point Y, button='left' )
eventType: mouseup mousedown mousemove click doubleclick
Point X : 觸發事件的X座標
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裡,我們可以捕獲這些事件並做出相應處理。由於涉及到的事件有很多種,那麼我們今天僅僅把一個比較有用的事件作為例子,基於這個事件你可以監控一個頁面並做出分析:
var startTime = null;
page.onLoadStarted = function() {
startTime = new Date().getTime();
}
監聽頁面開始載入事件,獲取初始載入時間;
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");
//預設路徑為當前js所在路徑,也可以指定路徑,如下所示
//page.render("D:/mavenProject/wnadmin/test/front-Thinking.jpg");
} 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);
}
}
這裡,讀取檔案內容並逐行列印。檔案操作有以下幾種方式:
r //讀取檔案
w //寫檔案,回覆蓋
a //寫檔案,追加
rb //讀取二進位制流
rw //寫入二進位制流
9、模組化
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後修改我部落格的標題,結果如下:
11、其它
PhantomJS可以做的事情太多了以至於我可能都介紹了只有它N分之一,N趨於無窮大。說了僅僅是入門的帖子,所以就不再深入介紹下去了,當然我也只是個小白,暫時知道了解的也比較淺顯。其實,PhantomJS可以結合Jasmine來一起做測試,可以省去很大的人力和時間成本。同時,開源社群有很多基於PhantomJS做的工具和應用,例如前端爬蟲等,有興趣的不妨去讀讀。
結束語