博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
nodejs爬虫——汽车之家所有车型数据
阅读量:5934 次
发布时间:2019-06-19

本文共 7705 字,大约阅读时间需要 25 分钟。

应用介绍

项目Github地址:

nodejs爬虫,爬取汽车之家所有车型数据

包括品牌,车系,年份,车型四个层级。

使用的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. 按需写入数据库(暂时没写)

细节控制

在售款有2016,2017同时存在

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

抓取失败时重新抓取该页面

项目代码

Github地址:

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 fetchBrand(req, res) {  var pageUrls = []; // 存放爬取网址  var count = 0; // 总数  var countSuccess = 0; // 成功数  var chars = ['A', 'B', 'C', 'D', 'F', 'G', 'H', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'W', 'X', 'Y', 'Z'];  for (var char of chars) {    count++;    pageUrls.push('http://www.autohome.com.cn/grade/carhtml/' + char + '.html');  }  var curCount = 0;  var reptileMove = function(url, callback) {    var startTime = Date.now(); // 记录该次爬取的开始时间    request({      url: url,      encoding: null // 关键代码    }, 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 curBrands = $('dl');      for (var i = 0; i < curBrands.length; i++) {        var obj = {          name: curBrands.eq(i).find('dt div a').text(),          sub: []        }        fetchData.push(obj);        var curSeries = curBrands.eq(i).find('h4 a');        for (var j = 0; j < curSeries.length; j++) {          var obj = {            name: curSeries.eq(j).text(),            sub: [],            url: curSeries.eq(j).attr('href')          }          fetchData[fetchData.length - 1].sub.push(obj);        }      }      countSuccess++;      var time = Date.now() - startTime;      console.log(countSuccess + ', ' + url + ', 耗时 ' + time + 'ms');      callback(null, url + 'Call back content');    });  };  // 使用async控制异步抓取     // mapLimit(arr, limit, iterator, [callback])  // 异步回调  async.mapLimit(pageUrls, 1, function(url, callback) {    reptileMove(url, callback);  }, function(err, result) {    console.log('----------------------------');    console.log('品牌车系抓取完毕!');    console.log('----------------------------');    fetchYear(req, res);  });}/** * 爬取年份 */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');// });

转载地址:http://qpjtx.baihongyu.com/

你可能感兴趣的文章
用户登录系统之后,禁止用户返回到登录页面
查看>>
java.lang.NoClassDefFoundError: javax/mail/Authenticator
查看>>
数据库多对多型数据表分类设计
查看>>
深入Activity,Activity启动模式LaunchMode完全解析
查看>>
黄聪:iis7.5 偶尔出现500服务器错误-内部服力器错误
查看>>
CSS3与页面布局学习总结
查看>>
驱动的境界
查看>>
sql 转 markdown
查看>>
Noise,Error,wighted pocket Algorithm
查看>>
hive内部表、外部表、分区表、视图
查看>>
人工智能--学术会议排名
查看>>
轻量级C#编辑器RoslynPad
查看>>
[Asp.net mvc]OutputCacheAttribute
查看>>
html布局小练习(百度首页)
查看>>
lmdb简介——结合MVCC的B+树嵌入式数据库
查看>>
浏览器对localstorage的支持情况以及localstorage在saas系统中的应用实践思考
查看>>
rsync常用参数详解
查看>>
(转)能根据文字生成图片的 GAN,深度学习领域的又一新星
查看>>
回顾2016展望2017
查看>>
weblogic线程阻塞性能调优(图解)转
查看>>