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的中文資料貌似也很少。

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

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




 



       

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