前言
Boss直聘是一款广受欢迎的招聘平台,其中包含了丰富的岗位信息。作为数据分析人员或技术爱好者,通过爬虫获取这些数据可以帮助我们进一步理解市场需求。本次爬虫项目使用了Python的Selenium库,以模拟浏览器自动化操作来抓取Boss直聘的招聘信息。并将其可视化以获得对不同城市、公司规模、学历要求等维度的职位数据分析。我们将主要使用 pandas
、matplotlib
、pyecharts
等库进行数据处理和可视化,最终生成一系列图表。
一、数据爬取
我们从招聘网站上爬取了以下字段:
- 岗位名:职位名称
- 工作地址:具体的工作地点
- 薪资:职位薪资范围
- 工作年限:要求的工作年限
- 学历要求:最低学历要求
- 公司名称:公司名称
- 公司类型:公司性质(如外企、国企等)
- 融资情况:公司融资阶段(如未融资、A轮、B轮等)
- 公司规模:公司规模(如0-20人、100-500人等)
- 岗位福利:公司提供的岗位福利(如五险一金、带薪年假等)
- 城市:所在城市
实现多线程启动
start
方法创建多个线程,并调用getData
方法来实现数据抓取。每个线程负责爬取一个页面范围的
数据,以此来提高数据抓取效率。
from threading import Thread
import pandas as pd
from selenium.webdriver.edge.service import Service
from selenium import webdriver
from selenium.webdriver.common.by import By
import time
class Boss(object):
def start(self):
threadList = []
for i in range(14): # 14个线程
t = Thread(target=self.getData, args=(i,))
t.start()
print(f"线程{t.name}开始")
time.sleep(10) # 避免被封
threadList.append(t)
return threadList
数据抓取方法:getData
在getData
方法中,通过Selenium模拟访问Boss直聘的招聘页面。该方法会获取工作岗位的相关信息,包括岗位名、工作地址、薪资、公司类型等。
def getData(self, i):
service = Service("./driver/msedgedriver.exe") # Edge驱动
driver = webdriver.Edge(service=service)
for i in range(10): # 每个线程爬取10页数据
driver.get(f"https://www.zhipin.com/web/geek/job?query=python&city=101040100&page={i+1}")
driver.implicitly_wait(10)
content = driver.find_elements(By.XPATH, '//div/ul/li[@class="job-card-wrapper"]')
for massage in content:
gwm = massage.find_element(By.XPATH, './div/a/div/span[@class="job-name"]').text
gzdz = massage.find_element(By.XPATH, './div/a/div/span/span').text
xz = massage.find_element(By.XPATH, './div/a/div/span[@class="salary"]').text
gznx = massage.find_element(By.XPATH, './div/a/div/ul/li[1]').text
xlyq = massage.find_element(By.XPATH, './div/a/div/ul/li[2]').text
qymc = massage.find_element(By.XPATH, './div/div/div/h3/a').text
# 公司类型、融资情况、公司规模等
data = {
"岗位名": gwm,
"工作地址": gzdz,
"薪资": xz,
"工作年限": gznx,
"学历要求": xlyq,
"公司名称": qymc,
}
print(data)
self.save(data) # 调用保存方法
driver.quit()
数据存储方法:save
save
方法负责将抓取的数据保存至CSV文件。该方法首先检查文件是否存在,若存在则读取并将新数据追加,确保最终文件数据去重且结构完整。
def save(self, data):
filename = "boss职位.csv"
df = pd.DataFrame([data])
if pd.io.common.file_exists(filename):
existing_df = pd.read_csv(filename)
combined_df = pd.concat([existing_df, df], ignore_index=True)
unique_df = combined_df.drop_duplicates(subset=['岗位名'], keep='first')
unique_df.to_csv(filename, index=False, encoding='utf-8-sig')
else:
df.to_csv(filename, index=False, encoding='utf-8-sig')
启动爬虫
__main__
部分启动整个程序,并调用start
和stop
方法实现数据抓取的启动与终止。
if __name__ == '__main__':
bs = Boss()
threads = bs.start()
bs.stop(threads)
- 延时设置:为避免触发反爬机制,每个线程启动时加入了10秒的延时。
- 数据去重:在保存数据时,通过去重避免了相同职位重复写入文件。
数据可视化可以帮助我们更清晰地了解数据的分布、趋势和关系。对Boss直聘的数据进行一系列图表绘制,包括地图、柱状图、饼图等,帮助我们更好地了解招聘市场的状况。
二、数据分析
数据预处理
首先,从CSV文件加载数据,检查是否存在缺失值,并进行数据清洗。对于空缺的公司规模
字段,我们删除对应的数据行。
import pandas as pd
df = pd.read_csv('boss职位.csv')
df.drop(df[df['公司规模'].isnull()].index, inplace=True)
数据的分析与可视化
1. 城市岗位数量的地图分布
我们使用Pyecharts的Map
图表绘制出全国主要城市的岗位数量分布,展示各地的招聘需求。
from pyecharts.charts import Map
from pyecharts import options as opt
df['城市'] = df['工作地址'].str.split('·', expand=True)[0]
map_chart = Map(init_opts=opt.InitOpts(width="1600px", height="600px"))
data = df.groupby('城市').size().reset_index().rename(columns={0: '数量'})
data['城市'] = data['城市'] + '市'
data = [list(z) for z in zip(data['城市'], data['数量'])]
map_chart.add("数据", data, "china-cities")
map_chart.set_global_opts(
title_opts=opt.TitleOpts(title="热门城市岗位数量分布地图"),
visualmap_opts=opt.VisualMapOpts(is_piecewise=False)
)
map_chart.render("热门城市岗位数量分布地图.html")
2. 热门城市的岗位数量柱状图
通过将城市按岗位数量排序并绘制柱状图,可以看到各城市的招聘岗位数量差异,方便我们了解招聘需求较多的地区。
from pyecharts.charts import Bar
bar = (Bar()
.add_yaxis('岗位数量', city['岗位数量'].tolist(), color='blue')
.add_xaxis(city['城市'].tolist())
.set_global_opts(
title_opts=opt.TitleOpts(title="热门城市工作岗位数量"),
yaxis_opts=opt.AxisOpts(name="工作岗位数量", name_location="middle", name_gap=30),
xaxis_opts=opt.AxisOpts(name="城市名称", name_location="middle", name_gap=30)
)
)
bar.render("热门城市岗位数量.html")
3. 热门城市的平均薪资
我们计算各城市的平均薪资,通过柱状图呈现热门城市的薪资水平,便于观察不同城市之间的薪资差异。
data['平均薪资'] = (data['最低薪资'] + data['最高薪资']) / 2
data1 = data.groupby('城市').agg(
平均最低薪资=('最低薪资', 'mean'),
平均最高薪资=('最高薪资', 'mean'),
平均薪资=('平均薪资', 'mean')
).reset_index()
bar = (Bar()
.add_yaxis("下限", data1["平均最低薪资"].astype(int).tolist(), color='blue')
.add_yaxis("上限", data1["平均最高薪资"].astype(int).tolist(), color="orange")
.add_yaxis("平均薪资", data1["平均薪资"].astype(int).tolist())
.add_xaxis(data1['城市'].tolist())
.set_global_opts(
title_opts=opt.TitleOpts(title="热门城市平均薪资"),
yaxis_opts=opt.AxisOpts(name="平均薪资", name_location="middle", name_gap=50),
xaxis_opts=opt.AxisOpts(name="城市名称", name_location="middle", name_gap=30)
)
)
bar.render("热门城市平均薪资.html")
4. 岗位与学历的关系
通过对数据按学历要求进行分组,并使用饼图展示不同学历对应的岗位数量分布,可以直观地看到公司对不同学历的需求情况。
from pyecharts.charts import Pie
data3 = df.groupby('学历要求').size().sort_values(ascending=False).reset_index()
pie = Pie()
pie.add(
"岗位与学历关系",
[list(z) for z in zip(data3['学历要求'].tolist(), data3[0].tolist())],
radius=["40%", "75%"]
)
pie.set_global_opts(
title_opts=opt.TitleOpts(title="岗位与学历关系")
)
pie.set_series_opts(
label_opts=opt.LabelOpts(formatter="{b}: {c} ({d}%)")
)
pie.render("岗位与学历关系.html")
5. 工作年限与薪资的关系
公司对不同工龄的员工支付的薪资水平不同。我们通过自定义顺序展示各工作年限对应的平均薪资,形成清晰的薪资-工龄对比图。
custom_order = ['经验不限', '10年以上', '5-10年', '3-5年', '1-3年', '1年以内', '在校/应届']
data5 = data.groupby('工作年限').agg(平均薪资=('平均薪资', 'mean')).loc[custom_order].reset_index()
bar = (Bar()
.add_yaxis("平均薪资", data5["平均薪资"].astype(int).tolist(), color="orange")
.add_xaxis(data5['工作年限'].tolist())
.set_global_opts(
title_opts=opt.TitleOpts(title="工作年限与薪资的关系图"),
yaxis_opts=opt.AxisOpts(name="平均薪资", name_location="middle", name_gap=50),
xaxis_opts=opt.AxisOpts(name="工龄", name_location="middle", name_gap=30)
)
)
bar.render("工作年限与薪资的关系图.html")
6. 薪资与学历关系
根据学历要求计算平均薪资,并通过柱状图展示学历与薪资之间的关系。
data3 = data2.groupby('学历要求').agg(
平均薪资=('平均薪资', 'mean'),
).reset_index()
bar = Bar().add_xaxis(data3['学历要求'].tolist()).add_yaxis("平均薪资", data3["平均薪资"].astype(int).tolist(), color="green")
7. 工作年限与薪资关系
根据工作年限计算薪资,并绘制柱状图展示工作年限与薪资的关系。
data4 = data.groupby('工作年限').agg(
平均薪资=('平均薪资', 'mean'),
).reset_index()
bar = Bar().add_yaxis("平均薪资", data4["平均薪资"].astype(int).tolist(), color="orange")
8. 公司规模与薪资关系
根据公司规模计算平均薪资,并展示公司规模与薪资的关系。
data6 = data.groupby('公司规模').agg(
平均薪资=('平均薪资', 'mean'),
).reset_index()
bar = Bar().add_xaxis(data6['公司规模'].tolist()).add_yaxis("平均薪资", data6["平均薪资"].astype(int).tolist(), color="blue")
9. 融资情况与薪资关系
通过柱状图和折线图的组合展示不同融资情况的公司薪资分布。
data7 = data.groupby('融资情况').agg(
数量=('融资情况', 'count'),
平均薪资=('平均薪资', 'mean')
).reset_index()
bar = Bar().add_xaxis(data7['融资情况'].tolist()).add_yaxis("数量", data7['数量'].tolist(), color='blue', stack="stack1")
line = Line().add_xaxis(data7['融资情况'].tolist()).add_yaxis("平均薪资趋势", data7['平均薪资'].astype(int).tolist(), color='red', stack="stack1")
bar.overlap(line)
总结
python爬虫
本次项目更加熟悉如何使用Python和Selenium抓取Boss直聘的岗位信息,并将数据存储到CSV文件中。本次项目的核心在于多线程的实现以及数据存储的去重处理。
数据分析方面
对不同城市、不同学历要求、工作年限、公司规模等维度的岗位需求、薪资水平以及其他相关信息,且通过不同类型的图表(如柱状图、饼图、地图等)进行可视化展示,帮助直观了解各类信息的分布和趋势。最后,通过本次项目的实践,我掌握了如何用 pyecharts 创建多种类型的图表,还了解了如何处理和分析数据。这种能力对于数据可视化和分析工作非常有帮助