爬取boss直聘数据并进行分析
1. 爬取boss直聘数据
因为高匿的代理IP要钱,所以小编只能通过增大时间间隔并利用selenium自动化库模拟人自然浏览网站来爬取数据,最终获得北京,上海,杭州,广州,深圳,长沙城市招聘3-5年工作经验的数据分析师,数据挖掘师,数据架构师,Al工程师的信息,保存文件为大数据招聘信息.xls.(最好利用手机热点的ip地址来进行爬取,因为就算封了ip,将手机重启ip地址会改变,可以重复爬取)
from selenium import webdriver #自动打开网页获取以便获取动态的cookie
from bs4 import BeautifulSoup #解析网页为树状结构的模块
import re #使用正则规则查找数据的位置的模块
import xlwt #将数据写入csv文件的模块
import time #防止爬取太过频繁而触动防爬机制的休眠模块
import random #产生随机数模块
#大致要获取北京,上海,杭州,广州,深圳,长沙城市招聘3-5年工作经验的数据分析师,数据挖掘师,数据架构师,人工智能的信息
#定义一个主函数
def main():
#基本的url信息,后面加数字代表页数
baseurl="https://www.zhipin.com/"
#获取自己想要的数据以一个列表的形式展现
datalist=getData(baseurl)
#保存路径
savepath="C:/Users/HUAWEI/Desktop/大数据招聘信息.xls"
#将datalist写入为xls文件
saveData(datalist,savepath)
def askURL(url):
# chromeOptions = webdriver.ChromeOptions()
# # 设置代理 (免费代理几乎都不可用。。。。。。所以学艺不精的我只能卡时间间隔获取)
# chromeOptions.add_argument(getip())
# 一定要注意,=两边不能有空格,不能是这样--proxy-server = http://202.20.16.82:10152
# 实例化一个浏览器对象(传入驱动程序的位置)
bro = webdriver.Chrome(executable_path="C:/Users/HUAWEI/Desktop/chromedriver.exe")
# bro = webdriver.Chrome(executable_path="C:/Users/HUAWEI/Desktop/chromedriver.exe",chrome_options=chromeOptions)
# 让浏览器发起一个指定的请求
bro.get(url)
#获取浏览器源代码数据
html=bro.page_source
#print(type(html))
time.sleep(random.randint(1,10)) #增加访问时间间隔与随机性防止反爬
bro.quit()
return html
#标签的正则表达式
findjop_name=re.compile(r'title="(.*?)".*?</a></span>') #工作名称规则
findjop_income=re.compile(r'<span class="red">(.*?)</span>') #工作收入规则
findjop_education=re.compile(r'<p>3-5年<em class="vline"></em>(.*?)</p>') #工作学历
findjop_skills=re.compile(r'<span class="tag-item">(.*?)</span>') #工作所需技能
findjop_company=re.compile(r'<h3 class="name"><a href=".*?title=".*?>(.*?)</a></h3>') #工作的公司
findjop_area=re.compile(r'<span class="job-area">(.*?)</span>') #工作的地域
#由获取一个页面信息发展到多个页面,并解析网页获取数据
#baseurl="https://www.zhipin.com/"
def getData(baseurl):
# place=["c101010100","c101020100","c101210100","c101280100","c101280600","c101250100"] #url中分别表示北京,上海,杭州,广州,深圳,长沙城市
#work=["%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90","%E6%95%B0%E6%8D%AE%E6%8C%96%E6%8E%98","%E6%95%B0%E6%8D%AE%E6%9E%B6%E6%9E%84","%E4%BA%BA%E5%B7%A5%E6%99%BA%E8%83%BD"] #url中分别表示数据分析师,数据挖掘师,数据架构师,人工智能
# work = ["%E6%95%B0%E6%8D%AE%E6%9E%B6%E6%9E%84","%E4%BA%BA%E5%B7%A5%E6%99%BA%E8%83%BD"] # url中分别表示数据架构师,人工智能,因为一次爬取太少了
place = ["c101210100", "c101280100", "c101280600", "c101250100"] #表示上海,杭州,广州,深圳,长沙城市
work = ["%E4%BA%BA%E5%B7%A5%E6%99%BA%E8%83%BD"] #url为人工智能
#设定空列表储存数据分析师,数据挖掘师,数据架构师,人工智能招聘数据
datalist=[]
# 每次循环得到一次招聘信息以列表的形式保存在datalist中
for i in work:
for j in place:
for k in range(1, 11):
if k == 9:
break # 只爬取8页,因为他只给你爬8页
else:
url = baseurl + j + "/e_105/?query=" + i + "&page=" + str(k)
# print(url)
# break
html = askURL(url)
# 对每次循环的网页进行页面解析,通过正则匹配获取自己想要的数据
# ptint(html)
# break
soup = BeautifulSoup(html, "html.parser")
for item in soup.find_all("div", class_="job-primary"): # 找到你需要分析的源代码大致范围
# print(item)
data = [] # 保存一个招聘的信息
item = str(item)
# 使用正则表达式获取想要的数据标签信息
# 例如工作名称,工作收入,工作学历,工作技能,工作公司,工作区域
# jop_name,jop_income,jop_education,jop_skills,jop_company,jop_area
jop_name = re.findall(findjop_name, item)
data.append(jop_name)
jop_income = re.findall(findjop_income, item)
data.append(jop_income)
jop_education = re.findall(findjop_education, item)
data.append(jop_education)
jop_skills = re.findall(findjop_skills, item)
jop_skills = ",".join(jop_skills)
data.append(jop_skills)
jop_company = re.findall(findjop_company, item)
data.append(jop_company)
jop_area = re.findall(findjop_area, item)
data.append(jop_area)
datalist.append(data) # 每次循环得到一次招聘信息以列表的形式保存在datalist中
return datalist
#getData(baseurl)
#保存数据到xls文件
def saveData(datalist,savepath):
book=xlwt.Workbook(encoding="utf-8",style_compression=0) #创建workbook对象
sheet=book.add_sheet("大数据招聘信息",cell_overwrite_ok=True) #创建工作表cell_overwrite_ok=True,每次循环覆盖前一次表
col=("工作名称","工作收入","工作学历","工作技能","工作公司","工作区域")
for i in range(6):
sheet.write(0,i,col[i])
for i in range(len(datalist)):
data=datalist[i]
for j in range(len(data)):
sheet.write(i+1,j,data[j])
book.save(savepath)
#当运行程序时,运行主函数
if __name__ in "__main__":
main()
因为网站反爬措施做得很好,所以大概爬取了四次才获得的想要的数据,损失不大,只有几百条。下述代码块中注释的部分是手动改变数据信息代码,更小重复的爬取想要的数据。(记得保存文件名也每次改一下)
def getData(baseurl):
# place=["c101010100","c101020100","c101210100","c101280100","c101280600","c101250100"] #url中分别表示北京,上海,杭州,广州,深圳,长沙城市
#work=["%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90","%E6%95%B0%E6%8D%AE%E6%8C%96%E6%8E%98","%E6%95%B0%E6%8D%AE%E6%9E%B6%E6%9E%84","%E4%BA%BA%E5%B7%A5%E6%99%BA%E8%83%BD"] #url中分别表示数据分析师,数据挖掘师,数据架构师,人工智能
# work = ["%E6%95%B0%E6%8D%AE%E6%9E%B6%E6%9E%84","%E4%BA%BA%E5%B7%A5%E6%99%BA%E8%83%BD"] # url中分别表示数据架构师,人工智能,因为一次爬取太少了
place = ["c101210100", "c101280100", "c101280600", "c101250100"] #表示上海,杭州,广州,深圳,长沙城市
work = ["%E4%BA%BA%E5%B7%A5%E6%99%BA%E8%83%BD"] #url为人工智能
2.数据分析
文件的处理就不说了,最后得到文件名为数据分析师招聘信息.csv,数据挖掘师招聘信息.csv,数据架构师招聘信息.csv,Al工程师招聘信息.csv,大数据招聘信息.csv的文件。下述代码是对工作学历与招聘之间关系的分析,在全部分析代码**(请私信小编获取全部代码)**中有很多冗长的地方需要改进,比如我定义了很多画图函数,其实可以合并在一起,需要读者自行摸索,我只是给大家传递一种思路而已。还有请务必使用Jupyter Notebook来执行下例代码,因为分段输出可以让你发现报错的问题,其中有一些全局变量是重复使用,在报错的地方执行之前你保存数据的地方,再执行本行代码就不会报错,比如:data .
import pandas as pd
data_f=pd.read_csv("C:/Users/HUAWEI/Desktop/数据分析师.csv",encoding="gbk")
data_w=pd.read_csv("C:/Users/HUAWEI/Desktop/数据挖掘师.csv",encoding="gbk")
data_j=pd.read_csv("C:/Users/HUAWEI/Desktop/数据架构师.csv",encoding="gbk")
data_AL=pd.read_csv("C:/Users/HUAWEI/Desktop/AL工程师.csv",encoding="gbk")
data=pd.read_csv("C:/Users/HUAWEI/Desktop/大数据招聘信息.csv")
#计算某列元素的频率,并将形成的series变成dataframe
Fre_f=pd.DataFrame(data_f["工作学历"].value_counts())
Fre_w=pd.DataFrame(data_w["工作学历"].value_counts())
Fre_j=pd.DataFrame(data_j["工作学历"].value_counts())
Fre_AL=pd.DataFrame(data_AL["工作学历"].value_counts())
Fre_data=pd.DataFrame(data["工作学历"].value_counts())
#定义一个函数画数学分析师,数据挖掘师,数据架构师,AL工程师的就业与学历关系的直方图和饼图
import matplotlib as mpl
from matplotlib import pyplot as plt
from matplotlib import font_manager
def Bar_1(data,title):
#设置全景中文字体
my_font=font_manager.FontProperties(fname="C:/Windows/Fonts/STXINGKA.TTF")
mpl.rcParams['font.sans-serif'] = my_font.get_name()
mpl.rcParams["axes.unicode_minus"] = False
#画直方图
#定义图片大小
p=plt.figure(figsize=(20,8),dpi=300)
ax=p.add_subplot(1,1,1) #创建一个1行1列的子图,并开始绘制第1幅
#去掉子图的上,右边框
ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)
x=list(data.index)
y=list(data['工作学历'])
plt.bar(range(len(x)),y)
plt.xticks(range(len(x)),x,font=my_font,fontsize=20,color="red")
plt.yticks(font=my_font,fontsize=20,color="#006400")
#定义背景网格线
plt.grid(axis="y",linestyle="--",color="#FFA500",alpha=0.5)
#加上注释()中的属性分别为文本内容,注释坐标,文本坐标
color_list=["#4B0082","#2F4F4F","#32CD32","#808000","#B22222","#808000"]
for i in range(len(y)):
plt.annotate(y[i],xy=(i,y[i]),xytext=(i,y[i]+10),font=my_font,fontsize=15,color=color_list[i])
#加上x,y轴的标签
plt.xlabel("\n学历",font=my_font,fontsize=30)
plt.ylabel("招聘人数\n",font=my_font,fontsize=30)
#加上标题
plt.title(title,font=my_font,fontsize=40,color="#FFD700")
# plt.savefig("C:/Users/HUAWEI/Desktop/大数据就业与学历关系直方图.png")
plt.show()
Bar_1(Fre_f,"数据分析师就业与学历关系")
Bar_1(Fre_w,"数据挖掘师师就业与学历关系")
Bar_1(Fre_j,"数据架构师就业与学历关系")
Bar_1(Fre_AL,"AL工程师就业与学历关系")
Bar_1(Fre_data,"大数据就业与学历关系")
def Bie_1(data,title):
plt.figure(figsize=(10,5),dpi=150) #调节图形大小
x=list(data.index)
y=list(data['工作学历'])
labels = x #定义标签
sizes = y #每块值
colors = ['red','yellowgreen','lightskyblue','yellow','blue'] #每块颜色定义
explode = (0.1,0.05,0.05,0.05,1.2) #将某一块分割出来,值越大分割出的间隙越大
patches,text1,text2 = plt.pie(sizes,
explode=explode,
labels=labels,
colors=colors,
autopct = '%3.2f%%', #数值保留固定小数位
shadow = False, #无阴影设置
startangle =0, #逆时针起始角度设置
pctdistance = 0.6) #数值距圆心半径倍数的距离
#patches饼图的返回值,texts1饼图外label的文本,texts2饼图内部的文本
# x,y轴刻度设置一致,保证饼图为圆形
plt.axis('equal')
#设置图列
my_font1=font_manager.FontProperties(fname="C:/Windows/Fonts/STXINGKA.TTF",size=10)
plt.legend(prop=my_font1)
#设置标题
my_font2=font_manager.FontProperties(fname="C:/Windows/Fonts/STXINGKA.TTF",size=20)
plt.title(title,font=my_font2,color='#32CD32')
plt.show()
Bie_1(Fre_f,"数据分析师就业与学历关系")
Bie_1(Fre_w,"数据挖掘师师就业与学历关系")
Bie_1(Fre_j,"数据架构师就业与学历关系")
def Bie_2(data,title):
plt.figure(figsize=(10,5),dpi=150) #调节图形大小
x=list(data.index)
y=list(data['工作学历'])
labels = x #定义标签
sizes = y #每块值
colors = ['red','yellowgreen','lightskyblue','yellow','blue','DarkGray'] #每块颜色定义
explode = (0.1,0.05,0.05,0.05,1.2,1.6) #将某一块分割出来,值越大分割出的间隙越大
patches,text1,text2 = plt.pie(sizes,
explode=explode,
labels=labels,
colors=colors,
autopct = '%3.2f%%', #数值保留固定小数位
shadow = False, #无阴影设置
startangle =0, #逆时针起始角度设置
pctdistance = 0.6) #数值距圆心半径倍数的距离
#patches饼图的返回值,texts1饼图外label的文本,texts2饼图内部的文本
# x,y轴刻度设置一致,保证饼图为圆形
plt.axis('equal')
#设置图列
my_font1=font_manager.FontProperties(fname="C:/Windows/Fonts/STXINGKA.TTF",size=10)
plt.legend(prop=my_font1)
#设置标题
my_font2=font_manager.FontProperties(fname="C:/Windows/Fonts/STXINGKA.TTF",size=20)
plt.title(title,font=my_font2,color='#32CD32')
plt.show()
Bie_2(Fre_AL,"AL工程师就业与学历关系")
Bie_2(Fre_data,"大数据就业与学历关系")
进入正题,开始进行数据分析!
大数据各个职业方向与学历的关系:
1.就大数据从业大方向而言,招聘要求学历中有71.9%本科学历,13.25%硕士学历,0.55%博士学历,三种学历几乎占据整个招聘市场,其中不难看出由于本科学历基数庞大,从事该行业就业压力相对很大,反之高学历的仅占13.8%,说明大数据行业人才缺口大,学历高有很大的竞争优势。
2.数据分析师,数据架构师招聘学历基本以本科为主,门槛低,AL工程师,数据挖掘师硕士学历比例大大提高,门槛高。
大数据各个职业的TOP10技能要求:
1.就大数据从业而言,要求招聘者掌握数据分析,挖掘能力,懂得深度学习算法,并且熟悉python,SQL软件,可以说是走大数据道路的硬 性要求。
2.数据分析师要求招聘者会一定的数据分析,挖掘能力,并且会使用python,SQL,Excel软件。
数据挖掘师除了要求招聘者会一定的数据分析,挖掘能力,熟悉python软件以外还要懂得深度学习算法,一些企业还要求会使用java,
hadoop,spark,sql。
数据架构师要求招聘者有数据分析,数据架构,大数据能力,熟悉python,java,sql,hadoop,spark软件和分布式技术。
AL工程师要求招聘者对人工智能,视觉图像算法,自然语言处理,产品设计有一定了解,并且熟悉python,c++。
大数据各个职业的平均月收入:
1.就大数据从业方向而已,招聘月均收入1-4w之间的占据整个招聘的78.05%,说明大数据行业有很好的发展前景,工资较高。
2.数据分析师月均工资再1-3w比较集中,中规中矩,高额月工资很少,本次爬取的数据表明数据分析师最高招聘平均月薪不超过8万,再 一次验该行业本科生居多的原因。
3.数据挖掘师大于月均2w的明显增多,中高薪分布较为均匀,大概在4w左右,最高月薪9w左右。
4.数据架构师整体分配均匀,是一个神奇的职业,本科生虽然占据主流,和数学分析师招聘市场差不多,但是数据架构师有不少月薪过10w甚至过20w的(也就是年薪破百万!!),我想应该和学历有很大的关系。
5.AL工程师更不用说了,工资月薪基本2w往上走,高薪居多,最高的也是年薪破百万,和数据架构师最高工资差不多水平,这应该与从事AL行业基本上为硕士学历有莫大的关系吧。
大数据各个职业平均收入之间的比较:
数据挖掘师,数据架构师,AL工程师平均月工资3w左右,而数据分析师平均月工资2.5w左右,别小看这小小的5000k差距,他们可是代表整个职业的平均收入。
上面分析过数据架构师,AL工程师高薪较高,与本图对比发现:
1.这两种职业月工资极差及大,说明大神的存在拉伸了整个职业的月均收入,也就是不要因为选择了架构或人工智能专业而沾沾自喜,全靠实力说话。
2.整个职业中数据挖掘师虽然没有很高薪的岗位,但是工资及其的均匀,都超过了数据架构师的月均收入和AL比肩。
最后小编想说的是行行出状元,做一行,行一行,行行行,但是你如果向往百万年薪就必须拓展自己。祝大家考研成功,乌拉!