数据展示地址:http://lg.otpath.com/
项目代码地址:https://github.com/WayneLiang/crawler-lagou
爬虫开始
环境要求
- Node.js环境
- Mongodb环境
主要模块
- superagent 网络请求
- superagent-proxy 代理IP转发
- cheerio jQuery 核心实现
- mongoose mongodb数据库使用
- koa web框架
- echarts 数据统计图表
一、抓取代理IP
防止请求过于频繁导致ip被网站屏蔽,请求都是使用代理IP进行。所以必须先获取对可用的代理IP,我选择http://www.xicidaili.com/nn/ 上的代理。然而获取回来的IP并不是每一个都可用,故需使用代理去请求http://ip.chinaz.com/getip.aspx ,若3秒内有响应即当作可用。具体代码如下:
var Models = require('../lib/core');
var $Ip = Models.$Ip;
var request = require('superagent');
var cheerio = require('cheerio');
require('superagent-proxy')(request);
(async function () {
for(var page = 1; page <= 10; page++){
//请求代理IP页面
var res = await request.get('http://www.xicidaili.com/nn/' + page);
var $ = cheerio.load(res.text);
var tr = $('tr');
//从第二行开始获取IP和端口
for(var line = 1 ; line < tr.length ; line++ ){
var td = $(tr[line]).children('td');
var proxy = 'http://' + td[1].children[0].data + ':' + td[2].children[0].data;
try {
//代理IP请求,设置超时为3000ms,返回正确即当可用
var testip = await request.get('http://ip.chinaz.com/getip.aspx').proxy(proxy).timeout(3000);
if(testip.statusCode == 200 && testip.text.substring(0,4) == '{ip:' ){
//存入数据库
await $Ip.addIp({proxy: proxy});
}
}catch (error){
}
}
}
})();
二、抓取拉勾数据
1.抓取城市列表
直接使用superagent请求http://www.lagou.com/lbs/getAllCitySearchLabels.json 即可获取城市列表-
2.抓取职位列表
- superagent请求http://www.lagou.com
- cheerio加载返回的html
- 获取id=sidebar的所有数据(menu_main类是一级,menu_sub类是二级)
async function crawlerPosition() {
var res = await request.get('http://www.lagou.com');
var $ = cheerio.load(res.text);
var length = $('#sidebar .menu_box').length;
var positions,position = {};
for(var num=0 ; num < length; num++){
position.name = $($('.menu_main h2')[num]).text().replace(/\n/g,'').replace(/ /g,'');
position.sub = [];
var menu_sub = ($($('.menu_sub')[num]).children('dl'));
for(var subnum=0 ; subnum < menu_sub.length; subnum++){
var subPosition = {};
subPosition.name = $(menu_sub[subnum]).children('dt').children('a').text();
subPosition.position = [];
positions = $(menu_sub[subnum]).children('dd').children('a');
for(var positionnum=0 ; positionnum < positions.length; positionnum++){
subPosition.position.push($(positions[positionnum]).text());
}
position.sub.push(subPosition);
}
await $Position.addPosition(position);
}
console.log('**************finish crawer position data***************');
}
- 3.抓取各职位在各城市的招聘总数
使用superagent和superagent-proxy代理请求http://www.crawler.com/jobs/positionAjax.json?px=new&city= 请求如果出错或无法获取数据则切换下一个IP再请求一遍,请求是需要post的表单为{ kd: position.name, pn: page }
async function crawlerJobTotal(city,position) {
var proxy = ips[ipNo++].proxy;
var positionResult,jobResult;
if(ipNo >= ips.length){ ipNo = 0; }
try {
positionResult = await request.post('http://www.crawler.com/jobs/positionAjax.json?px=new&needAddtionalResult=false&city='+city)
.type('application/x-www-form-urlencoded')
.send({ kd: position.name, pn: 1,first:true })
.proxy(proxy)
.timeout(3000);
}catch(error){
console.log('request error, again');
return await crawlerJobTotal(city,position);
}
var totalCount;
if(positionResult.body && positionResult.body.success && (positionResult.body.content.length != 0) &&(positionResult.body.content.positionResult!= 0)){
totalCount = positionResult.body.content.positionResult.totalCount;
console.log(city,position.name,1,Date.now(),totalCount);
var item = {};
item.city = city;
item.position = position.name;
item.firstTag = position.firstTag;
item.secondTag = position.secondTag;
item.total = totalCount;
await $JobTotal.addJobTotal(item);
}else{
console.log('could not get positionResult,again',proxy);
return await crawlerJobTotal(city,position);
}
}
- 4.抓取各职位在各城市的具体招聘情况
使用superagent和superagent-proxy代理请求http://www.crawler.com/jobs/positionAjax.json?px=new&city= 请求如果出错或无法获取数据则切换下一个IP再请求一遍,请求是需要post的表单为{ kd: position.name, pn: page },这里需要注意的是拉勾返回的总的数据数会比json数据里面的totalCount少。这部分代码请看https://github.com/WayneLiang/crawler-lagou/blob/master/crawler/lagou.js#L22
三、数据展示
- 具体数据展示可以访问http://lg.otpath.com/
- 具体实现代码可以看https://github.com/WayneLiang/crawler-lagou
- 具体echarts图表的使用可以访问http://echarts.baidu.com/