1. 程式人生 > >phantomjs快速入門和使用說明

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做的工具和應用,例如前端爬蟲等,有興趣的不妨去讀讀。

  結束語