1. 摘要
智联招聘汇聚了全国所有最新职位信息、最新招聘信息,是国内专业权威的招聘和职位搜索平台。本项目爬取了杭州地区软件/互联网开发/系统集成等相关职位类别的12000多条职位信息。
2. 工具
- superagent
- cheerio
- async
- mongodb
3. 前期准备
-
在页面选择相应职业类别发现有** 12000 **左右需要爬取的职位
- 一共只有90页,根据分析发现一个页面有60条数据,也就是只能访问到5400条职位信息,这与显示信息出入太大,调查发现此网站只能显示90页的表格数据
-
因此,确定爬取思路是:首先爬取职业类别的职位号,根据得到的职业号,爬取表格的链接,得到所有链接后即可访问所有职位的详情,并存入数据库
4. 模块代码
4.1 获取职位类别名称及代码
function start() {
var job=[];
var opt = {
Referer: url,
'User-Agent': config.url.opt
}
superagent
.get(url)
.set(opt)
.end(function (err,res) {
if(err){
console.log(err)
}
else{
var $ = cheerio.load(res.text);
var links = $('#search_jobtype_tag a').toArray();
for(var i = 2 ; i < links.length ; i++){
var caree = {};
var type=$(links[i]).attr('href').split("&");
caree.code=type[type.length-1].split('=')[1];
caree.name = $(links[i]).text().split('(')[0];
caree.number =parseInt( $(links[i]).text().split('(')[1].split(')')[0]);
job.push(caree)
}
console.log(job)
}
})
}
start()
- 结果输出
var jobList = [
{ code: '045', name: '软件工程师', number: 2303},
{ code: '054', name: '网页设计/制作/美工', number: 1020 },
{ code: '2040', name: 'Java开发工程师', number: 1017 },
{ code: '864', name: 'WEB前端开发', number: 970 },
{ code: '044', name: '高级软件工程师', number: 950 },
{ code: '079', name: '软件研发工程师', number: 735 },
{ code: '669', name: '用户界面(UI)设计', number: 575 },
{ code: '2039', name: 'Android开发工程师', number: 455 },
{ code: '057', name: '游戏设计/开发', number: 445 },
{ code: '2041', name: 'PHP开发工程师', number: 366 },
{ code: '687', name: '嵌入式软件开发', number: 365 },
{ code: '047', name: '数据库开发工程师', number: 333 },
{ code: '679', name: '手机软件开发工程师', number: 329 },
{ code: '053', name: '互联网软件工程师', number: 200 },
{ code: '667', name: '系统架构设计师', number: 199 },
{ code: '2034', name: '算法工程师', number: 194 },
{ code: '2038', name: 'IOS开发工程师', number: 177 },
{ code: '2042', name: 'C语言开发工程师', number: 168 },
{ code: '672', name: '游戏界面设计', number: 136 },
{ code: '671', name: '游戏策划', number: 132 },
{ code: '666', name: '系统集成工程师', number: 101 },
{ code: '048', name: 'ERP技术/开发应用', number: 83 },
{ code: '665', name: '需求工程师', number: 83 },
{ code: '863', name: '移动互联网开发', number: 82 },
{ code: '861', name: '用户体验(UE/UX)设计', number: 81 },
{ code: '668', name: '系统分析员', number: 45 },
{ code: '317', name: '语音/视频/图形开发', number: 41 },
{ code: '2037', name: '网站架构设计师', number: 38 },
{ code: '2036', name: '计算机辅助设计师', number: 30 },
{ code: '2043', name: '脚本开发工程师', number: 16 },
{ code: '2035', name: '仿真应用工程师', number: 10 },
{ code: '060', name: '其他', number: 359 } ];
module.exports = jobList;
4.2 获取职位表格页面链接
根据上述得到的职位类别的代码以及职位数量计算页面个数从而得到所有表格页面的代码
var jobList = require("./data/jobs")
function getLink(cb) {
var links = []
for(var i = 0 ; i< jobList.length ; i++){
var page=Math.ceil(jobList[i].number/60);
for(var j = 1;j <= page;j++){
var url = config.url.job_url + jobList[i].code +'&jl=%E6%9D%AD%E5%B7%9E&sm=0&p='+ j +"&kt=2&isfilter=1&fl=653&isadv=0";
links.push(url)
}
}
cb(null,links)
}
4.3 获取职位详情链接
抓取职位表格页面中每项中详情页的链接并保存
//获取详细页面
var jobLink = []
function getDetailLink(links,cb) {
async.eachLimit(links, 5, function(item, callback) {
superagent.get(item).end(function (err, res) {
try {
if(res.ok) {
console.log(item + ' 获取页面中...');
getJobLink(res.text);
callback();
} else {
console.log(item + ' 获取页面失败...');
callback();
}
sleep(0.1)
} catch (e) {
console.log(e.message);
callback();
}
})
}, function(err) {
if (err) {
console.log('Mession Failed!');
} else {
console.log('共获取到'+jobLink.length+'个具体页面');
cb(null, jobLink);
}
});
}
function getJobLink(text) {
var $ = cheerio.load(text);
var jobs=$('.newlist_list_content table').toArray();
for(var i=1;i
4.4 爬取职位详情并存入数据库
4.4.1 数据库设计
var jobSchema = new Schema({
posname: String, //职位类别
salary: String, //职位月薪
pubdate: String, //发布日期
type: String, //工作性质
exp: String, //工作经验
edu: String, //最低学历
count: String, //招聘人数
company: String, //公司
desc: String, //职位描述
url: {type:String,unique:true} //详情地址
});
module.exports = mongoose.model('Jobs', jobSchema);
4.4.2 爬取信息
function saveDB(jobLink,cb) {
async.eachLimit(jobLink,30,function (item,cb) {
superagent.get(item).end(function (err,res) {
try {
if(res.ok) {
console.log(item + ' 获取页面中...');
grapData(res.text,item);
cb();
} else {
console.log(item + ' 获取页面失败...');
cb();
}
} catch (e) {
console.log(e.message);
cb();
}
})
})
}
function grapData(text ,url ){
var $ = cheerio.load(text);
var job = {};
var detail = $('.terminalpage-left ul li').toArray()
//职位类别
job.posname = ($(detail[7]).text()).split(':')[1];
//职位月薪
job.salary = ($(detail[0]).text()).split(':')[1];
//发布日期
job.pubdate = ($(detail[2]).text()).split(':')[1];
//工作性质
job.type = ($(detail[3]).text()).split(':')[1];
//工作经验
job.exp = ($(detail[4]).text()).split(':')[1];
//最低学历
job.edu = ($(detail[5]).text()).split(':')[1];
//招聘人数
job.count = ($(detail[6]).text()).split(':')[1];
//公司
job.company = $('.inner-left h2').text();
//职位描述
job.desc = $('.tab-inner-cont').text().replace(/\s+/g, '');
job.url = url;
saveJob(job)
// console.log(job)
}
function saveJob(job){
var job = new Jobs({
posname:job.posname,
salary:job.salary ,
pubdate:job.pubdate,
type:job.type ,
exp:job.exp,
edu:job.edu,
count:job.count ,
company:job.company ,
desc:job.desc ,
url:job.url
});
job.save(function (err, doc) {
if (err) {
console.log("失败");
}
else {
console.log("保存成功");
}
});
}
4.5 函数调用
function start() {
async.waterfall([
getLink,
getDetailLink,
saveDB
], function (err, result) {
if(err) {
console.log('error: ' + err);
} else {
console.log(jobLink.length)
console.log('任务完成!!!');
}
});
}
start();
源码地址