NodeJS網絡爬蟲

原文地址:NodeJS網絡爬蟲
網上有不少其餘語言平臺版本的網絡爬蟲,好比Python,Java。那怎麼能少得了咱們無所不能的javascript呢😂?這個和以前給產品狗開發的批量圖片下載配置工具,原理很類似,核心就是調用Node的http模塊。javascript

網絡爬蟲基本就由以下部分組成:html

  1. 程序入口
  2. 請求模塊
  3. 數據解釋

程序入口能夠用web頁面實現,還能夠在網頁上顯示抓取的數據和分析結果;可是這個我只想把精力花在覈心模塊,頁面和樣式不想花太多精力去弄。因此呢,我就開發個node的命令行工具,這個比較成熟的就是commander了。java

請求模塊方面,我只想抓取百度的頁面,還有知乎的頁面,它們的請求都是https協議的,好在Node的https和http模塊功能幾乎是同樣的,這裏須要作的就是熟悉它的api就行了,也是easy。node

數據解釋模塊,由於抓取出來的頁面內容是字符串,因此能夠用正則表達式去匹配,可是這樣太麻煩了。有沒有更好的方式?抓取回來可都是html內容,用jQuery以操做dom的方式去解析數據不是很方便嘛,剛好有個服務端的jquery庫cheerio。jquery

頁面抓取完,數據也分析出來了,那就很是簡單了,你能夠選擇存入數據庫或者寫入文件保存。接下來就開始實現上面的功能模塊。git

程序入口

開始配置和初始化commander,具體的使用方式參考官方的文檔:https://www.npmjs.com/package/commander,這裏再也不詳細解釋用法了,下面開始配置commander。
首先要在package.json添加以下節點,表示註冊了一個命令行 "grab"。github

"bin": {
    "grab": "bin/grab.js"
  },

接着在grab.js開始定義commander,最後咱們就能夠這樣執行命令行:"grab baidu <內容> ",固然能夠用bd簡寫代替baidu,知乎的定義和百度是同樣,這裏再也不重複介紹了。 web

program
        // .allowUnknownOption()//不報錯誤
        .version('0.0.1')
        .usage('這是個人網絡爬蟲程序😎'
          +'\n  grap [option]'
          +'\n    bd baidu: baidu search'
          +'\n    zh zhihu: zhihu search');

    program
        .command('baidu <cmd>')
        .alias('bd')
        .description('baidu search baidu')
        .option("-t, --tieba", "baidu tieba")
        .action(function(cmd, options){
          console.log('baidu search "%s":', cmd);
          request.baiduSearch(cmd);
        }).on('--help', function() {
          console.log('  Examples:');
          console.log();
          console.log('    grab bd    <cmd>');
          console.log('    grab baidu <cmd>');
          console.log();
        });

    program.parse(process.argv);

請求模塊

https模塊發起請求主要有兩種方式,這裏稍微封裝了下:正則表達式

  1. get方式,主要針對的是簡單的請求,只須要傳遞url發起get請求。知乎的調用這個就能夠了。
function get(url,callback) {
        return https.get(url,function(response) {
            var body = '';

            response.on('data', function(data) {
                body += data;
            });

            response.on('end', function() {
                callback(body);
            });
        });
    }
  1. requerst方式,不但能夠發起get請求,也能夠發起post請求,還能夠修改端口,請求header。這個主要是針對限制比較多的百度爬蟲。百度必須設置header,同時百度請求參數也比較複雜,須要專門配置,具體可參考網上的資料。
function request(options,callback){
        // var postData = qs.stringify({});
        var body,
        req = https.request(options, (res) => {
            console.log('STATUS: ' + res.statusCode);
            // console.log('HEADERS: ' + JSON.stringify(res.headers));
            res.setEncoding('utf8');
            res.on('data', function (chunk) {
                body+=chunk;
            });
            res.on('end',function(){
                callback(body)
            });
        });

        req.on('error', function(e) {
            console.log('problem with request: ' + e.message);
        });

        // write data to request body
        // req.write(postData);
        req.end();
    }

    function baiduRequset(pageNo,pageSize,keyword){
        var path='/s?'+qs.stringify({
            ie:'utf-8',
            f:8,
            rsv_bp:1,
            tn:'baidu',
            rn:pageSize,
            pn:pageNo*pageSize,
            wd:keyword
        }),
        options = {
            hostname: 'www.baidu.com',
            port: 443,
            path: path,
            method: 'GET',
            headers: {
                'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36'
            }
        };

        request(options,function(body){
            saveFile(pageNo,keyword,body);
            showBaiduResult(pageNo,body);
        });
    }

數據解釋

抓取數據以後,咱們須要作的就是調用cheerio,以jquery獲取dom內容的方式獲取結果,並顯示出來,固然也能夠保存文件或數據庫。數據庫

/**
   * 顯示結果
   * @param  {[type]} pageNo [description]
   * @param  {[type]} body   [description]
   * @return {[type]}        [description]
   */
  function showBaiduResult(pageNo,body){
    var title,summary,link,
        reg=/<[^<>]+>/g,
        $ = cheerio.load(body,{decodeEntities: false});

    $('#content_left .result').each(function(i,item){
      var $a = $(item).find('h3 a');
      title = $a.html();
      link = $a.attr('href');
      summary=$(item).find('.c-abstract').html();
      if(title){
        console.log(`第${pageNo+1}頁 第${i+1}條`);
        console.log(`link: ${link}`.green);
        // console.log(`title: ${title}`);
        console.log('title: ');
        ouputColor(title);
        if(summary){
          // console.log(`summary: ${summary}`);
          console.log('summary: ');
          ouputColor(summary);
        }
      }
      console.log('------------------------------');
      console.log('');
    });
  }

  // 知乎
  exports.zhihuSearch=function(keyword,cb){
    get('https://www.zhihu.com/search?type=content&q='+keyword,function(content){
      var title,summary;
      var $ = cheerio.load(content,{decodeEntities: false});
      saveFile(0,keyword,content);
      $('.list .item').each(function(i,item){
        title=$(item).find('.js-title-link').html();
        summary=$(item).find('.summary').html();
        if(title){
          // title=(''+title).replace(/<[^<>]+>/g,'');
          // summary=(''+summary).replace(/<.+>/g,'');
          console.log('title: ');
          ouputColor(title);
          if(summary){
            console.log('summary: ');
            ouputColor(summary);
          }
        }
        console.log('------------------------------');
        console.log('');
      });
    });
  };

執行爬蟲

功能完成後,先試驗一下抓取知乎的內容

grab zh webgl

抓取到的html文件保存在download文件夾,同時在命令行顯示抓取結果。

若是要執行百度的爬蟲,運行以下命令行便可

grab bd webgl

總結

這裏完成的是最基本的爬蟲功能,代碼請看net_grab

相關文章
相關標籤/搜索