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的中文資料貌似也很少。
今天老大還跟我說,為什麼叫“飯桶”呢?我默默的笑了,也許它在執行上的確很飯桶吧,哈哈。。。。。
在正式步入工作這個環境,進入網際網路這個行業,特別是在最近的一年,我深刻體會到,如果不留心思考,不嘗試閱讀英文資料,對英文深深抵觸,那我就別想在這個行業繼續混下去了。處處留心,學著怎麼去做一個人,我常常對自己說的話就是,不管在工作還是在生活中,靜下心來,身為一個女生,更要理智多於感性,看看自己能夠成為一個什麼樣的人。