摘要:成功爬取了拉鉤網(wǎng)上多個(gè)招聘崗位的具體信息后,數(shù)據(jù)可視化并得出分析結(jié)果如下從整體看,北上廣深杭這五個(gè)城市前端工程師招聘崗位,北京是遙遙領(lǐng)先,是深圳的兩倍,是廣州的三倍,其次到上海,深圳,杭州,廣州居末。
前前言
本文首發(fā)于 github blog
不想看爬蟲(chóng)過(guò)程只想看職位錢途數(shù)據(jù)分析請(qǐng)看這里:
前端招聘崗位分析
C++招聘崗位分析
JAVA招聘崗位分析
PHP招聘崗位分析
Python招聘崗位分析
想看源碼或想自己爬一個(gè)請(qǐng)看這里:本文github源碼
前言早在一年前大學(xué)校招期間,為了充實(shí)下簡(jiǎn)歷,就寫了個(gè)node爬蟲(chóng),可惜當(dāng)時(shí)能力有限,工程存在一定的局限性,不好意思拿出來(lái)裝逼分享。
一年過(guò)去了,現(xiàn)在能力依然有限,但是臉皮卻練厚了,于是就有了這篇文章。
題綱關(guān)于爬蟲(chóng),主流技術(shù)是用python,然而隨著node的出現(xiàn),對(duì)于對(duì)python了解有限的前端同學(xué),用node來(lái)實(shí)現(xiàn)一個(gè)爬蟲(chóng)也不失為一個(gè)不錯(cuò)的選擇。
當(dāng)然無(wú)論是python爬蟲(chóng)還是node爬蟲(chóng)或者其他品種的爬蟲(chóng),其實(shí)除了語(yǔ)言特性之外,其思路基本大同小異。下面我就為大家詳細(xì)介紹下node爬蟲(chóng)的具體思路與實(shí)現(xiàn),內(nèi)容大概如下:
爬前準(zhǔn)備
選擇目標(biāo)
分析可收集數(shù)據(jù)與目標(biāo)可爬取入口
爬蟲(chóng)
爬取JSON數(shù)據(jù)
爬取HTML文檔,提取有用信息
Mongodb 數(shù)據(jù)存儲(chǔ)
并發(fā)控制
動(dòng)態(tài)IP代理(防止IP被禁)
數(shù)據(jù)可視化展示
爬前準(zhǔn)備 選擇目標(biāo)既然要寫爬蟲(chóng),當(dāng)然要爬一些利益相關(guān)的數(shù)據(jù)比較好玩啦。爬取招聘網(wǎng)站的招聘信息,來(lái)看看互聯(lián)網(wǎng)圈子里各個(gè)工種的目前薪酬?duì)顩r及其發(fā)展前景,想來(lái)是不錯(cuò)的選擇。
經(jīng)我夜觀天下,掐指一算,就選拉勾網(wǎng)吧。
分析可收集數(shù)據(jù)一個(gè)職位招聘信息,一般來(lái)說(shuō),我們關(guān)注的重點(diǎn)信息會(huì)是:
薪酬(毫無(wú)疑問(wèn),重中之重)
工作城市
學(xué)歷要求
工作年限要求
雇主公司
公司領(lǐng)域
公司規(guī)模
帶著想要收集的信息,首先,進(jìn)入拉勾官網(wǎng),搜索web前端崗位,能看到
很好,我們想要的信息基本都有了。
分析目標(biāo)可爬取入口 PC端入口F12 分析請(qǐng)求資源,可得https://www.lagou.com/jobs/positionAjax.json?needAddtionalResult=false&isSchoolJob=0
post 請(qǐng)求體
{ first:false, pn:1, kd:`web前端` }
響應(yīng)JSON數(shù)據(jù)
完美!!! 數(shù)據(jù)格式都已經(jīng)幫我們整理好了,直接爬就行了。
但,完美的數(shù)據(jù)總不會(huì)這么輕易讓你得到,經(jīng)我用 node 和 python,還有postman 攜帶瀏覽器全部header信息一一測(cè)試,均發(fā)現(xiàn):
好吧,此路不通。(此接口反爬蟲(chóng)機(jī)制不明,有研究的大神請(qǐng)留言=_=)
所謂條條大路通羅馬,此路不通,咱繞路走。
移動(dòng)端入口經(jīng)過(guò)一番探索,發(fā)現(xiàn) 拉勾移動(dòng)端站點(diǎn) 空門大開(kāi)!
提示: 一般有點(diǎn)技術(shù)含量的網(wǎng)站都可能會(huì)存在不同強(qiáng)度的反爬蟲(chóng)機(jī)制,而一般其移動(dòng)端站點(diǎn)的反爬蟲(chóng)機(jī)制相對(duì)于PC站點(diǎn)較弱,是一個(gè)不錯(cuò)的著手點(diǎn)。再不行的話,還可以去其app端抓包分析是否存在想要的請(qǐng)求哦。
GET請(qǐng)求: https://m.lagou.com/search.js...
響應(yīng)信息:
很好,雖然數(shù)據(jù)信息有點(diǎn)少,但是總算是一個(gè)能爬的接口了。
爬蟲(chóng)好了,分析也分析完了,現(xiàn)在正式設(shè)計(jì)爬蟲(chóng)程序。
JSON數(shù)據(jù)爬取
首先,把請(qǐng)求的路徑與參數(shù)多帶帶抽離。
let spider = { requestUrl : "http://m.lagou.com/search.json", query: { city: "", pageNum: "", job: "", }, ... }
發(fā)出請(qǐng)求,此處的服務(wù)端構(gòu)造請(qǐng)求使用 superagent,當(dāng)然,用 request 等類似的包也可以,并無(wú)限定。
let spider = { .... /** * 發(fā)起單個(gè)請(qǐng)求 * @return {> | >} 請(qǐng)求成功resolve原始數(shù)據(jù),否則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) { // 當(dāng)請(qǐng)求結(jié)果數(shù)組長(zhǎng)度為0,即認(rèn)為已經(jīng)到末頁(yè),結(jié)束爬蟲(chóng) reject("finish"); } else { resolve(dataList) } } }) }) },
處理數(shù)據(jù)
let spider = { .... /** * 處理爬取到的原始數(shù)據(jù),提取出所需的數(shù)據(jù) * @param {} - companyList : 原始數(shù)據(jù) * @return { >} resolve處理過(guò)的數(shù)據(jù) **/ handleCallbackData(companyList) { //處理數(shù)據(jù) let arr = companyList.map((item) => { let salary = item.salary.split("-"); //工資兩種情況:”10k以上“ or "10k-15k", 平均工資取中位數(shù) aveSalary = salary.length == 1 ? parseInt(salary[0])*1000 : (parseInt(salary[0]) + parseInt( salary[1] ) )*500; //過(guò)濾出所需數(shù)據(jù) return { companyFullName: item.companyFullName, positionId : item.positionId , salary:aveSalary , city:item.city , field: "", companySize:"", workYear:"" , qualification: "", } }); return Promise.resolve(arr) }
保存數(shù)據(jù),此處數(shù)據(jù)庫(kù)使用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("丟棄重復(fù)數(shù)據(jù)") reject(err); } else { resolve("save data to database successfully") } }) }) },HTML 數(shù)據(jù)解析爬取
從上述的json數(shù)據(jù)其實(shí)我們可以看到,JSON返回的信息十分有限,那么我們需要爬取更多的信息,就需要在招聘詳情頁(yè)解析 html 后提取出所需的信息
隨便打開(kāi)一個(gè)移動(dòng)端的招聘詳情頁(yè)https://m.lagou.com/jobs/3638173.html,目測(cè)出url結(jié)構(gòu)很簡(jiǎn)單,就是jobs/{{positionId}}.html
從詳情頁(yè)中可以找出 JSON 數(shù)據(jù)中缺少的數(shù)據(jù)項(xiàng):工作年限要求,學(xué)歷要求,雇主公司領(lǐng)域,雇主公司融資情況,雇主公司規(guī)模大小。
爬取方法和上述爬取 JSON 數(shù)據(jù)相差無(wú)幾,主要差別就是數(shù)據(jù)解析部分,這里需要用到cherrio來(lái)解析 爬取到的HTML,從而更簡(jiǎn)單地提取必要信息。
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]; /* 如果這四項(xiàng)數(shù)據(jù)都沒(méi)有提取到,很有可能是被拉勾的反爬蟲(chóng)機(jī)制攔截了 */ 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, } } },并發(fā)控制
做過(guò)爬蟲(chóng)的都知道,爬蟲(chóng)的請(qǐng)求并發(fā)量是必須要做的,為什么要控制并發(fā)?
控制其爬取頻率,以免沒(méi)爬幾個(gè)就網(wǎng)站被封IP了。
控制爬蟲(chóng)應(yīng)用運(yùn)行內(nèi)存,不控制并發(fā)的話一下子處理N個(gè)請(qǐng)求,內(nèi)存分分鐘爆炸。
實(shí)現(xiàn)并發(fā)控制可以使用npm包 async.mapLimit,這里為了自由度更大我使用了自己實(shí)現(xiàn)的 15 行代碼實(shí)現(xiàn)并發(fā)控制。
具體代碼如下:
let ids = [2213545,5332233, ...], // 招聘崗位詳情id列表 limit = 10, // 并發(fā)數(shù) runningRequestNum = 0 , // 當(dāng)前并發(fā)數(shù) count = 0; // 累計(jì)爬取數(shù)據(jù)項(xiàng)計(jì)數(shù) 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(`當(dāng)前并發(fā)數(shù)`, runningRequestNum) runningRequestNum-- return result; }).then(mapResult => { // 并發(fā)控制下將 ids 全部迭代完畢 // do something })
然而,即便嚴(yán)格控制了請(qǐng)求頻率,我們還是不可避免地中招了。
對(duì)于反爬蟲(chóng)措施比較暴躁的網(wǎng)站來(lái)說(shuō),一個(gè)IP爬取太過(guò)頻繁,被識(shí)別成機(jī)器爬蟲(chóng)幾乎是不可避免的。
一般來(lái)講,我們最簡(jiǎn)單直接的方法就是:換IP。這個(gè)IP訪問(wèn)頻率太高了被反爬攔截到,換個(gè)IP就行了嘛。
動(dòng)態(tài)IP代理單個(gè)IP爬蟲(chóng)對(duì)于反爬較為嚴(yán)厲的網(wǎng)站是走不通的。那么我們需要用到動(dòng)態(tài)IP池,每次爬取時(shí)從IP池中拉取一個(gè)IP出來(lái)爬數(shù)據(jù)。
道理很簡(jiǎn)單,
1秒內(nèi)1個(gè)IP訪問(wèn)了100個(gè)頁(yè)面,即便是單身20多年的手速也無(wú)法企及。只能是機(jī)器爬蟲(chóng)無(wú)疑。
但1秒內(nèi)100個(gè)IP訪問(wèn)100個(gè)頁(yè)面,平均每個(gè)IP一秒內(nèi)訪問(wèn)了1個(gè)頁(yè)面,那基本不會(huì)被反爬干掉
怎么搭建動(dòng)態(tài)IP池?
首先我們得有一個(gè)IP源,動(dòng)態(tài)IP池的補(bǔ)充都從這里拉取,這個(gè)網(wǎng)上搜一下"免費(fèi)代理IP"就有很多出來(lái),選其中一個(gè),收費(fèi)的IP源比較穩(wěn)定可靠,免費(fèi)的就一分錢一分貨了。
其次,每次從IP源中拉取的IP都是無(wú)法確認(rèn)其是否可用的,我們必須篩選一遍,提取出可用的IP。(PS: 此處和步驟4目的一直,如果IP源較為可靠,可以省略)
設(shè)計(jì)從IP池中拉取單個(gè)IP的策略,使得每個(gè)IP使用頻率均勻,盡量避免單個(gè)IP使用頻率過(guò)高而失效。
移除失效IP。盡管設(shè)計(jì)了拉取策略,但依舊不可避免某些IP失效,此時(shí)需要將其移出IP池廢棄。
動(dòng)態(tài)IP池工作流程:
st=>start: 提取一個(gè)可用IP e=>end: 根據(jù)策略返回一個(gè)可用IP isEnought=>condition: 池中IP數(shù)量是否足夠 fetch=>operation: 從IP源拉取IP valid=>operation: 篩選出有效IP并存入IP池 st->isEnought(yes)->e isEnought(no,right)->fetch(right)->valid(right)->isEnought
具體實(shí)現(xiàn)代碼其實(shí)和上面的爬蟲(chóng)差不多,無(wú)非就是爬崗位變成了爬IP而已,具體實(shí)現(xiàn)源碼在這,就不在這寫了。
數(shù)據(jù)可視化分析我們最終折騰爬蟲(chóng),無(wú)非就是想要看爬到的數(shù)據(jù)到底說(shuō)明了什么。
成功爬取了拉鉤網(wǎng)上多個(gè)招聘崗位的具體信息后,數(shù)據(jù)可視化并得出分析結(jié)果如下:
從整體看,北上廣深杭這五個(gè)城市前端工程師招聘崗位,北京是遙遙領(lǐng)先,是深圳的兩倍,是廣州的三倍,其次到上海,深圳,杭州,廣州居末。
從需求量大概可以看出,整體互聯(lián)網(wǎng)產(chǎn)業(yè)發(fā)達(dá)程度是 北 > 上 > 深 > 杭 > 廣
由平均工資曲線圖可以看到,每隔2K算一檔的話,北京一檔,上海一檔,杭州深圳一檔,空一檔,廣州吊車尾,杭州竟然比深圳高了300,這就代表著深圳雖然招聘需求比杭州大,但兩者薪酬待遇其實(shí)差不多。
從不同薪酬的招聘數(shù)量也能看出一些很大的區(qū)別,招聘提供薪資水平中,普遍數(shù)量最多的是10k-20k這個(gè)水平,但,北京牛逼,招聘崗位60%以上都是20K以上的。我們具體來(lái)看看,各個(gè)城市對(duì)高端人才(提供薪酬20k以上)的招聘比例,那就可以看出明顯區(qū)別了:
北京:招聘的薪資水平是"20k以上",大概是招聘總數(shù)的59.7%
上海:招聘的薪資水平是"20k以上",大概是招聘總數(shù)的41.3%
深圳:招聘的薪資水平是"20k以上",大概是招聘總數(shù)的29.2%
杭州:招聘的薪資水平是"20k以上",大概是招聘總數(shù)的30.4%,和深圳相差不大
廣州:招聘的薪資水平是"20k以上",大概是招聘總數(shù)的……10.4%。
基本可以看到一個(gè)明顯的趨勢(shì),公司規(guī)模越大,能提供的薪酬越高,不差錢。
另外,從不同規(guī)模的公司的前端招聘數(shù)量來(lái)看,北京又一枝獨(dú)秀,大公司招聘需求很高。
但從全國(guó)來(lái)看,不同規(guī)模的公司(除了15人以下的)招聘數(shù)量基本在同一水平,基本說(shuō)明:大公司少,但是每個(gè)公司招聘的人多;小公司多,但是每個(gè)公司招聘的人少。好像這是句廢話。
從圖上看,工作經(jīng)歷在1-5年的現(xiàn)在需求最旺盛,并且理所當(dāng)然地,工作資歷越高,薪資越高。
其中3-5年的最吃香,廣州有點(diǎn)奇怪,1-3年的最吃香?綜合上面的多項(xiàng)數(shù)據(jù),感覺(jué)像是1-3年工資比3-5年低所以廣州互聯(lián)網(wǎng)公司多招1-3年
當(dāng)然,這里存在這一個(gè)幸存者偏差,拉勾上大部分的都是社招性質(zhì)的招聘,而應(yīng)屆生和1年經(jīng)驗(yàn)的大部分都跑校招去了吧,所以數(shù)量低也不出奇。
移動(dòng)互聯(lián)網(wǎng)占據(jù)了大半壁江山,剩下之中,金融,電子商務(wù),企業(yè)服務(wù),數(shù)據(jù)服務(wù)在同一層次。另外,物聯(lián)網(wǎng),智能硬件各有一招聘崗位,薪酬都是5K...嗯雖說(shuō)node現(xiàn)在也可以做物聯(lián)網(wǎng)了(還別說(shuō),我還真的用node搞過(guò)硬件串口通信Orz),但是終究不是主流技術(shù),數(shù)據(jù)展示表明,前端基本與硬件絕緣。
薪酬待遇倒是都在同一水平上,“大數(shù)據(jù)”工資倒是一枝獨(dú)秀,但是數(shù)據(jù)量太少,參考價(jià)值不大。
總結(jié):北京錢多機(jī)會(huì)多當(dāng)之無(wú)愧第一檔;上海稍遜一籌;杭州深圳又低一籌;廣州真的是差了兩個(gè)身位。 而對(duì)于前端來(lái)說(shuō),北京 移動(dòng)互聯(lián)網(wǎng) 大公司,錢多!坑多!速來(lái)!
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.specialneedsforspecialkids.com/yun/93896.html
摘要:實(shí)際上,前程無(wú)憂招聘網(wǎng)站上與數(shù)據(jù)有關(guān)的只有幾百頁(yè),而我們爬取了頁(yè)的所有數(shù)據(jù),因此在后面進(jìn)行數(shù)據(jù)處理時(shí)需要把無(wú)關(guān)的數(shù)據(jù)剔除掉。 目錄 一、項(xiàng)目背景 二、數(shù)據(jù)爬取 1、相關(guān)庫(kù)的導(dǎo)入與說(shuō)明 2、獲取二級(jí)頁(yè)面鏈接 1)分析一級(jí)頁(yè)面url特征 2)構(gòu)建一級(jí)url庫(kù) 3)爬取所有二級(jí)url鏈接 3、獲取...
摘要:因?yàn)楸救嗽诔啥紡氖虑岸耍赃@次爬取的關(guān)鍵詞既是成都,前端。僅僅有這個(gè)是不夠的,因?yàn)槊菜评淳W(wǎng)有反爬蟲(chóng),沒(méi)有好像得不到數(shù)據(jù)這個(gè)還待論證,至少我這邊是。 前言 showImg(https://segmentfault.com/img/bV1g4S?w=700&h=490); 今天是2018的第一天,首先祝各位小伙伴元旦快樂(lè)!又到了新的一年,雖然離春節(jié)還有一段時(shí)間,但是程序狗打工不易啊,不...
摘要:因?yàn)楸救嗽诔啥紡氖虑岸耍赃@次爬取的關(guān)鍵詞既是成都,前端。僅僅有這個(gè)是不夠的,因?yàn)槊菜评淳W(wǎng)有反爬蟲(chóng),沒(méi)有好像得不到數(shù)據(jù)這個(gè)還待論證,至少我這邊是。 前言 showImg(https://segmentfault.com/img/bV1g4S?w=700&h=490); 今天是2018的第一天,首先祝各位小伙伴元旦快樂(lè)!又到了新的一年,雖然離春節(jié)還有一段時(shí)間,但是程序狗打工不易啊,不...
摘要:最近在研究區(qū)塊鏈,閑來(lái)無(wú)事抓取了拉勾網(wǎng)上條區(qū)塊鏈相關(guān)的招聘信息。拉勾網(wǎng)的反爬蟲(chóng)做的還是比較好的,畢竟自己也知道這種做招聘信息聚合的網(wǎng)站很容易被爬,而且比起妹子圖這種網(wǎng)站,開(kāi)發(fā)的技術(shù)水平應(yīng)該高不少。 最近在研究區(qū)塊鏈,閑來(lái)無(wú)事抓取了拉勾網(wǎng)上450條區(qū)塊鏈相關(guān)的招聘信息。過(guò)程及結(jié)果如下。 拉勾網(wǎng)爬取 首先是從拉勾網(wǎng)爬取數(shù)據(jù),用的requests庫(kù)。拉勾網(wǎng)的反爬蟲(chóng)做的還是比較好的,畢竟自己也...
摘要:智聯(lián)其實(shí)一共寫了兩次,有興趣的可以在源碼看看,第一版的是回調(diào)版,只能一次一頁(yè)的爬取。 寫在前面的話, .......還是不寫了,直接上效果圖。附上源碼地址 github.lonhon showImg(https://segmentfault.com/img/bVUM3F?w=714&h=543);showImg(https://segmentfault.com/img/bVUM...
閱讀 5289·2021-09-22 15:59
閱讀 1867·2021-08-23 09:42
閱讀 2570·2019-08-29 18:42
閱讀 3453·2019-08-29 10:55
閱讀 2067·2019-08-27 10:57
閱讀 1764·2019-08-26 18:27
閱讀 2729·2019-08-23 18:26
閱讀 2926·2019-08-23 14:40