天天看點

熱點技術:使用CasperJS建構Web爬蟲

從你的應用中收集資料有時候可能有點困難和艱辛。可能是缺少一個必須的api,或者是有太多的資料需要處理。這時候你就需要借助于web抓取。

不用說了,這可能是個法律雷區,是以要確定你沒有逾越法律的邊界。

目前有很多工具可以幫助你抓取内容,例如import.io,但是有時這些工具并不能完全滿足你的需要。又或者,像我一樣,充滿好奇心,希望深入地了解web抓取。

挑戰

讓我們從一個簡單地挑戰——網絡爬蟲開始,讓這個爬蟲爬取techmeme,并獲得一個當天熱門新聞清單!

注意: 在這裡我将會使用dzone,但在擷取頁面時會出現問題。後面會詳細說明這個問題。

機器設定

您隻需要做很少的工作來完成安裝。我假設您已經安裝了node.js(我的意思是誰沒有安裝呢!)。盡管我們并不直接使用phantomjs,但是您依然需要安裝它。版本2.0.1目前已經可以使用了——您可以從其官網下載下傳或使用homebrew或其他等效的包管理器安裝。

如果您使用具有homebrew的mac,您可以這樣安裝phantomjs

brew install phantomjs

casperjs允許我們編寫javascript腳本。您可以通過在終端中輸入casperjs以測試其是否正确安裝并加入到path中。

熱點技術:使用CasperJS建構Web爬蟲

編寫腳本

下面我們将編寫一個新的javascript腳本檔案。在我的例子中,我稱其為index.js。您需要做的第一件事就是在您的代碼中建立一個casper執行個體。您還需要加入依賴的子產品并向其傳遞一些基本參數。

var casper = require("casper").create({ 

waittimeout: 10000, 

steptimeout: 10000, 

verbose: true, 

pagesettings: { 

websecurityenabled: false 

}, 

    onwaittimeout: function() { 

          this.echo('** wait-timeout **'); 

    }, 

    onsteptimeout: function() { 

        this.echo('** step-timeout **'); 

    } 

}); 

當您等待一個元素可見時,上面的onwaittimeout回調将會被調用。例如,點選一個按鈕之後,waittimeout将被超出。

現在,您可以啟動casper執行個體并将其指向我們希望爬取的頁面。

casper.start(); 

casper.open("http://techmeme.com"); 

casper使用一個可靠地架構來幫助您一步一步地運作所有任務。對于第一步,您将希望使用then函數。

casper.then(function() { 

  //logic here 

//start your script 

casper.run(); 

為了使casper打開網頁并按您的想法運作,您需要調用run函數。

檢查網頁以擷取想要的元素

當抓取到一個網頁,您可以假設它具有特定的結構。在您編寫腳本之前,可能已經浏覽過了網頁的源代碼,或者已經使用開發者工具觀察了頁面對特定行為的變化。

是以,讓我們開始于一個簡單地邏輯,使用casperjs維護系統確定一個特定的元素在繼續之前處于合适的位置。如果元素不存在,腳本将會停止,但

是至少您将會知道其為何停止。這個維護行為對于觀察您之前抓取頁面的變化是無價的,但是可能會與您之前見到的頁面具有不一樣的結構。

如果您檢查了techmeme首頁的元素,您将會注意到頭條新聞部分在一個id為,topcol1的div中。

熱點技術:使用CasperJS建構Web爬蟲

讓我們使用維護功能確定這個元素存在:

this.test.assertexists("#topcol1"); 

如果這個元素不存在,測試(例如我們的腳本)将會停止,否則它将繼續運作。

您還可以使用waitforselector函數來獲得更為細緻的結果:

this.waitforselector("#topcol1", 

    function pass () { 

       console.log("continue"); 

    function fail () { 

        this.die("did not load element... something is wrong"); 

); 

使用這個函數的優點就是它允許頁面加載元素并一直等待到執行。您在初始配置中指定的waittimeout将會被用于确定失敗前等待多久。

注意:有時,使用casperjs查找元素可能會出問題。使用capture()函數截取一個casperjs看到的頁面的截圖。 this.capture(‘screener.png’);

從頁面中提取内容

下面,讓我們看看怎樣從頁面中找出标題。首先,找到包含您需要的内容的元素,在我們的例子中,為class=ii的div。

casperjs自帶一個evaluate函數,可以讓您在頁面中運作javascript,并且您還可以讓函數傳回一個值以供進一步處理。

這個javascript寫起來并沒有什麼不同,您可能注意到,在本例中,我使用的是原始的純dom方法,而不是jquery,同樣,如果您願意,您也可以在evaluate函數中使用jquery;

var links = this.evaluate(function(){ 

var results = [];  

var elts = document.getelementsbyclassname("ii"); 

for(var i = 0; i < elts.length; i++){ 

var link = elts[i].getelementsbytagname("a")[0].getattribute("href"); 

var headline = elts[i].firstchild.textcontent; 

results.push({link: link, headline: headline}); 

return results;  

如果您在evaluate函數中使用console.log語句,它們将會通過remote.message句柄列印到您的控制台,這将會在下一節中詳細介紹。

一旦運作結束,結果将會傳回給您。您可以将它們寫入檔案系統,或者将它們列印到螢幕上:

console.log("there were "  + links.length + " stories"); 

for(var i = 0; i < links.length; i++){ 

console.log(links[i].headline); 

輸出的結果如:

熱點技術:使用CasperJS建構Web爬蟲

抓取中的錯誤處理

有時,您運作的javascript中可能存在錯誤,或者其對您抓取的頁面的處理存在問題。這些情況中,您可以捕獲錯誤并使用remote.message和page.error事件将其列印到控制台:

casper.on('remote.message', function(msg) { 

this.echo('remote message caught: ' + msg); 

casper.on('page.error', function(msg, trace) { 

this.echo('error: ' + msg, 'error'); 

您同樣還能觀察到即将請求的資源,這些資源的加載使用的是resource.error和resource.received事件: 

casper.on('resource.error', function(msg) { 

this.echo('resource error: ' + msg); 

casper.on('resource.received', function(resource) { 

    console.log(resource.url); 

了解更多

本文隻寫了點關于使用casperjs你所能做到的皮毛的東西。該項目的文檔是完美的,是以要確定檢視過 api ,看看你還可以用它來做些什麼。

在本系列的下一篇文章中,我回來看看如何從網頁上下載下傳圖檔,而且我也會讨論下如何使用建構到casperjs中的檔案系統函數,其使用會受到比node.js更多的限制。

來源:51cto

繼續閱讀