出于个人就业需求,故通过对苏州 无锡 常州[某程无忧]上招聘信息的分析,了解该地区的市场需求,薪资水平,明确求职方向
说明:
考虑到疫情和数据选取时间节点,结论可能具有片面性,仅供参考!
数据爬取日期2022年5月14日
数据清洗和可视化2022年5月15日
- 数据来源分析
① 确定自己需求是什么?
采集内容是那些,采集网址是什么
② 通过浏览器自带的 开发者工具 进行抓包分析
确定请求网址 请求方式 请求头 - 代码实现步骤过程
① 发送请求,对于刚刚分析得到url地址模拟浏览器发送请求
② 获取数据,获取服务器返回响应数据
③ 解析数据,提取我们想要数据内容
④ 保存数据,保存表格数据
import requests #导入数据请求模块 import re #导入正则模块 import json#导入json模块 import pprint#导入格式化输出模块 import csv #导入csv import time#导入时间模块创建文件 确定保存方式 以及编码格式
f = open('苏锡常数分岗位需求.csv',mode = 'a', encoding='utf-8',newline ='')
csv_writer = csv.DictWriter(f,fieldnames = [
'职位名称',
'城市',
'经验学历要求',
'薪资',
'福利待遇',
'公司名字',
'行业属性',
'公司规模',
'公司性质',
'职位详情页',
'公司详情页',
'发布时间',
])
csv_writer.writeheader()#写入表头
① 发送请求,对于刚刚分析得到url地址模拟浏览器发送请求
Ⅰ 确定请求url地址 Ⅱ 请求方式 Ⅲ 如何进行伪装python代码
for page in range(1,7):
print(f'================================正在采集第{page}页内容================================')
time.sleep(3.5)
url = f'https://search.51job.com/list/070300%252c070400%252c070500,000000,0000,00,9,99,%25E6%2595%25B0%25E6%258D%25AE%25E5%2588%2586%25E6%259E%2590,2,{page}.html'
headers = {
'Cookie':'_uab_collina=165252788909109577276979; acw_tc=76b20fec16525278867308550e0f644ec8550264e813975d44159d8b99cee3; guid=60c891c18e26c8e602be27be1a4a922e; nsearch=jobarea%3D%26%7C%26ord_field%3D%26%7C%26recentSearch; search=jobarea%7E%60070300%2C070400%2C070500%7C%21ord_field%7E%600%7C%21recentSearch; acw_sc__v2=627f9793fc42aeae56ee8c45b94e6af8f5a5099b; ssxmod_itna=eqIxg7DQDtK7qAKq0dD=wgY4mxUaaKaeeTkttODl=D=xA5D8D6DQeGTTuadoIo17DBKaibWfPx5fFBA4dY3aonxxaoUtEeGLDmKDyYjOR; ssxmod_itna2=eqIxg7DQDtK7qAKq0dD=wgY4mxUaaKaeeTkttD6p4=miD0yiB403kQyoatK0tcDn4h8qDCqj345Wnxj=4hzW9R8K+p7EWvOq8AYFhKdUxFHk8G,
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome',
}
response = requests.get(url = url,headers = headers) #返回response响应对象:,200是状态码 表示请求成功
#常见错误:requests.exceptions.InvalidHeader: Invalid return character or leading space in header: Cookie
#解决办法:检查直接复制过来的请求头,删除请求头里面的空格
② 获取数据,获取服务器返回响应数据
Ⅰ response.text 获取响应文本数据
print(response.text)③ 解析数据,提取我们想要数据内容
Ⅰ 正则表达式提取,可以直接对于字符串数据进行数据解析
re.findall()从什么数据里面找什么样的东西
html_data 列表;正则表达式提取数据 返回是列表
在pycharm运行结果里面判断是字符串还是字典,如果是双引号 大概率是字符串,如果是单引号 大概率是字典;
需要把字符串转成字典模式
html_data = re.findall('window.__SEARCH_RESULT__ = (.*?)',response.text)[0]
json_data = json.loads(html_data)#需要把字符串转成字典模式
#print(html_data)
#print(type(html_data))
#print(json_data)
#print(type(json_data))
# pprint.pprint(json_data)#格式化输出
#for 循环遍历 把列表里面元素取出来
for index in json_data['engine_jds']:
#pprint.pprint(index)
dit = {
'职位名称': index['job_title'],
'城市': index['workarea_text'],
'经验学历要求': index['attribute_text'],
'薪资': index['providesalary_text'],
'福利待遇': index['jobwelf'],
'公司名字': index['company_name'],
'行业属性': index['companyind_text'],
'公司规模': index['companysize_text'],
'公司性质': index['companytype_text'],
'职位详情页': index['job_href'],
'公司详情页':index['company_href'],
'发布时间': index['issuedate']
}
④ 保存数据,保存表格数据
csv_writer.writerow(dit)#写入数据
# print(dit)
数据清洗
导入包
import pandas as pd import numpy as np import matplotlib.pyplot as plt from pyecharts.charts import * from pyecharts import options as opts # 解决坐标轴刻度负号乱码 plt.rcParams['axes.unicode_minus'] = False # 解决中文乱码问题 plt.rcParams['font.sans-serif'] = ['Simhei']导入数据
df = pd.read_csv('苏锡常数据分析岗位需求.csv')
描述性概况
df.head()#数据标题行,整体导入情况
df.info() #查看数据基本情况:是否缺失,变量类型等
df.dtypes #查看数据类型
df.shape查看重复值
df.duplicated().sum()查看缺失值
df.isnull().sum()
s=df.isnull().sum(axis=1) #查看一行的缺失情况 s[s>0] #选出有缺失值的行缺失值处理
学历 用众数填充
薪资 缺失较少 删除
福利待遇 暂不处理
df[df.学历.isnull()]
#学历 用众数填充 # df['学历'].mode() df.loc[[167],'学历']='本科' df[df.学历.isnull()]
#薪资独特属性 且 缺失较少 删除 df.dropna(subset=['薪资'],inplace = True)
#再次查看数据基本信息 df.info()地区列处理
df['城市'].unique()
#取城市名称
df['城市'] = df['城市'].apply(lambda x:x.split('-')[0])
df['城市'].unique()
经验列处理
df['工作经验'].unique()
无异常值
df['学历'].unique()
无异常值 | 可以将"高中"和"中技/中专"合并 减少分类,本案例中未处理
df['薪资'].unique()
单位不统一
分子 金额不统一[千 万 元]
分母 时间不统一[月 年 小时]
基本思路:
1. 按-分隔符拆分,再分别取出数字和单位
2. 计算平均值时候,统一 单位 按照 千/月 转换
#正则选取上限和下限,方便取岗位平均值用于统计分析
df['bottom'] = df['薪资'].str.extract('^(.*?)-.*?')
df['top'] = df['薪资'].str.extract('^.*?-(d+).*')
df['单位'] = df['薪资'].str.extract('^.*?-.*?([u4e00-u9fa5]/[u4e00-u9fa5])')
#数据格式改为浮点型 便于计算
df['bottom'] = df['bottom'].astype('float64')
df['top'] = df['top'].astype('float64')
df['单位'].unique()
#对单位进行替换,便于计算
df['单位'] = df.单位.str.replace('千/月','1000',regex=True).str.replace('万/月','10000',regex=True).str.replace('万/年','834',regex=True).astype('float64')
#替换之后的单位
df['单位'].unique()
#对缺失值进行处理 df[df.单位.isnull()] #1条记录 :可以选择删除或者进行处理 df.loc[[250],['bottom','top']] = 6.688 df.loc[[250],'单位'] =1000
#计算平均工资
df['平均工资'] = (df['bottom']+df['top'])*df['单位']/2
df.平均工资 = df.平均工资.astype('int')
df['平均工资'].unique()
#检验 数据清洗是否异常 | 即 数据区间是否符合逻辑 df[['bottom','top','平均工资']].describe()可视化展示
薪资 区间 >>> 众数区间[- 9k -]; 平均月薪11k; 3/4分位:15k 经验要求情况 >>> 1-4年工作经验+(本科|大专)学历 = 基本OK 什么地区招聘人员比较多 >>>苏州 > 无锡 > 常州 基本符合GDP现状 经验要求和薪资情况:是不是薪资越高 经验要求越高 >>>基本匹配 学历要求和薪资情况:是不是薪资越高 学历要求越高 >>>基本匹配薪资区间
df['平均工资'].plot.hist(bins =30,figsize =(20,8),edgecolor = 'black')
plt.xlabel('千/月')
plt.ylabel('数量')
plt.show()
经验 学历要求情况
df_1 = df['工作经验'].value_counts() x = df_1.index.tolist() y = df_1.values.tolist() df_2 = df['学历'].value_counts() x_2 = df_2.index.tolist() y_2 = df_2.values.tolist() data_pair_1 = [list(z) for z in zip(x,y)] data_pair_2 = [list(z) for z in zip(x_2,y_2)]
c = (
Pie(init_opts = opts.InitOpts(width = "1000px",height ="600px",bg_color ="#2c343c"))
.add(
series_name = "经验需求占比",
data_pair = data_pair_1,
rosetype = "radius",
radius ="55%",
center = ["25%","50%"],
label_opts = opts.LabelOpts(is_show =False, position ="center",color = "rgba(255,255,255,0.3)"),
)
.add(
series_name = "学历需求占比",
data_pair = data_pair_2,
radius ="55%",
center = ["75%","50%"],
label_opts = opts.LabelOpts(is_show =False, position ="center",color = "rgba(255,255,255,0.3)"),
)
.set_series_opts(
tooltip_opts = opts.TooltipOpts(
trigger = "item",formatter = "{a}
{b}: {c} ({d}%)"
),
label_opts = opts.LabelOpts(color = "rgba(255,255,255,0.3)"),
)
.set_global_opts(
title_opts = opts.TitleOpts(
title = "经验、学历需求占比",
pos_left ="center",
pos_top ="20",
title_textstyle_opts = opts.TextStyleOpts(color ="#fff"),
),
legend_opts = opts.LegendOpts(is_show =False),
)
.set_colors(["#D53A35","#334B5C","#61A0A8","#D48265","#749F83"])
)
c.render_notebook()
经验:1-4年占据76%左右;
学历:大专+本科 占据90%左右;
from pyecharts.globals import SymbolType
address_count = df.groupby('城市').count()['公司名字'].sort_values()
x = address_count.index.tolist()
y = address_count.values.tolist()
c = (
PictorialBar()
.add_xaxis(x)
.add_yaxis(
"",
y,
label_opts = opts.LabelOpts(is_show = False),
symbol_size = 18,
symbol_repeat = "fixed",
symbol_offset = [0,0],
is_symbol_clip = True,
symbol = SymbolType.ROUND_RECT,
)
.reversal_axis()
.set_global_opts(
title_opts = opts.TitleOpts(title = "地区人员招聘数量"),
xaxis_opts = opts.AxisOpts(is_show =False),
yaxis_opts = opts.AxisOpts(
axistick_opts = opts.AxisTickOpts(is_show = False),
axisline_opts = opts.AxisLineOpts(
linestyle_opts = opts.LineStyleOpts(opacity = 0)
),
),
)
)
c.render_notebook()
经验要求 和薪资情况:是不是薪资越高经验要求越高
mean = df.groupby('工作经验')['平均工资'].mean().sort_values()
x = mean.index.tolist()
y = mean.values.tolist()
c = (
Bar()
.add_xaxis(x)
.add_yaxis(
"工作经验",
y,
markpoint_opts =opts.MarkPointOpts(
data = [opts.MarkPointItem(name ="无需经验",coord = [x[3],y[3]],value = y[3])]
)
)
.set_global_opts(title_opts = opts.TitleOpts(title = "不同工作经验的平均薪资"))
.set_series_opts(label_opts = opts.LabelOpts(is_show =False))
)
c.render_notebook()
学历要求 和薪资情况:是不是薪资越高 学历要求越高
mean = df.groupby('学历')['平均工资'].mean().sort_values()
x = mean.index.tolist()
y = mean.values.tolist()
c = (
Bar()
.add_xaxis(x)
.add_yaxis(
"学历",
y,
markpoint_opts =opts.MarkPointOpts(
data = [opts.MarkPointItem(name ="学历不限",coord = [x[1],y[1]],value = y[1])]
)
)
.set_global_opts(title_opts = opts.TitleOpts(title = "不同学历的平均薪资"))
.set_series_opts(label_opts = opts.LabelOpts(is_show =False))
)
c.render_notebook()
福利待遇
text = df["福利待遇"].dropna().to_string() text
import jieba# 导入结巴库 处理分词
words = jieba.lcut(text)
#通过遍历words的方式,统计出每个词出现的频次
counts = {}
for word in words:
if len(word)==1:
continue
else:
counts[word] = counts.get(word,0)+1
items = list(counts.items())
new = []
for i in items:
if i[1]>3:
new.append(i)
c = (
WordCloud()
.add(series_name ="热点分析",data_pair = new,word_size_range = [6,66])
.set_global_opts(
title_opts = opts.TitleOpts(
title ="福利待遇",title_textstyle_opts = opts.TextStyleOpts(font_size =23)
),
tooltip_opts = opts.TooltipOpts(is_show =True),
)
)
c.render_notebook()



