最近都在學nodeJs,剛好看到http模組,於是就心血來潮,想寫個簡單的爬蟲。 簡單的爬蟲實現原理很簡單:發送http請求至目標地址擷取HTML頁面資料,然後從擷取來的頁面資料中提取需要的資料儲存。 用nodeJs寫爬蟲,主要就是用到http.get發送請求至目標地址,然後在res.on("data")中監聽資料轉送並且儲存資料,最後在res.on("end")資料傳送完畢後對資料進行處理,儲存。 先來說步驟吧。 我用了express架構,先進入項目目錄,在命令列敲入express -e myCreeper 產生express的目錄。然後進入myCreeper的目錄下再敲入命令npm install。然後項目就搭建好了。 搭建好項目後,就可以開始寫了,爬蟲的主要功能代碼就是下面這兩段: 【前端代碼】 複製代碼<body> <h1>我的部落格</h1> <div class="showMess"></div> <script src="/javascripts/zepto.min.js"></script> <script> $.ajax({ data:{page:1}, dataType:"json", type:"get", url:"/creeper", success:function(data){ console.log(data) var html = ""; for(var i=0;i<data.blogs.length;i++){ var blog = data.blogs[i]; html += "<p><a href='"+blog.src+"' target='_blank'>"+blog.title+"</a><br>" +"<div class='break'>"+blog.content+"</div><div class='moreMess' style='text-align:right'>"+ blog.time+" "+blog.read+" "+blog.say+"</div></p>" } $(".showMess").html(html); }, error:function(){ alert("錯誤") } }) </script> </body>複製代碼 【後台代碼】 複製代碼var http = require("http"), cheerio = require("cheerio"); exports.getBlog = function(req , res){ var page = req.param("page")||1; var _res = res; http.get('http://www.cnblogs.com/axes/default.html?page='+page, function(res){ var chunks = [], size = 0; res.on("data" , function(chunk){ chunks.push(chunk); size += chunk.length; }); res.on("end" , function(){ //拼接buffer var data = Buffer.concat(chunks , size); var html = data.toString(); var $ = cheerio.load(html); var blogs = []; for(var i=0;i<$('.postTitle2').length;i++){ var blog = {}; blog.title = $('.postTitle2').eq(i).html(); blog.src = $('.postTitle2').eq(i).attr("href"); blog.content = $(".c_b_p_desc").eq(i).html(); var mess = $(".postDesc").eq(i).html().split("<a")[0].split(" "); blog.time = mess[2]+" "+mess[3]; blog.read = mess[5]; blog.say = mess[6]; blogs.push(blog); } _res.json({ blogs:blogs }) }) }).on('error' , function(e){ console.log("error:"+e.message) });};複製代碼 我是直接爬自己部落格裡的資料了,所以目標地址就是自己的部落格地址。首先通過前端ajax發送page資料給後台,然後後台接收到page值後,通過http.get發送請求。然後用res.on("data")開始監聽資料轉送,當有資料傳來的時候,就把資料儲存到chunks數組裡面。同時用res.on("end")在資料轉送結束時對資料進行處理。 上面傳輸資料那裡得注意一下。buffer的拼接容易出問題。我剛開始寫的時候,習慣性是寫成 var data = ""; res.on("data" , function(chunk){ data+=chunk }); 這樣寫,如果爬出來的中文資料量比較小,顯示還是正常的,但是當資料量比較大的時候,就會出現亂碼了。因為擷取的chunk是一個buffer,data+=buffer就相當於把所有的資料buffer通過buffer.toString()拼接起來了。如果某一塊buffer是不完整的。當它用toString轉成字串的時候,就會出現截斷現象,也就是某些中文字元沒了。 所以解決辦法就是先用一個數組把所有buffer儲存起來,同時記錄buffer的總長度,在資料轉送完畢的時候,再通過Buffer.concat方法把所有buffer拼接好,再用toString轉成字串。這時擷取的data資料就是正確的了。順便貼出一下Buffer.concat的參數說明: 當把資料轉成字串的時候,我們要取資料,如何取呢?這裡直接用一個很強大的第三方庫:cheerio,這個模組採用了跟jQuery類似的選取器。基本上平時jquery怎麼用,就可以怎麼用cheerio。cheerio的項目地址:https://github.com/MatthewMueller/cheerio 安裝方法就直接:npm install cheerio就行了。引入cheerio後直接通過load函數處理data資料,再接下來就是很簡單的事了。就像前端控制dom一樣輕鬆的控制dom擷取資料吧。把所有資料擷取到後就直接發送至前端頁面。然後顯示出來。