PhantomJS pdf抓取

from:https://www.cnblogs.com/front-Thinking/p/4321720.html

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保存:

複製代碼

 
  1. 1 // a phantomjs example
  2. 2 var page = require('webpage').create();
  3. 3 phantom.outputEncoding="gbk";
  4. 4 page.open("http://www.cnblogs.com/front-Thinking", function(status) {
  5. 5 if ( status === "success" ) {
  6. 6 console.log(page.title);
  7. 7 } else {
  8. 8 console.log("Page failed to load.");
  9. 9 }
  10. 10 phantom.exit(0);
  11. 11 });
 

複製代碼

  然後,打開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. 1 var content = page.evaluate(function () {
  2. 2 var element = document.querySelector('#elem');
  3. 3 return element.textContent;
  4. 4 });
  5. 5 console.log(content);
 

  evaluate函數是個新東西,其實很簡單,就是在webpage環境下執行evaluate傳入的回調函數,在這裏面執行與phantom相關的操作可以避免web頁面刺探phantom相關的設置信息。上面的代碼就比較簡單了,不囉嗦了。

  模仿用戶點擊事件:

  phantomJS提供了兩種模仿點擊事件的接口,一個是sendEvent,phantomJS事件觸發器;一個是DOM事件觸發器。

  我們先看看第一個,語法如下:

 
  1. 1 sendEvent( eventType, Point X, Point Y, button='left' )
  2. 2 eventType: mouseup mousedown mousemove click doubleclick
  3. 3 Point X : 觸發事件的X座標
  4. 4 Point Y: 觸發事件的Y座標
 

  第二個,我們都應該比較熟悉了:

複製代碼

 
  1. 1 var evt = document.createEvent("MouseEvents");
  2. 2 evt.initMouseEvent(
  3. 3 "click", // 事件類型
  4. 4 true,
  5. 5 true,
  6. 6 window,
  7. 7 1,
  8. 8 1, 1, 1, 1, // 事件的座標
  9. 9 false, // Ctrl鍵標識
  10. 10 false, // Alt鍵標識
  11. 11 false, // Shift鍵標識
  12. 12 false, // Meta鍵標識
  13. 13 0, // Mouse左鍵
  14. 14 element); // 目標元素
  15. 15 element.dispatchEvent(evt);
 

複製代碼

  6、事件處理


  在真正的瀏覽器裏,任何事件發生都可見,而在PhantomJS裏都是不可見的。在PhantomJS裏,我們可以捕獲這些事件並做出相應處理。由於涉及到的事件有很多種,那麼我們今天僅僅把一個比較有用的事件作爲例子,基於這個事件你可以監控一個頁面並做出分析:

 
  1. 1 var startTime = null;
  2. 2 page.onLoadStarted = function() {
  3. 3 startTime = new Date().getTime();
  4. 4 }
 

  監聽也沒開始加載事件,獲取初始加載時間;

複製代碼

 
  1. 1 var resources = [];
  2. 2 page.onResourceRequested = function (request) {
  3. 3 resource = {
  4. 4 "startTime": request.time,
  5. 5 "url": request.url
  6. 6 };
  7. 7 resources[request.id] = resource;
  8. 8 };
  9.  
  10. 監聽資源文件請求事件,獲取資源發起請求的時間;
 

複製代碼

複製代碼

 
  1. 1 page.onResourceReceived = function (response) {
  2. 2 if(response.stage == "start") {
  3. 3 resources[response.id].size = response.bodySize;
  4. 4 } else if(response.stage == "end") {
  5. 5 resources[response.id].endTime = response.time;
  6. 6 }
  7. 7 };
  8.  
  9. 監聽資源文件加載完成事件,獲取加載完成時間;
 

複製代碼

複製代碼

 
  1. 1 page.onLoadFinished = function () {
  2. 2 endTime = new Date();
  3. 3 timeInSeconds = (endTime - startTime) / 1000;
  4. 4 console.log("Loading takes " + timeInSeconds + " seconds.");
  5. 5 resources.forEach(function (resource) {
  6. 6 st = new Date(resource.startTime).getTime();
  7. 7 et = new Date(resource.endTime).getTime();
  8. 8 timeSpent = (et - st) / 1000;
  9. 9 console.log(timeSpent + " seconds : " + resource.url);
  10. 10 });
  11. 11 phantom.exit(0);
  12. 12 };
  13. 監聽文檔加載完成事件,記錄完成時間,並打印出所有資源文件的耗時。
 

