基于拉勾网的深圳数据分析职位分析
基于拉勾网的深圳数据分析职位分析
一、选题的背景
随着毕业生人数的上涨,如何及时获取有效就业信息并加以分析做出相应决策对于大学生而言显得尤为重要。传统的搜索招聘网站、各单位官网、人力资源网等,可以获得海量的就业信息,然而这种方式都需要到相应网站翻页查找,在不同网站之间切换,耗时、速度慢、不及时、不利于集中分析统计等缺点,导致大学生容易错过适合的岗位信息。针对这种情况,提出了基于网络爬虫的就业数据分析,为大学生搜索分析就业信息提供一定的参考价值。
二、主题式网络爬虫设计方案
1.主题式网络爬虫名称:
基于拉勾网的深圳数据分析职位分析
主题式网络爬虫爬取的内容与数据特征分析:
以拉勾网作为实例,对如何开发爬虫获取信息,及对获取的信息快速分析进行了深入探讨与研究。
2.
主题式网络爬虫设计方案概述(包括实现思路与技术难点):
网络爬虫程序的开发是否成功取决于确保系统能够实现用户定制功能,达到预期设计目的。因此,在网络爬虫程序设计之前,就需要对该程序需求加以详细的分析,从而对整体的设计有一个清晰的思路。时下,普遍适用的爬虫程序都是模块化的,模块化的程序设计有利于代码块的测试与维护,而且也进一步增加了代码的适用性。在此基础上,只要对各个模块进行组合,就能够构建出一个完整的爬虫程序。
因为研究旨在通过爬虫程序对当前就业进行分析,所以需要通过编写爬虫程序抓取相关岗位的就业信息,获取的信息包括公司名称、公司规模、招聘岗位、公司福利、工作地址、薪资水平、工作经验、职位类型、学历要求、发布日期等,并将抓取的就业信息保存在数据库中,以便后期进行数据处理和可视化分析。
爬虫系统的设计思路:首先,需要获得所有包括岗位信息网页的源码;其次,在每一页的网页源码中寻找出与需求相匹配的信息,此时就需要连接爬虫系统和数据库,将每次成功匹配到的信息均存入数据库中,直至所有网页检索完毕。
三,结构特征分析
1,结构与特征分析
2,Htmls页面解析
四,程序设计
1,数据爬取与采集
import numpy as np import pandas as pd import seaborn as sns import jieba import jieba.analyse import re from wordcloud import WordCloud from matplotlib import pyplot as plt from matplotlib import style style.use('ggplot') # from matplotlib.font_manager import FontProperties import pprint # 让图表直接在jupyter中展示出来 %matplotlib inline # 解决中文乱码问题 plt.rcParams["font.sans-serif"] = 'SimHei' # 解决负号无法正常显示问题 plt.rcParams['axes.unicode_minus'] = False # import matplotlib as mpl # 关闭警告信息 import warnings warnings.filterwarnings('ignore') data = pd.read_csv('./lagou_DT.csv') data.head()
data.info()
data.describe()
2,对数据进行清洗和处理
不同区域数据分析师职位的需求情况
1 plt.figure(figsize = (8,6)) 2 data['address'].value_counts().sort_values(ascending=False).plot.bar(width = 0.8,color = 'steelblue') 3 plt.ylabel('职位数量') 4 plt.xlabel('区域') 5 plt.title('不同区域的职位分布') 6 plt.grid(False)
plt.figure(figsize = (8,6)) data['address'].value_counts().sort_values(ascending = False).plot.bar(width = 0.8,color = 'blue') plt.xlabel('区域') plt.ylabel('职位数量') plt.title('不同区域数据分析师职位数量') plt.grid(False)
不同行业数据分析师岗位的需求情况
# 存在多个行业,只取第一个 clean_foursquare = [str(i.split(',')[0]) for i in data.foursquare] data['foursquare'] = clean_foursquare plt.figure(figsize = (8,6)) data['foursquare'].value_counts().sort_values(ascending = True).plot.barh(width = 0.8,color = 'red') plt.xlabel('职位数量') plt.ylabel('职位名称') plt.title('不同行业数据分析师职位数量') plt.grid(False)
数据分析师对应聘者工作年限的要求
plt.figure(figsize = (8,6)) data['experience'].value_counts().plot.barh(width = 0.6,color = 'orange') plt.xlabel('职位数量') plt.ylabel('工作经验') plt.title('数据分析对求职者工作经验的要求',loc = "center") plt.grid(False)
数据分析师对应聘者工作年限的要求
plt.figure(figsize = (8,6)) data['experience'].value_counts().plot.barh(width = 0.6,color = 'orange') plt.xlabel('职位数量') plt.ylabel('工作经验') plt.title('数据分析对求职者工作经验的要求',loc = "center") plt.grid(False)
数据分析师对求职者学历的要求
education_count = data['education'].value_counts() labels='本科及以上','学历不限','硕士及以上','大专及以上' colors=[ 'lightskyblue', 'gold','yellowgreen', 'lightcoral'] explode=(0.1,0.1,0.1,0.1) plt.axis('equal') plt.title('数据分析师对求职者学历的要求',size = 15) plt.pie(education_count,explode=explode,labels=labels,colors=colors,autopct='%1.1f%%', shadow=True,labeldistance=1.1,startangle=60,radius=1.2)
数据分析师的薪酬范围分布
# 去除字段中'k'或'K'字符 clean_salary = [re.sub('[k|K]','',i) for i in data.salary] # 将salary数据转换为DataFrame格式 salary = pd.DataFrame(clean_salary,columns = ['salary']) salary_s = pd.DataFrame((x.split('-') for x in salary['salary']),columns = ['bottomSalary','topSalary']) # 更改字段格式 salary_s['bottomSalary']=salary_s['bottomSalary'].astype(np.int) salary_s['topSalary']=salary_s['topSalary'].astype(np.int) # 计算平均值 salary_avg = [(salary_s['bottomSalary'][i] + salary_s['topSalary'][i])/2 for i in range(len(salary_s))] salary_s['avgSalary'] = salary_avg # for i in range(len(salary_s)): # avg.append((salary_s['bottomSalary'][i]+salary_s['topSalary'][i])/2) # salary_s['avgSalary']=avg # 将salary_s表与原表进行拼接 data = pd.merge(data,salary_s,right_index=True,left_index=True) data.head()
plt.figure(figsize = (8,6)) plt.hist(data['avgSalary'],bins=16,color='green') plt.axis('tight') plt.title('薪酬分布') plt.xlabel('每月薪酬(单位:K/月)') plt.ylabel('职位数量') plt.grid(False)
公司规模与薪酬之间的关系
data['figure'] = data['figure'].map(str.strip) data.groupby(['figure']).count() size1=data.loc[data['figure'] == '15-50人',['figure','avgSalary']] size2=data.loc[data['figure'] == '50-150人',['figure','avgSalary']] size3=data.loc[data['figure'] == '150-500人',['figure','avgSalary']] size4=data.loc[data['figure'] == '500-2000人',['figure','avgSalary']] size5=data.loc[data['figure'] == '2000人以上',['figure','avgSalary']] plt.figure(figsize = (20,8)) plt.xlabel('公司规模') plt.ylabel('平均薪酬(K/月)') plt.title('公司规模与平均薪酬') plt.grid(False) plt.boxplot((size1['avgSalary'],size2['avgSalary'],size3['avgSalary'],size4['avgSalary'],size5['avgSalary']), labels=('15-50人','50-150人','150-500人','500-2000人','2000人以上')) # plt.grid(color='#95a5a6',linestyle='--',linewidth=0.8,axis='y',alpha=0.4)
工作经验与薪酬的关系
data['experience'] = data['experience'].map(str.strip) # 把经验应届毕业生和经验不限归为经验1年以下 for i in range(len(data['experience'])): if data['experience'][i] in ['经验应届毕业生','经验不限']: data['experience'][i]='经验1年以下' # data['experience'] year1=data.loc[data['experience'] == '经验1年以下',['experience','avgSalary']] year2=data.loc[data['experience'] == '经验1-3年',['experience','avgSalary']] year3=data.loc[data['experience'] == '经验3-5年',['experience','avgSalary']] year4=data.loc[data['experience'] == '经验5-10年',['experience','avgSalary']] plt.figure(figsize = (20,8)) plt.xlabel('工作年限') plt.ylabel('薪酬(K/月)') plt.title('工作年限与平均薪酬') plt.grid(False) # plt.grid(color='#95a5a6',linestyle='--',linewidth=0.8,axis='y',alpha=0.4) plt.boxplot((year1['avgSalary'],year2['avgSalary'],year3['avgSalary'],year4['avgSalary']), labels=('经验1年以下','经验1-3年','经验3-5年','经验5-10年'))
学历对薪酬的影响
data['education']=data['education'].map(str.strip) edu1=data.loc[data['education'] == '学历不限',['education','avgSalary']] edu2=data.loc[data['education'] == '大专及以上',['education','avgSalary']] edu3=data.loc[data['education'] == '本科及以上',['education','avgSalary']] edu4=data.loc[data['education'] == '硕士及以上',['education','avgSalary']] plt.figure(figsize = (20,8)) plt.xlabel('学历') plt.ylabel('薪酬(K/月)') plt.title('学历与平均薪酬') plt.grid(False) # plt.grid(color='#95a5a6',linestyle='--',linewidth=0.8,axis='y',alpha=0.4) plt.boxplot((edu1['avgSalary'],edu2['avgSalary'],edu3['avgSalary'],edu4['avgSalary']),labels=('学历不限','大专及以上','本科及以上','硕士及以上'))
职业技能关键词
# 把每个岗位描述连接起来保存在文件中 description_text = ' '.join([i for i in data['description']]) with open('des.txt','w',encoding = 'utf-8') as f: f.write(description_text) f.close() text = open('des.txt', 'r',encoding='utf-8').read() stop_word = ['岗位职责','任职要求','工作职责','岗位要求','任职资格','本科及以上学历','本科以上学历','职位描述', '工作职责','岗位职责1','职位诱惑','职位要求','任职要求1','工作职责1','职位职责','计算机','数据分析', 'and','to','with','the','in','for','of'] wordcloud = WordCloud(font_path="./SimHei.ttf", stopwords=stop_word, # 去掉停用词 max_words=100, width=2000, height=1200).generate(text) # 保存词云 wordcloud.to_file('DT.jpg') # 显示词云文件 plt.imshow(wordcloud) plt.axis("off") plt.show()
完整代码:
1 import numpy as np 2 import pandas as pd 3 import seaborn as sns 4 import jieba 5 import jieba.analyse 6 import re 7 from wordcloud import WordCloud 8 from matplotlib import pyplot as plt 9 from matplotlib import style 10 style.use('ggplot') 11 # from matplotlib.font_manager import FontProperties 12 import pprint 13 # 让图表直接在jupyter中展示出来 14 %matplotlib inline 15 # 解决中文乱码问题 16 plt.rcParams["font.sans-serif"] = 'SimHei' 17 # 解决负号无法正常显示问题 18 plt.rcParams['axes.unicode_minus'] = False 19 # import matplotlib as mpl 20 # 关闭警告信息 21 import warnings 22 warnings.filterwarnings('ignore') 23 24 25 data = pd.read_csv('./lagou_DT.csv') 26 27 28 29 data.head() 30 31 32 data.info() 33 34 35 data.describe() 36 37 38 39 plt.figure(figsize = (8,6)) 40 data['address'].value_counts().sort_values(ascending=False).plot.bar(width = 0.8,color = 'steelblue') 41 plt.ylabel('职位数量') 42 plt.xlabel('区域') 43 plt.title('不同区域的职位分布') 44 plt.grid(False) 45 46 47 48 plt.figure(figsize = (8,6)) 49 data['address'].value_counts().sort_values(ascending = False).plot.bar(width = 0.8,color = 'blue') 50 plt.xlabel('区域') 51 plt.ylabel('职位数量') 52 plt.title('不同区域数据分析师职位数量') 53 plt.grid(False) 54 55 56 57 58 # 存在多个行业,只取第一个 59 clean_foursquare = [str(i.split(',')[0]) for i in data.foursquare] 60 data['foursquare'] = clean_foursquare 61 62 63 64 65 plt.figure(figsize = (8,6)) 66 data['foursquare'].value_counts().sort_values(ascending = True).plot.barh(width = 0.8,color = 'red') 67 plt.xlabel('职位数量') 68 plt.ylabel('职位名称') 69 plt.title('不同行业数据分析师职位数量') 70 plt.grid(False) 71 72 73 74 75 76 plt.figure(figsize = (8,6)) 77 data['experience'].value_counts().plot.barh(width = 0.6,color = 'orange') 78 plt.xlabel('职位数量') 79 plt.ylabel('工作经验') 80 plt.title('数据分析对求职者工作经验的要求',loc = "center") 81 plt.grid(False) 82 83 84 85 86 education_count = data['education'].value_counts() 87 labels='本科及以上','学历不限','硕士及以上','大专及以上' 88 colors=[ 'lightskyblue', 'gold','yellowgreen', 'lightcoral'] 89 explode=(0.1,0.1,0.1,0.1) 90 plt.axis('equal') 91 plt.title('数据分析师对求职者学历的要求',size = 15) 92 plt.pie(education_count,explode=explode,labels=labels,colors=colors,autopct='%1.1f%%', 93 shadow=True,labeldistance=1.1,startangle=60,radius=1.2) 94 95 96 97 98 99 # 去除字段中'k'或'K'字符 100 clean_salary = [re.sub('[k|K]','',i) for i in data.salary] 101 102 103 104 105 # 将salary数据转换为DataFrame格式 106 salary = pd.DataFrame(clean_salary,columns = ['salary']) 107 salary_s = pd.DataFrame((x.split('-') for x in salary['salary']),columns = ['bottomSalary','topSalary']) 108 # 更改字段格式 109 salary_s['bottomSalary']=salary_s['bottomSalary'].astype(np.int) 110 salary_s['topSalary']=salary_s['topSalary'].astype(np.int) 111 112 113 114 # 计算平均值 115 salary_avg = [(salary_s['bottomSalary'][i] + salary_s['topSalary'][i])/2 for i in range(len(salary_s))] 116 salary_s['avgSalary'] = salary_avg 117 # for i in range(len(salary_s)): 118 # avg.append((salary_s['bottomSalary'][i]+salary_s['topSalary'][i])/2) 119 # salary_s['avgSalary']=avg 120 121 122 123 # 将salary_s表与原表进行拼接 124 data = pd.merge(data,salary_s,right_index=True,left_index=True) 125 data.head() 126 127 128 129 130 plt.figure(figsize = (8,6)) 131 plt.hist(data['avgSalary'],bins=16,color='green') 132 plt.axis('tight') 133 plt.title('薪酬分布') 134 plt.xlabel('每月薪酬(单位:K/月)') 135 plt.ylabel('职位数量') 136 plt.grid(False) 137 138 139 140 data['figure'] = data['figure'].map(str.strip) 141 data.groupby(['figure']).count() 142 143 144 145 146 size1=data.loc[data['figure'] == '15-50人',['figure','avgSalary']] 147 size2=data.loc[data['figure'] == '50-150人',['figure','avgSalary']] 148 size3=data.loc[data['figure'] == '150-500人',['figure','avgSalary']] 149 size4=data.loc[data['figure'] == '500-2000人',['figure','avgSalary']] 150 size5=data.loc[data['figure'] == '2000人以上',['figure','avgSalary']] 151 152 153 154 plt.figure(figsize = (20,8)) 155 plt.xlabel('公司规模') 156 plt.ylabel('平均薪酬(K/月)') 157 plt.title('公司规模与平均薪酬') 158 plt.grid(False) 159 plt.boxplot((size1['avgSalary'],size2['avgSalary'],size3['avgSalary'],size4['avgSalary'],size5['avgSalary']), 160 labels=('15-50人','50-150人','150-500人','500-2000人','2000人以上')) 161 # plt.grid(color='#95a5a6',linestyle='--',linewidth=0.8,axis='y',alpha=0.4) 162 163 164 165 data['experience'] = data['experience'].map(str.strip) 166 167 168 169 170 171 172 # 把经验应届毕业生和经验不限归为经验1年以下 173 for i in range(len(data['experience'])): 174 if data['experience'][i] in ['经验应届毕业生','经验不限']: 175 data['experience'][i]='经验1年以下' 176 # data['experience'] 177 178 179 180 181 year1=data.loc[data['experience'] == '经验1年以下',['experience','avgSalary']] 182 year2=data.loc[data['experience'] == '经验1-3年',['experience','avgSalary']] 183 year3=data.loc[data['experience'] == '经验3-5年',['experience','avgSalary']] 184 year4=data.loc[data['experience'] == '经验5-10年',['experience','avgSalary']] 185 186 187 188 189 plt.figure(figsize = (20,8)) 190 plt.xlabel('工作年限') 191 plt.ylabel('薪酬(K/月)') 192 plt.title('工作年限与平均薪酬') 193 plt.grid(False) 194 # plt.grid(color='#95a5a6',linestyle='--',linewidth=0.8,axis='y',alpha=0.4) 195 plt.boxplot((year1['avgSalary'],year2['avgSalary'],year3['avgSalary'],year4['avgSalary']), 196 labels=('经验1年以下','经验1-3年','经验3-5年','经验5-10年')) 197 198 199 200 201 data['education']=data['education'].map(str.strip) 202 203 204 205 edu1=data.loc[data['education'] == '学历不限',['education','avgSalary']] 206 edu2=data.loc[data['education'] == '大专及以上',['education','avgSalary']] 207 edu3=data.loc[data['education'] == '本科及以上',['education','avgSalary']] 208 edu4=data.loc[data['education'] == '硕士及以上',['education','avgSalary']] 209 210 211 212 213 plt.figure(figsize = (20,8)) 214 plt.xlabel('学历') 215 plt.ylabel('薪酬(K/月)') 216 plt.title('学历与平均薪酬') 217 plt.grid(False) 218 # plt.grid(color='#95a5a6',linestyle='--',linewidth=0.8,axis='y',alpha=0.4) 219 plt.boxplot((edu1['avgSalary'],edu2['avgSalary'],edu3['avgSalary'],edu4['avgSalary']),labels=('学历不限','大专及以上','本科及以上','硕士及以上')) 220 221 222 223 224 225 # 把每个岗位描述连接起来保存在文件中 226 description_text = ' '.join([i for i in data['description']]) 227 228 with open('des.txt','w',encoding = 'utf-8') as f: 229 f.write(description_text) 230 f.close() 231 232 233 234 235 236 text = open('des.txt', 'r',encoding='utf-8').read() 237 stop_word = ['岗位职责','任职要求','工作职责','岗位要求','任职资格','本科及以上学历','本科以上学历','职位描述', 238 '工作职责','岗位职责1','职位诱惑','职位要求','任职要求1','工作职责1','职位职责','计算机','数据分析', 239 'and','to','with','the','in','for','of'] 240 wordcloud = WordCloud(font_path="./SimHei.ttf", 241 stopwords=stop_word, # 去掉停用词 242 max_words=100, 243 width=2000, 244 height=1200).generate(text) 245 # 保存词云 246 wordcloud.to_file('DT.jpg') 247 # 显示词云文件 248 plt.imshow(wordcloud) 249 plt.axis("off") 250 plt.show()
五,总结
通过上面的分析,可以得到如下结论:
1,在深圳数据分析师岗位需求主要集中在南山、福田,即互联网聚集地,总体待遇较高(基本上在8K以上),学历要求不是特别高(本科以上),大厂需求量较大,大量的工作经验需求集中在1-3年。
2,数据分析师分布的行业领域主要是移动互联网行业,不过也开始向传统行业(例如金融、教育)渗透。
3,数据分析师技能具备的频率排在前列的有:SQL,Python,数学统计,对数据敏感,Excel, SAS,SPSS, Hadoop,机器学习等,其中数学统计、SQL、Python、Excel是必备技能。
4,机器学习、大数据挖掘是走向高薪的正确方向。
在整个设计的过程中,我学到了很多新知识,增长了见识。我想这是一次意志的磨练,是对我实际能力的一次提升,也会对我未来的学习和工作有很大的帮助。需要改进的建议在于该网络爬虫程序只获取了单个网站的就业信息,下一步的重点应该放在如何进行多数据源的就业信息获取,以获得更加全面的就业信息。