1. 程式人生 > >PhantomJs+MutationObserver實現動態頁面資料抓取

PhantomJs+MutationObserver實現動態頁面資料抓取

       IT行業,支撐業務的變化需要優秀的大量的資料,我們需要適應資料的動態變化,拿到這些動態變化的資料,分析,然後提供給自己的專案,支撐公司的業務。最近,就碰到這種,需要獲取網頁上不斷變化的資料,只有在資料發生變化的時候,才取這個變化的值,並將其存放到庫中。

       其實PhantomJs,乍看這個名字,還以為是什麼Js,其實吧,它就是一個沒有頁面的瀏覽器,它跟其他瀏覽器的最大的區別就在於它沒有介面,核心是用WebKit,這是PhantomJs的官網http://phantomjs.org/ 。PhantomJs的中文資料很少,介紹的也很簡單,基本上都是官網的示例,說是在的,這些對我一點都沒有幫助,不過,人要學會變通,也就只能將這些簡單的進行拼裝組合,支撐自己複雜的業務。PhantomJs僅僅只是一個瀏覽器而已,並不能在資料變化的時候主動告訴我,這是變化的資料。所以,這還需要MutationObserver的支援。

       MutationObserver,乍看名字,也許你就能想到他的實現原理是什麼,在我看來,就是個觀察者模式,當然,JS具體的實現細節,我不知道,我也沒查過。其實計算機很多東西都是相通的,從名字看,也許就能看到他的作用或者能大體猜測到他的實現原理上。

安裝

       PhantomJs的使用,需要先安裝,詳細可以參見官網,官網介紹的很詳細,就不累述了。我在使用的時候用到了PhantomJs的以下方法。

使用方法簡介

       當然是我使用過的方法的一個簡介,其他的,還請移步官網。

       page.onConsoleMessage      監聽所有的console.log訊息

    page.onConsoleMessage = function(msg){
	console.log(msg);				 	
    };

      page.onLoadFinished       介面載入完成之後,進行頁面動態資料抓取

    page.onLoadFinished = function(status){
 	  console.log('---------start-----------');  
		page.evaluate(getContent,"test");
    };


      page.open    介面開啟,我用到了它的兩個引數

   page.open(url, function (status) {   
       //Page is loaded!     
       if (status !== 'success') {     
          console.log('can not start');      
       } else {
       }	        
   }); 

     page.evaluate()         支援js操作

   page.evaluate(getContent,postUrl);
     getContent為js的方法名,postUrl為該方法需要傳遞的引數

      剩下的就是MutationObserver對動態資料變化的監聽了。

    function getContent(url) {
	  console.log("---------start fetch------------"+url+"---");
		var tar = $('#MarketGrid');
		var MutationObserver = window.MutationObserver|| window.WebKitMutationObserver|| window.MozMutationObserver;
		var observer = new MutationObserver(function(mutations) { 
				mutations.forEach(function(mutation) {
			     var text=$(mutation.target).parents(".ipe-Market").find(".ipe-Market_ButtonText").text();
			     console.log(text);
				})
		});
 	observer.observe(tar[0], { 
  	    attributes: true,
 	    childList: true,
  	    characterData: true,
  	    characterDataOldValue: true,
  	    attributeOldValue:true,
  	    subtree: true});
    }	 

完整的Js為:   

system = require('system')     
address = system.args[1];//獲得命令列第二個引數 接下來會用到    
var page = require('webpage').create();     
var url = address; 

page.onConsoleMessage = function(msg){
	console.log(msg);				 	
}; 

 page.onLoadFinished = function(status){
 	  console.log('---------start-----------');  
		var postUrl=getUrl();
		page.evaluate(getContent,"test");
 };

page.open(url, function (status) {   
    //Page is loaded!     
    if (status !== 'success') {     
       console.log('can not start');      
    } else {
    }	        
}); 
function getContent(txt) {
	  console.log("---------start fetch------------"+txt+"---");
		var tar = $('#MarketGrid');
		var MutationObserver = window.MutationObserver|| window.WebKitMutationObserver|| window.MozMutationObserver;
		var observer = new MutationObserver(function(mutations) { 
				mutations.forEach(function(mutation) {
			     var text=$(mutation.target).parents(".ipe-Market").find(".ipe-Market_ButtonText").text();
			     console.log(text);
				})
		});
 	observer.observe(tar[0], { 
  	    attributes: true,
 	    childList: true,
  	    characterData: true,
  	    characterDataOldValue: true,
  	    attributeOldValue:true,
  	    subtree: true}
  	    );
 }	 

