本文首发于 github blogjavascript
不想看爬虫过程只想看职位钱途数据分析请看这里:
前端招聘岗位分析
C++招聘岗位分析
JAVA招聘岗位分析
PHP招聘岗位分析
Python招聘岗位分析php
想看源码或想本身爬一个请看这里:本文github源码html
早在一年前大学校招期间,为了充实下简历,就写了个node
爬虫,惋惜当时能力有限,工程存在必定的局限性,很差意思拿出来装逼分享。 前端
一年过去了,如今能力依然有限,可是脸皮却练厚了,因而就有了这篇文章。java
关于爬虫,主流技术是用python
,然而随着node
的出现,对于对python
了解有限的前端同窗,用node
来实现一个爬虫也不失为一个不错的选择。node
固然不管是python
爬虫仍是node
爬虫或者其余品种的爬虫,其实除了语言特性以外,其思路基本大同小异。下面我就为你们详细介绍下node
爬虫的具体思路与实现,内容大概以下:python
爬前准备git
爬虫github
JSON
数据HTML
文档,提取有用信息既然要写爬虫,固然要爬一些利益相关的数据比较好玩啦。爬取招聘网站的招聘信息,来看看互联网圈子里各个工种的目前薪酬情况及其发展前景,想来是不错的选择。web
经我夜观天下,掐指一算,就选拉勾网吧。
一个职位招聘信息,通常来讲,咱们关注的重点信息会是:
带着想要收集的信息,首先,进入拉勾官网,搜索web前端
岗位,能看到
很好,咱们想要的信息基本都有了。
F12
分析请求资源,可得https://www.lagou.com/jobs/positionAjax.json?needAddtionalResult=false&isSchoolJob=0
post 请求体
{ first:false, pn:1, kd:`web前端` }
响应JSON数据
完美!!! 数据格式都已经帮咱们整理好了,直接爬就好了。
但,完美的数据总不会这么轻易让你获得,经我用 node
和 python
,还有postman
携带浏览器所有header
信息一一测试,均发现:
好吧,此路不通。(此接口反爬虫机制不明,有研究的大神请留言=_=)
所谓条条大路通罗马,此路不通,咱绕路走。
通过一番探索,发现 拉勾移动端站点 空门大开!
提示: 通常有点技术含量的网站均可能会存在不一样强度的反爬虫机制,而通常其移动端站点的反爬虫机制相对于PC站点较弱,是一个不错的着手点。再不行的话,还能够去其app端抓包分析是否存在想要的请求哦。
GET请求: https://m.lagou.com/search.js...
响应信息:
很好,虽然数据信息有点少,可是总算是一个能爬的接口了。
好了,分析也分析完了,如今正式设计爬虫程序。
首先,把请求的路径与参数单独抽离。
let spider = { requestUrl : "http://m.lagou.com/search.json", query: { city: '', pageNum: '', job: '', }, ... }
发出请求,此处的服务端构造请求使用 superagent,固然,用 request 等相似的包也能够,并没有限定。
let spider = { .... /** * 发起单个请求 * @return {<Promise<Array>> | <Promise<String>>} 请求成功resolve原始数据,不然reject **/ request() { return new Promise((resolve,reject)=>{ superagent .get(this.requestUrl) .query({ city: this.query.city, pageNo: this.query.pageNum, positionName: this.query.job }).end((err, res)=>{ let dataList = []; if (err || !res || !res.ok) { console.error(err); reject('request failed!') } else { dataList = res.body.content.data.page.result if (dataList.length === 0) { // 当请求结果数组长度为0,即认为已经到末页,结束爬虫 reject('finish'); } else { resolve(dataList) } } }) }) },
处理数据
let spider = { .... /** * 处理爬取到的原始数据,提取出所需的数据 * @param {<Array>} - companyList : 原始数据 * @return {<Promise<Array>>} resolve处理过的数据 **/ handleCallbackData(companyList) { //处理数据 let arr = companyList.map((item) => { let salary = item.salary.split('-'); //工资两种状况:”10k以上“ or "10k-15k", 平均工资取中位数 aveSalary = salary.length == 1 ? parseInt(salary[0])*1000 : (parseInt(salary[0]) + parseInt( salary[1] ) )*500; //过滤出所需数据 return { companyFullName: item.companyFullName, positionId : item.positionId , salary:aveSalary , city:item.city , field: '', companySize:'', workYear:'' , qualification: '', } }); return Promise.resolve(arr) }
保存数据,此处数据库使用mongodb
,ORM
使用 moogoose
。
save2db(jobList) { return new Promise((resolve, reject)=>{ Job.create(jobList,function (err,product) { if (err) { console.error(err.errmsg) err.code == 11000 && resolve('丢弃重复数据') reject(err); } else { resolve("save data to database successfully") } }) }) },
从上述的json
数据其实咱们能够看到,JSON
返回的信息十分有限,那么咱们须要爬取更多的信息,就须要在招聘详情页解析 html 后提取出所需的信息
随便打开一个移动端的招聘详情页https://m.lagou.com/jobs/3638173.html,目测出url
结构很简单,就是jobs/{{positionId}}.html
从详情页中能够找出 JSON 数据中缺乏的数据项:工做年限要求,学历要求,雇主公司领域,雇主公司融资状况,雇主公司规模大小。
爬取方法和上述爬取 JSON
数据相差无几,主要差异就是数据解析部分,这里须要用到cherrio
来解析 爬取到的HTML,从而更简单地提取必要信息。
handleCallbackData({res, jobId}) { var $ = cheerio.load(res.text); let workYear = $('#content > div.detail > div.items > span.item.workyear > span').text(), qualification = $('#content > div.detail > div.items > span.item.education').text().trim(), field = $('#content > div.company.activeable > div > div > p').text().trim().split(/\s*\/\s*/)[0] companySize = $('#content > div.company.activeable > div > div > p').text().trim().split(/\s*\/\s*/)[2]; /* 若是这四项数据都没有提取到,颇有多是被拉勾的反爬虫机制拦截了 */ if ( !(workYear || qualification || field || companySize) ) { console.log(res.text) return Promise.reject({code:-1, msg:'wrong response!', jobId}); } return { id: jobId, jobInfo: { workYear, qualification, field, // financeStage, companySize, } } },
作过爬虫的都知道,爬虫的请求并发量是必需要作的,为何要控制并发?
实现并发控制可使用npm
包 async.mapLimit,这里为了自由度更大我使用了本身实现的 15 行代码实现并发控制。
具体代码以下:
let ids = [2213545,5332233, ...], // 招聘岗位详情id列表 limit = 10, // 并发数 runningRequestNum = 0 , // 当前并发数 count = 0; // 累计爬取数据项计数 mapLimit(ids, limit, async (jobId)=>{ let requestUrl = `http://m.lagou.com/jobs/${jobId}.html?source=home_hot&i=home_hot-6` ; let delay = parseInt(Math.random() * 2000); let currentIndex = count++; runningRequestNum++ await sleep( delay ); // 避免爬太快被封ip,休眠一两秒 let result = await spiderHTML.run({ requestUrl, jobId, proxyIp }) console.log(`当前并发数`, runningRequestNum) runningRequestNum-- return result; }).then(mapResult => { // 并发控制下将 ids 所有迭代完毕 // do something })
然而,即使严格控制了请求频率,咱们仍是不可避免地中招了。
对于反爬虫措施比较暴躁的网站来讲,一个IP爬取太过频繁,被识别成机器爬虫几乎是不可避免的。
通常来说,咱们最简单直接的方法就是:换IP。这个IP访问频率过高了被反爬拦截到,换个IP就好了嘛。
单个IP爬虫对于反爬较为严厉的网站是走不通的。那么咱们须要用到动态IP池,每次爬取时从IP池中拉取一个IP出来爬数据。
道理很简单,
1秒内1个IP访问了100个页面,即使是单身20多年的手速也没法企及。只能是机器爬虫无疑。
但1秒内100个IP访问100个页面,平均每一个IP一秒内访问了1个页面,那基本不会被反爬干掉
怎么搭建动态IP池?
动态IP池工做流程:
st=>start: 提取一个可用IP e=>end: 根据策略返回一个可用IP isEnought=>condition: 池中IP数量是否足够 fetch=>operation: 从IP源拉取IP valid=>operation: 筛选出有效IP并存入IP池 st->isEnought(yes)->e isEnought(no,right)->fetch(right)->valid(right)->isEnought
具体实现代码其实和上面的爬虫差很少,无非就是爬岗位变成了爬IP而已,具体实现源码在这,就不在这写了。
咱们最终折腾爬虫,无非就是想要看爬到的数据到底说明了什么。
成功爬取了拉钩网上多个招聘岗位的具体信息后,数据可视化并得出分析结果以下:
从总体看,北上广深杭这五个城市前端工程师招聘岗位,北京是遥遥领先,是深圳的两倍,是广州的三倍,其次到上海,深圳,杭州,广州居末。
从需求量大概能够看出,总体互联网产业发达程度是 北 > 上 > 深 > 杭 > 广
由平均工资曲线图能够看到,每隔2K算一档的话,北京一档,上海一档,杭州深圳一档,空一档,广州吊车尾,杭州居然比深圳高了300,这就表明着深圳虽然招聘需求比杭州大,但二者薪酬待遇其实差很少。
从不一样薪酬的招聘数量也能看出一些很大的区别,招聘提供薪资水平中,广泛数量最多的是10k-20k这个水平,但,北京牛逼,招聘岗位60%以上都是20K以上的。咱们具体来看看,各个城市对高端人才(提供薪酬20k以上)的招聘比例,那就能够看出明显区别了:
基本能够看到一个明显的趋势,公司规模越大,能提供的薪酬越高,不差钱。
另外,从不一样规模的公司的前端招聘数量来看,北京又一枝独秀,大公司招聘需求很高。
但从全国来看,不一样规模的公司(除了15人如下的)招聘数量基本在同一水平,基本说明:大公司少,可是每一个公司招聘的人多;小公司多,可是每一个公司招聘的人少。好像这是句废话。
从图上看,工做经历在1-5年的如今需求最旺盛,而且理所固然地,工做资历越高,薪资越高。
其中3-5年的最吃香,广州有点奇怪,1-3年的最吃香?综合上面的多项数据,感受像是1-3年工资比3-5年低因此广州互联网公司多招1-3年
固然,这里存在这一个幸存者误差,拉勾上大部分的都是社招性质的招聘,而应届生和1年经验的大部分都跑校招去了吧,因此数量低也不出奇。
移动互联网占据了大半壁江山,剩下之中,金融,电子商务,企业服务,数据服务在同一层次。另外,物联网,智能硬件各有一招聘岗位,薪酬都是5K...嗯虽然说node如今也能够作物联网了(还别说,我还真的用node搞过硬件串口通讯Orz),可是终究不是主流技术,数据展现代表,前端基本与硬件绝缘。
薪酬待遇却是都在同一水平上,“大数据”工资却是一枝独秀,可是数据量太少,参考价值不大。
总结:北京钱多机会多当之无愧第一档;上海稍逊一筹;杭州深圳又低一筹;广州真的是差了两个身位。 而对于前端来讲,北京 移动互联网 大公司,钱多!坑多!速来!