本文首發於 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),可是終究不是主流技術,數據展現代表,前端基本與硬件絕緣。
薪酬待遇卻是都在同一水平上,「大數據」工資卻是一枝獨秀,可是數據量太少,參考價值不大。
總結:北京錢多機會多當之無愧第一檔;上海稍遜一籌;杭州深圳又低一籌;廣州真的是差了兩個身位。 而對於前端來講,北京 移動互聯網 大公司,錢多!坑多!速來!