PhantomJS快速入門

jopen 9年前發布 | 32K 次閱讀 PhantomJS JavaScript開發

本文簡要介紹了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代碼了。

 PhantomJS快速入門

由于我們都比較懶,不喜歡為了運行一個程序總是跑到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快速入門

如果你的結果跟我的一樣,那么恭喜你,你已經成功跑起來屬于你的第一個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的格式。結果如下:

 PhantomJS快速入門

利用這些提供的特性,你完全可以做一個爬蟲去爬去別人的網站。

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后修改我博客的標題,結果如下:

 PhantomJS快速入門

before.png

 PhantomJS快速入門


after.png

11、其它


PhantomJS可以做的事情太多了以至于我可能都介紹了只有它N分之一,N趨于無窮大。說了僅僅是入門的帖子,所以就不再深入介紹下去了, 當然我也只是個小白,暫時知道了解的也比較淺顯。其實,PhantomJS可以結合Jasmine來一起做測試,可以省去很大的人力和時間成本。同時,開 源社區有很多基于PhantomJS做的工具和應用,例如前端爬蟲等,有興趣的不妨去讀讀。


注:轉載需注明出處及作者名。

流柯     

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!