综述
上一篇我们通过node + cheerio爬取了猎聘网上近4000条关于前端开发岗的招聘信息,在这一篇呢,我们对这些信息做一个数据分析与统计,一起看看吧。
想要源代码的,这里有整个项目的Github入口:Github入口
上一篇——数据采集篇的入口
这些是我们爬取到的数据,可以看到数据中有薪酬,有学历要求,也有招聘的岗位是初中高级还是资深或专家,同时也有关于招聘公司,工作地点等等,我们就从这些不同的维度对这3960条数据进行分析。
第一,先来看看岗位工作地点的地区分布。
// 地区分布分析
areaAnalysis () {
let area = this.data.map(item => item.area),
_self = this;
area.forEach(item => {
let flag = true;
for(let i in _self.areaMap) {
item.indexOf(i) > -1 ? (_self.areaMap[i] ++, flag = false) : null;
}
flag && _self.areaMap['其他'] ++;
});
}
加一点修饰,比如用一下我们最常见的echart.js来将我们这些数据做可视化。
可以看到岗位工作地点北上广深杭占了近80%,其中北京和上海的前端岗均占比超20%。
第二,再来看看学历要求。
// 学历要求分析
eduAnalysis () {
let edu = this.data.map(item => item.experience),
_self = this;
edu.forEach(item => {
let flag = true;
for(let i in _self.eduMap) {
if(item.indexOf(i) > -1) {
_self.eduMap[i] ++;
flag = false;
break;
}
}
flag && _self.eduMap['其他'] ++;
});
}
最低学历要求超75%是本科,所以高考不管怎样,最好是能到本科,清华也是本科,当然,大专要求的占比也有接近17%,也不算特别低,大专的同学机会也还好,技术水平是关键。
第三,再来看看薪酬水平。
// 薪酬水平分析
rewardAnalysis () {
let _self = this;
let reward = this.data.map(item => {
if(item.reward.indexOf('万') > -1) {
let average = item.reward.replace('万','').split('-');
return ( Number(average[0]) + Number(average[0]) ) / 2;
}
return item.reward;
});
let arr = [];
for(let i in _self.rewardMap) {
i !== '面议' && arr.push(i);
}
reward.forEach((item, index) => {
if(typeof item === 'string' && item.indexOf('面议') > -1) _self.rewardMap['面议'] ++;
else if (item >= 100){
_self.rewardMap['100万及以上'] ++;
}
else{
_self.rewardMap[arr[Math.floor(item / 10)]] ++;
}
});
}
看看占比:
可以看到,薪酬水平在10-19万,20-29万的维度占比是最高的,分别达到44.17%和19.95%。而更上一层楼的30+整体占比和也接近15%,当然也有不少比例并未直接列出薪酬而是面议薪酬,看着这个数据,笔者不禁感叹,又拖后腿了。
第四,再来看看前端级别需求。
// 前端级别需求
rankAnalysis () {
let rank = this.data.map(item => item.name),
_self = this;
rank.forEach(item => {
let flag = true;
for(let i in _self.rank) {
i !== '初中级' && item.indexOf(i) > -1 ? (_self.rank[i] ++, flag = false) : null;
}
flag && _self.rank['初中级'] ++;
});
}
看看占比
当然这里的初中级之所以占比这么高,是因为程序的判定就是招聘的信息中未有高级、资深、专家或主管的,自动被归为初中级,实际可能比这个低一些,但高级及以上的人才是目前很多公司急需也很缺少的人才。
第五,再来看看公司的标签。
// 公司标签分析
tagAnalysis () {
let companyTag = this.data.map(item => item.company.tag),
_self = this;
companyTag.forEach(item => {
for(let i in _self.companyTag) {
item.indexOf(i) > -1 ? _self.companyTag[i] ++ : null;
}
});
}
这里列出的标签有:
// 公司标签 - 只按照标签计算,会超过总工作数,初步预估总标签数是总工作数的几倍
companyTag: {
'股票期权': 0,
'带薪年假': 0,
'弹性工作': 0,
'年度旅游': 0,
'节日礼物': 0,
'交通补助': 0,
'五险一金': 0,
'六险一金': 0,
'七险一金': 0,
'团队聚餐': 0,
'定期体检': 0,
'休闲餐点': 0,
'休闲餐点': 0,
'500强': 0,
'外派津贴': 0,
'周末双休': 0,
'免费班车': 0,
'领导好': 0,
'老板NICE': 0,
'扁平管理': 0,
'人性化管理': 0,
'住房补贴': 0,
'年底双薪': 0,
'上市公司': 0,
'公司规模大': 0,
'发展空间大': 0,
'美资企业': 0,
'不加班': 0
},
再来看看这些标签的占比:
五险一金、六险一金、七险一金、老板好、领导NICE,管理人性化、扁平、各种补贴,各种礼物,各种聚餐,各种休假,各种标签琳琅满目,当然其中占比较多的还是诸如发展空间大、带薪年假、五险一金等常规福利。当然也出现了少量的七险一金的标签,当然这部分也是只有大厂才出得起的。
当然值得一提的是,不加班作为一种福利的标签被放在了这里,而占比也是非常的感人——0.02%,再加上之前的996ICU,可见加班是目前互联网乃至软件行业的常态。
最后,再来看看代码吧。
主要的dataAnalysis.js + 一个字典js
import { dataDictionary } from './dataDictionary.js'
export class DataAnalysis {
constructor () {
this.init();
this.all();
}
init () {
// 地区枚举初始化
this.areaMap = dataDictionary.areaMap;
// 学历要求分析
this.eduMap = dataDictionary.eduMap;
// 薪酬水平分析
this.rewardMap = dataDictionary.reward;
// 前端级别需求
this.rank = dataDictionary.rank;
// 公司标签分析
this.companyTag = dataDictionary.companyTag;
}
// 地区分布分析
areaAnalysis () {
let area = this.data.map(item => item.area),
_self = this;
area.forEach(item => {
let flag = true;
for(let i in _self.areaMap) {
item.indexOf(i) > -1 ? (_self.areaMap[i] ++, flag = false) : null;
}
flag && _self.areaMap['其他'] ++;
});
}
// 学历要求分析
eduAnalysis () {
let edu = this.data.map(item => item.experience),
_self = this;
edu.forEach(item => {
let flag = true;
for(let i in _self.eduMap) {
if(item.indexOf(i) > -1) {
_self.eduMap[i] ++;
flag = false;
break;
}
}
flag && _self.eduMap['其他'] ++;
});
}
// 薪酬水平分析
rewardAnalysis () {
let _self = this;
let reward = this.data.map(item => {
if(item.reward.indexOf('万') > -1) {
let average = item.reward.replace('万','').split('-');
return ( Number(average[0]) + Number(average[0]) ) / 2;
}
return item.reward;
});
let arr = [];
for(let i in _self.rewardMap) {
i !== '面议' && arr.push(i);
}
reward.forEach((item, index) => {
if(typeof item === 'string' && item.indexOf('面议') > -1) _self.rewardMap['面议'] ++;
else if (item >= 100){
_self.rewardMap['100万及以上'] ++;
}
else{
_self.rewardMap[arr[Math.floor(item / 10)]] ++;
}
});
}
// 前端级别需求
rankAnalysis () {
let rank = this.data.map(item => item.name),
_self = this;
rank.forEach(item => {
let flag = true;
for(let i in _self.rank) {
i !== '初中级' && item.indexOf(i) > -1 ? (_self.rank[i] ++, flag = false) : null;
}
flag && _self.rank['初中级'] ++;
});
}
// 公司标签分析
tagAnalysis () {
let companyTag = this.data.map(item => item.company.tag),
_self = this;
companyTag.forEach(item => {
for(let i in _self.companyTag) {
item.indexOf(i) > -1 ? _self.companyTag[i] ++ : null;
}
});
}
all () {
let _self = this;
fetch('./cache/jobs.txt')
.then(res => res.json())
.then(data => {
_self.data = data;
// 地区分布分析
this.areaAnalysis();
// 学历要求分析
this.eduAnalysis();
// 前端级别需求
this.rankAnalysis();
// 公司标签分析
this.tagAnalysis();
// 薪酬水平分析
this.rewardAnalysis();
});
}
}
再看看页面:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>爬虫测试</title>
<style>
html, body, div, p, h1, h2, h3{
margin: 0;
padding: 0;
}
body{
background-color: rgb(235, 240, 247);
}
.pie{
margin: 0 auto;
width: 720px;
height: 600px;
}
.tag{
width: 1200px;
height: 800px;
}
</style>
</head>
<body>
<div class='pie area'></div>
<div class='pie edu'></div>
<div class='tag reward'></div>
<div class='pie rank'></div>
<div class='tag companyTag'></div>
<script src='./dataAnalysis/echarts.min.js'></script>
<script type="module">
import { DataAnalysis } from './dataAnalysis/dataAnalysis.js';
import { PicChart } from './dataAnalysis/picChart.js';
let data = new DataAnalysis();
console.log(data);
setTimeout(function () {
new PicChart(JSON.parse(JSON.stringify(data.areaMap)), '.area', 'areaMap');
new PicChart(JSON.parse(JSON.stringify(data.eduMap)), '.edu', 'eduMap');
new PicChart(JSON.parse(JSON.stringify(data.rewardMap)), '.reward', 'rewardMap');
new PicChart(JSON.parse(JSON.stringify(data.rank)), '.rank', 'rank');
new PicChart(JSON.parse(JSON.stringify(data.companyTag)), '.companyTag', 'companyTag');
}, 1000);
</script>
</body>
</html>
基本上初步的分析就到这了,当然爬虫嘛,能实时或定时爬取最新信息,并做分析输出报表,才是上上之选,轮子都造好给你了,这里这部分就留给你去拓展了哈。
热门评论
为什么用vscode 运行 index.html 报错,提示:
Uncaught SyntaxError: Unexpected identifier
dataAnalysis/dataAnalysis.js:1 Failed to load module script: The server responded with a non-JavaScript MIME type of "text/html". Strict MIME type checking is enforced for module scripts per HTML spec.