複製代碼

  上面的on+事件,做了四件事,監聽資源文件請求和加載完成事件,監聽文檔加載開始完成事件,獲取對應的時間,這樣我們就可以使用這些事件去分析這個頁面的性能問題了。

  7、抓取頁面


  將要訪問的頁面抓取保存爲圖片或者PDF文件的格式,這在PhantomJS裏非常簡單。我們下面就分別做一個保存圖片和PDF的例子:

  保存爲圖片:

複製代碼

 
  1. 1 // a phantomjs example, saved as img
  2. 2 var page = require('webpage').create();
  3. 3 page.open("http://www.cnblogs.com/front-Thinking/", function(status) {
  4. 4 if ( status === "success" ) {
  5. 5 console.log(page.title);
  6. 6 page.render("front-Thinking.png");
  7. 7 } else {
  8. 8 console.log("Page failed to load.");
  9. 9 }
  10. 10 phantom.exit(0);
  11. 11 });
 

複製代碼

  注:render獲取一個參數,即保存文件的文件名。結果如下:

  保存爲pdf:

複製代碼

 
  1. 1 // a phantomjs example,saved as pdf file
  2. 2 var page = require('webpage').create();
  3. 3 page.open("http://www.baidu.com", function(status) {
  4. 4 if ( status === "success" ) {
  5. 5 console.log(page.title);
  6. 6 page.paperSize = { format: 'A4',
  7. 7 orientation: 'portrait',
  8. 8 border: '1cm' };
  9. 9 page.render("front-Thinking.pdf");
  10. 10 } else {
  11. 11 console.log("Page failed to load.");
  12. 12 }
  13. 13 phantom.exit(0);
  14. 14 });
 

複製代碼

  注:其中,pagerSize設置pdf的格式。結果如下:

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

  8、文件操作相關


  文件操作在編碼中非常有用,例如你可以將一些配置信息放在文件中,在程序執行的過程中去讀取;你也可以將你程序執行過程中一些有用的信息保存爲文件。因此文件I/O非常有用。我們舉個簡單的例子,讀取文件信息:

複製代碼

 
  1. 1 var filePath = '/workspace/file1.js';//文件路徑
  2. 2
  3. 3 //判斷文件是否存在,是文件還是文件夾
  4. 4 if( fs.exists(filePath) && fs.isFile(filePath) ) {
  5. 5 var ins = fs.open(filePath, 'r');//打開文件
  6. 6 while(!ins.atEnd()) {//循環讀取文件內容
  7. 7 var buffer = ins.readLine();//一行行的讀取
  8. 8 console.log(buffer);
  9. 9 }
  10. 10 }
 

複製代碼

  這裏,讀取文件內容並逐行打印。文件操作有以下幾種方式:

 
  1. 1 r //讀取文件
  2. 2 w //寫文件,回覆蓋
  3. 3 a //寫文件,追加
  4. 4 rb //讀取二進制流
  5. 5 rw //寫入二進制流
 

  9、模塊化


  模塊化是沒個技術都涉及到的內容,這裏不做詳細介紹了。具體可參考阮一峯前輩的博客:http://www.ruanyifeng.com/blog/2012/10/javascript_module.html

  10、與jQuery等第三方的結合


  有很多第三方非常優秀的庫函數,那麼這裏我們就舉一個大家都非常喜歡的jQuery庫函數來講講phantomJS與庫函數的結合。代碼如下:

複製代碼

 
  1. 1 var page = require('webpage').create();
  2. 2 page.open("http://www.cnblogs.com/front-Thinking/", function(status) {
  3. 3 if ( status === "success" ) {
  4. 4 page.render("before.png");
  5. 5 page.includeJs("http://code.jquery.com/jquery-1.10.1.min.js",
  6. 6 function() {
  7. 7 page.evaluate(function() {
  8. 8 $('#Header1_HeaderTitle').html('My PhantomJS');
  9. 9 });
  10. 10 page.render("after.png");
  11. 11 phantom.exit();();
  12. 12 });
  13. 13 }
  14. 14 });
 

複製代碼

  以上代碼,訪問我的博客地址,並抓取截屏,加載jquery後修改我博客的標題,結果如下:

  

before.png

    

  after.png

  11、其它


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

  結束語


  再次對你有如此大的耐性讀這麼一篇爛文到現在表示感謝(花了兩個多小時寫它,我也是夠有耐性的了,哇咔咔)!在閱讀或者敲代碼過程中發現任何問題或者有任何疑問,歡迎留言指導交流!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章