nodejs爬蟲——汽車之家所有車型數據

dd90w156f3 7年前發布 | 35K 次閱讀 Node.js 網絡爬蟲

應用介紹

項目Github地址:https://github.com/iNuanfeng/node-spider/

nodejs爬蟲,爬取汽車之家所有車型數據 http://www.autohome.com.cn/car/

包括品牌,車系,年份,車型四個層級。

使用的node模塊:

superagent, request, iconv; (網絡請求模塊,iconv用于gbk轉碼)

cheerio; (和jQuery一樣的API,處理請求來的html,省去正則匹配)

eventproxy, async; (控制并發請求,async控制得更細)

async控制并發請求數量為10個(避免封IP與網絡錯誤)

模擬sleep使間隔100ms(不設間隔偶爾會出現dns錯誤)

去除express模塊,該為控制臺直接開啟爬蟲(數據量大,打開網頁來開啟爬蟲可能會由于超時而重新發起訪問)

最終使用的模塊為: request , iconv , cheerio , async

最后寫入到數據庫mysql或mongoDB

寫入data.json:

項目說明

app.js是爬蟲主程序,分步驟抓取數據。

  1. 抓取品牌和車系
  2. 抓取年份
  3. 抓取車型
  4. 存入本地json文件
  5. 按需寫入數據庫(暫時沒寫)

細節控制

http://www.autohome.com.cn/3128 在售款有2016,2017同時存在

有的車系在售有2016,停售也有2016

抓取失敗時重新抓取該頁面

項目代碼

Github地址: https://github.com/iNuanfeng/node-spider/

app.js:

var express = require('express'),
  app = express(),
  request = require('request'),
  iconv = require('iconv-lite'),
  cheerio = require('cheerio'),
  async = require("async"), // 控制并發數,防止被封IP
  fs = require('fs');

var fetchData = []; // 存放爬取數據

/**

  • 睡眠模擬函數
  • @param {Number} numberMillis 毫秒 */ function sleep(numberMillis) { var now = new Date(); var exitTime = now.getTime() + numberMillis; while (true) { now = new Date(); if (now.getTime() > exitTime) return; } }

/**

}

/**

  • 爬取年份 */ function fetchYear(req, res) { var count = 0; // 總數 var countSuccess = 0; // 成功數 var seriesArr = []; // 輪詢所有車系 for (var brand of fetchData) { for (var series of brand.sub) { count++; seriesArr.push(series); } }

    var curCount = 0; var reptileMove = function(series, callback) { var startTime = Date.now(); // 記錄該次爬取的開始時間 curCount++; // 并發數

    request({ url: series.url, encoding: null // gbk轉碼關鍵代碼 }, function(err, res, body) { if (err || res.statusCode != 200) {

     console.error(err);
     console.log('抓取該頁面失敗,重新抓取該頁面..')
     reptileMove(series, callback);
     return false;
    

    }

    var html = iconv.decode(body, 'gb2312') var $ = cheerio.load(html);

    // 頁面默認的數據 var itemList = $('.interval01-list li'); itemList.each(function(){

     var year = $(this).find('a').eq(0).text().substr(0, 4);
     var name = $(this).find('a').eq(0).text();
     var flag = false;
     for (item of series.sub) {
       if (item.name == year) {
         item.sub.push(name);
         flag = true;
       }
     }
     if (!flag) {
       var obj = {
         name: year,
         sub: [$(this).find('a').eq(0).text()],
         url: ''
       };
       series.sub.push(obj);
     }
    

    });

    // 下拉框中的年份抓取 var curYears = $('.cartype-sale-list li'); curYears.each(function(){

     var year = $(this).text().substr(0, 4);
     var flag = false;
    
     var href = series.url;
     var s = href.split('/')[3]; // 從url中截取所需的s參數
     var y = ($(this).find('a').attr('data'))
     var url = 'http://www.autohome.com.cn/ashx/series_allspec.ashx?s='
               + s + '&y=' + y;
    
     for (item of series.sub) {
       if (item.name == year) {
         item.url = url;
         flag = true;
       }
     }
     if (!flag) {
       var obj = {
         name: year,
         sub: [],
         url: url
       };
       series.sub.push(obj);
     }
    

    })

    curCount--; countSuccess++; var time = Date.now() - startTime; console.log(countSuccess + ', ' + series.url + ', 耗時 ' + time + 'ms');

    sleep(50); callback(null, series.url + 'Call back content'); }); };

    console.log('車系數據總共:' + count + '條,開始抓取...')

    // 使用async控制異步抓取
    // mapLimit(arr, limit, iterator, [callback]) // 異步回調 async.mapLimit(seriesArr, 10, function(series, callback) { reptileMove(series, callback); }, function(err, result) { // 訪問完成的回調函數 console.log('----------------------------'); console.log('車系抓取成功,共有數據:' + countSuccess); console.log('----------------------------'); fetchName(req, res); }); }

/**

  • 爬取型號 */ function fetchName(req, res) { var count = 0; // 總數 var countSuccess = 0; // 成功數 var yearArr = []; // 輪詢所有車系 for (var brand of fetchData) { for (var series of brand.sub) { for (var year of series.sub) {

     if (year.url) {
       count++;  // 過濾沒有url的年款
       yearArr.push(year);
     }
    

    } } }

    var curCount = 0; var reptileMove = function(year, callback) { var startTime = Date.now(); // 記錄該次爬取的開始時間 curCount++; // 并發數 // console.log(curCount + ': ' + series.url);

    request({ url: year.url, encoding: null // gbk轉碼關鍵代碼 }, function(err, res, body) { if (err || res.statusCode != 200) {

     console.error(err);
     console.log('抓取該頁面失敗,重新抓取該頁面..')
     console.log(year)
     reptileMove(year, callback);
     return false;
    

    }

    console.log(countSuccess + ', 抓取: ' + year.url) var html = iconv.decode(body, 'gb2312') try {

     var data = JSON.parse(html)
    

    } catch(e) {

     console.log('error... 忽略該頁面');
     // reptileMove(series, callback);
     curCount--;
     callback(null, year.url + 'Call back content');
     return false;
    

    } var specArr = data.Spec; for (var item of specArr) {

     year.sub.push(item.Name);
    

    }

    curCount--; countSuccess++; var time = Date.now() - startTime; // sleep(100); callback(null, year.url + 'Call back content'); }); };

    console.log('車型數據總共:' + count + '條,開始抓取...')

    // 使用async控制異步抓取
    // mapLimit(arr, limit, iterator, [callback]) // 異步回調 async.mapLimit(yearArr, 20, function(year, callback) { reptileMove(year, callback); }, function(err, result) { // 訪問完成的回調函數 console.log('----------------------------'); console.log('車型抓取成功,共有數據:' + countSuccess); console.log('----------------------------'); // res.send(fetchData); var t = JSON.stringify(fetchData); fs.writeFileSync('data.json', t); }); }

/**

  • 爬蟲入口 */ fetchBrand();

// 開啟express路由,用于瀏覽器調試 // app.get('/', fetchBrand); // var server = app.listen(3000, function() { // console.log('listening at 3000'); // });</code></pre>

 

來自:http://www.cnblogs.com/woodk/p/6431645.html

 

 本文由用戶 dd90w156f3 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!