Node.js Spider

2017-04-22_14-55-04.png

1.基礎知識

爬蟲
爬蟲,是一種自動獲取網頁內容的程序,是搜索引擎的重要組成部分,因此搜索引擎優化很大程度上就是針對爬蟲而做出的優化。

Robots協議
robots.txt是一個文本文件,也是一個協議,不是一個命令。
robots.txt是爬蟲要查看的第一個文件。
robots.txt告訴爬蟲在服務器上什么文件是可以被查看的,搜索機器人就會按照文件中的內容來確定訪問的范圍。

配置環境

express spider && cd spider && npm install 創建項目spider并安裝依賴
cd bin && node www 啟動服務器
npm install request --save-dev 安裝request模塊并放入項目
npm install cheerio --save-dev 安裝cheerio模塊并放入項目

模塊相關
superagent :發起http請求
cheerio :解析http返回的html內容
async :多線程并發控制

2.原理分析

步驟1:app.js

var express = require('express');
var app = express();

app.get('', function(req,res){
    res.send('hi,world!');
});
app.listen(3000);

測試
supervisor start app.js

3.實戰案例

3.1 爬取圖片并保存到本地

var http = require('http');
var fs = require('fs');
var request = require('request');
var cheerio = require('cheerio');

var url = 'http://tu.duowan.com/tag/5037.html';

function saveImg($){
    var arr = [];
    $('.box').each(function(index,item){
        //獲取圖片的標題
        var obj = {
            'name':$(this).find('em a').text(),
            'img':$(this).find('img').attr('src')
        };
        arr.push(obj);
        //采用request模塊,向服務器發起一次請求,獲取圖片資源
        request.head(obj.img, function(err, res, body){
            if(err){
                console.log(err);
            }
        });
        //通過流的方式,把圖片寫到本地目錄下
        request(obj.img).pipe(
            fs.createWriteStream('./imgs/'+obj.name+'.jpg')
        );

        // 在本地存儲所爬取的內容資源
        var file = './imgs/note.log';
        var content = obj.name+'\n';
        fs.appendFile(file, content, 'utf-8', function(err){
            if(err){
                console.log(err);
            }
        });
    });
    console.log(arr);
}
function startRequest(url){
    //采用http模塊向服務器發起一次get請求
    http.get(url,function(res){
        var html = '';
        //防止中文亂碼
        res.setEncoding('utf-8');
        res.on('data', function(chunk){
            //監聽data事件,每次取一塊數據
            html += chunk;
        }).on('end', function(){
            //監聽end事件,如果整個網頁內容的html都獲取完畢,就執行回調函數
            //采用cheerio模塊解析html
            var $ = cheerio.load(html);
            //在本地存儲所爬取到的圖片資源
            saveImg($);
        }).on('error', function(err){
            console.log(err);
        });
    });
}
function getPage(url){
    startRequest(url);
}
getPage(url);

3.2 爬取博客

環境配置

npm install async -save-dev
npm install url-save-dev
npm install superagent -save-dev
npm install eventproxy -save-dev

代碼解析


var cheerio = require('cheerio');
var async = require('async');
var url = require('url');
var superagent = require('superagent');

var express = require('express');
var app = express();

var eventproxy = require('eventproxy');
var ep = eventproxy();


var pageurl = [];
var pagenum = 3;
for(var i=0; i<pagenum; i++){
    pageurl.push('http://www.ruanwen2008.com/page_'+i+'.html');
}


app.get('/', function(req,res,next){
    var posturl = [];
    //ep重復監聽emit事件
    //eventproxy就是使用事件(并行)方法來解決這個問題。當所有的抓取完成后,eventproxy接收到事件消息自動幫你調用處理函數。
    ep.after('getPost', pageurl.length, function(eps){
        var count = 0;
        //抓取內容
        var fetch = function(url,callback){
            count++;
            superagent.get(url).end(function(error,result){
                count--;

                var $ = cheerio.load(result.text);
                var title = $('title').text();
                var obj = {title:title};
                callback(null,obj);
            });
        };
        //控制最大并發數為5
        async.mapLimit(posturl, 5, function(url,callback){
            fetch(url, callback);
        }, function(error,result){
            res.send(result);
        });
    });
    pageurl.forEach(function(url){
        superagent.get(url).end(function(error,response){
            if(error){
                return next(error);
            }
            //cheerio充當服務器端的jQuery功能
            //先使用它的.load()來載入HTML
            //再通過CSS selector來篩選元素。
            var $ = cheerio.load(response.text);
            //其結果為一個個對象,調用 .each(function(index, element))函數來遍歷每一個對象,返回的是HTML DOM Elements。
            $('.lieb>ul>li>h2>a').each(function(){
                var href = $(this).attr('href');
                posturl.push(href);
            });
            //使用eventproxy來并發抓取
            ep.emit('getPost', 'get article');
        });
    });
});
//監聽服務器端口
app.listen(3001, function(req,res){
    console.log('app is running');
});

4.爬蟲小結

4.1http.get+cheerio+iconv-lite

直接使用http的get方法進行請求url,將得到的內容給cheerio解析,用jquery的方式解析。得到的結果中文亂碼如何解決呢,用iconv-lite模塊將得到的內容進行轉碼即可。

http.get(options,function(result){
  var body = [];
  result.on('data',function(chunk){
     body.push(chunk);
  });
  result.on('end', function () {
     var html = iconv.decode(Buffer.concat(body), 'gb2312');  //注意這里body是數組
     var $ = cheerio.load(html);
     ...
  });
});

4.2request+cheerio+iconv-lite

直接獲取到Buffer類型的數據。然后將得到的內容給cheerio解析,用jquery的方式解析出我們要東西即可。

request(options,function(err,res,body){
  if(err)console.log(err);
  if(!err&&res.statusCode==200){
     var html = iconv.decode(body, 'gb2312');     //這里body是直接拿到的是Buffer類型的數據,可以直接解碼。
     var $ = cheerio.load(html);
     ...
  }
});

4.3 superagent+cheerio+superagent-charset

用了superagent的get方法發起請求,解碼的時候用到了superagent-charse,用法還是很簡單的,之后再將獲取到的內容給cheerio解析,用jquery的方式解析出我們要東西即可。結果中文亂碼解決用superagent-charset模塊進行轉碼。

var charset = require("superagent-charset");
var superagent = charset(require("superagent"));   //將superagent模塊傳遞給superagent-charset
superagent.get(url)
  .charset('gb2312')                                //用charset方法達到解碼效果。
  .end(function(err,result){
     if(err) console.log(err);
     var $ = cheerio.load(result.text);
     ...
  });
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,321評論 6 543
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,559評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,442評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,835評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,581評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,922評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,931評論 3 447
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,096評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,639評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,374評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,591評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,104評論 5 364
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,789評論 3 349
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,196評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,524評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,322評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,554評論 2 379