Nodejs,不一樣的爬蟲實踐
來自: http://www.famanoder.com/bokes/56b0ff763b9d992825f0a1bb
做前端以來,對我成長幫助最大的恐怕也就是各位大俠們的博客了, ,慢慢的也在我心里種下了顆種子:我也要寫博客!哪怕我文筆差,技術菜,難以望其項背,我也要追隨大神們的腳步,寫寫博客,處處留香。摸爬滾打,終是成長;學習分享,與君共勉!小前端初學Nodejs,搭了個 簡單的博客 ,捉襟見肘,望大俠路過指導!好了,此處有廣告之嫌,進入正題。
關于Nodejs的爬蟲程序,百度一大把,是的,我也是百度到的,然后到github上看了看cheerio模塊;乍一看,這不就是Jquery嘛,沒想到Jquery都能牛到后端操作DOM了啊,恩。。。可以先這么認為和理解吧,因為cheerio確實可以像jquery操作DOM一樣操作從遠程爬取過來的頁面;頓時邪念四起:我要把我喜歡的博客全抓到我的博客站點上去、我要不KX上網而是把谷歌抓過來訪問。。。然后就有了我博客上的 “爬呀爬” 版塊,都是爬取的國內頂尖的前端團隊嘔心瀝血寫的博客, ,保留了作者信息和版權,當然,如果他們看到了,罵我一頓,叫我刪掉,我肯定會屁顛屁顛刪掉的;
還有就是怎么通過我的站點訪問谷歌了,比如:http://www.famanoder.com?url=http://google.com的請求,我res.send(googleBody);恩 ,這樣是可以的,可是問題在于:相對路徑的資源返回404了,因為相對路徑域名取的是我的站點,而我的站點沒有對應的目錄和資源,自然404了;這時cheerio可就很有用了,在res.send之前可以對body進行些DOM操作啊,貌似有點復雜啊,我正則還不行。。。為了讓爬取過來的谷歌可以點擊,鏈接沒有404,還需要做一步,就是通過cheerio將所有相對路徑補上http://www.famanoder.com?url=http://google.com,絕對路徑補上http://www.famanoder.com?url=來將爬取的目標站點所有資源都通過我的博客站點請求;
很高興,一個小小的爬蟲讓我我又知道了三個很好用的模塊:request、superagent、cheerio ;
request和superagent差不多,過年后做個橫向的比較,爭取進一步理解http模塊;
先看看request怎么抓頁面的吧,江湖中人不多廢話了,看代碼:
if (req.query.url) { var iurl = decodeURIComponent(req.query.url); var thaturl = url.parse(iurl).protocol +url.parse(iurl).host; var body=[],size=0; request.get({ url: iurl, headers: {} }) .on('response', function (response) { res.set(response.headers); response.setEncoding='utf8'; response.on('data',function(chunk){ body.push(chunk); size+=chunk.length; }); }) .on('error', function (err) { console.log(err); }) .on('end',function(){
//buffer 防止丟包的情況,如果數據過多,會抓不全的。。。。。 var data = Buffer.concat(body , size); var html = data.toString(); var $=cheerio.load(html); //只是個栗子,具體情況還會要url.parse解析所有href、src再處理 $('a').each(function(){ $(this).attr('href','
//.pipe(res); }</pre>
除了丟包,一般不會有什么問題了,可能就是unicode中文的亂碼了,也有很多模塊可以處理,不過用JS弄也不錯,謝謝某大俠的代碼,找半天了,值得收藏:
function reconvert(str){ str = str.replace(/(\\u)(\w{4})/gi,function($0){ return (String.fromCharCode(parseInt((escape($0).replace(/(%5Cu)(\w{4})/g,"$2")),16))); }); str = str.replace(/(&#x)(\w{4});/gi,function($0){ return String.fromCharCode(parseInt(escape($0).replace(/(%26%23x)(\w{4})(%3B)/g,"$2"),16)); }); return str; }對了,抓取來的body是不能直接操作的,不信試一試,不用cheerio而是直接toString再replace什么的,都是無用功;
好吧,到這我一口氣爬取了上百篇大神們的博客,
,還是有些繁瑣的,巴拉巴拉,我想還是弄個定時任務吧,每天到點就爬一頁,取最新的留下;這里也有兩個模塊供選擇:schedule、later,還是下次做個橫向的比較吧,期待。schedule這個單詞在學校時就沒寫對過,今天終于寫對了,原諒我,又掉底子了。。。看看定時任務吧:
var registTask=function(hour,minute,taskname,fn){ var rule = new schedule.RecurrenceRule(); //每天這個時刻定時執行任務 rule.dayOfWeek = [0, new schedule.Range(1, 6)]; rule.hour = hour; rule.minute = minute; var j = schedule.scheduleJob(rule, function(){ console.log("開始爬取:"+taskname); fn&&fn(); }); } registTask(23,30,'TaoBaoFED',function(){ getTaoBaoFEDBokes(1); //呵呵,每天23:30爬一頁 });差不多這就是“爬呀爬” 這個小玩意,對于一個業余的noder來說,又走了一小步,也挺好玩的;馬上就過年了,又要老一歲了啊,不過也很快就到春天了,祝大家猴年大吉,四季如春!
</div>