執行

       我安裝的是Windows版本的PhantomJs,執行的時候,需要進入到對應的bin目錄下,然後使用命令格式為:phantomjs  xxx.js  http地址  。

問題及解決方案

       說說我在這中間遇到的一些問題吧。

        第一個問題:實時監測動態資料變化

        剛開始,我並不理解PhantomJs是個什麼東西,其實我就是不信這就是一個瀏覽器,它跟其他瀏覽器的區別就是沒有介面,其他瀏覽器功能,PhantomJs基本上都有,所以在當MutationObserver在其他瀏覽器產生作用的時候,當和PhantomJs結合的時候,卻不能產生相應的效果的時候,我一度懷疑,這個利用這兩個東西動態抓取資料的功能不能實現,原因是在 page.evaluate()中執行MutationObserver的時候,這個裡面的頁面是死頁面,資料根本就不會變化。

        老大否定了我,也是後來老大通過他的手段發現,當執行到page.evaluate()時候,這個時候頁面還不存在,還沒有那些可能會發生變化的html元素。老大就是老大啊,不得不佩服。

       第二個問題:PhantomJs記憶體飆升,CPU佔用高

       這個問題的原因,在於PhantomJs在執行過程中,因為page.evaluate()中的js方法的問題,導致PhantomJs佔用記憶體越來越大,最終在達到1.5G左右,自動關閉退出。解決辦法我就不用說了吧,除錯js就好了,找到導致原因的那段js就可以了。

      第三個問題:看到資料動態變化了,但是並沒有獲取到動態變化的數值

      這個問題的原因其實跟第一個問題有點類似,為什麼類似呢?因為我遇到的這兩個問題,都跟具體的http請求頁面有關,這個問題的出現,是因為裡面的html元素的原因,在檢測到變化後,並沒有拿到值,這個問題隱藏的很深,如果不細緻觀察很難發現。

       第四個問題:因為PhantomJs啟動後,是一個程序,那檢測到的資料變化值如何傳入到專案中

       解決辦法類似的有兩個,第一:Ajax請求到專案服務;第二:長期掛起執行緒,並保持一個活躍狀態,或者使用main函式。

       第五個問題:管理問題

       當前,這還涉及到另外的一些問題,如果利用不使用其他額外的工具封裝類的話,將面臨啟動一個數據抓取服務,將啟動一個PhantomJs的程序,啟動10個的話,將啟動10個PhantomJs程序,什麼時候啟動,什麼時候刪除PhantomJs的程序,這些都是問題。一個程序大約佔用記憶體50m,如果是10個,就是500m,但是,你能手動去啟動,手動去刪除嗎?顯然這是不合理的,至於如何解決,以後告知。

總結

       利用PhantomJs和MutationObserver實現動態網頁資料抓取工作,光是調通這個PhantomJs和MutationObserver,用了差不多一週的時間,不斷的改造,當然這不是最終版本,其實最終版本比這稍微複雜。PhantomJs的作用還有很多,在資料抓取這個行業中,我想,PhantomJs以後會大有前途的。其實,PhantomJs也有對應的封裝工具—PhantomJsDriver,只是我查了下這個封裝工具類的API,並沒有適合我們這種特殊需求的,所以也就沒有深入研究,PhantomJsDriver的中文資料貌似也很少。

       今天老大還跟我說,為什麼叫“飯桶”呢?我默默的笑了,也許它在執行上的確很飯桶吧,哈哈。。。。。

       在正式步入工作這個環境,進入網際網路這個行業,特別是在最近的一年,我深刻體會到,如果不留心思考,不嘗試閱讀英文資料,對英文深深抵觸,那我就別想在這個行業繼續混下去了。處處留心,學著怎麼去做一個人,我常常對自己說的話就是,不管在工作還是在生活中,靜下心來,身為一個女生,更要理智多於感性,看看自己能夠成為一個什麼樣的人。