简介:这是一份基于boss直聘网招聘数据的Python数据分析与可视化期末大作业,适合数据分析初学者、高校学生用于课程设计、毕业设计或项目实战参考。项目围绕职位、城市、公司、薪资、学历、工作经验等字段展开,完成数据清洗、重塑、统计和交互式可视化,并采用Flask框架与Bootstrap搭建网页展示,直观呈现数据分析岗位的人才需求、薪资水平与发展前景。压缩包共60个文件,大小约6.15MB,涵盖Jupyter Notebook分析脚本、Python源码、CSV数据集、HTML可视化页面及大量结果图表,并带有README说明文档与目录结构说明,便于按模块逐步学习与复现。目前已有1389人学习,内容覆盖从数据预处理、最低/最高/平均薪资及奖金率计算,到Plotly绘图和Web部署的完整流程;同时针对不同城市、学历、薪资段和行业进行多维对比分析,能帮助读者系统理解数据分析岗位的行业分布与职业前景,快速掌握数据分析与可视化的项目实践方法。
1. 项目整体设计与技术选型思路
1.1 这个期末项目到底做了什么
先把这个项目的定位说清楚。这是一份典型的“数据采集-数据清洗-数据分析-可视化呈现”全流程作业,选题是BOSS直聘网的招聘数据。说白了,就是把招聘网站上和你专业相关的岗位信息爬下来,存成结构化数据,用Python做一轮多维度的分析,最后用图表把结论直观地摆出来。
这类项目在期末作业里非常常见,但它的价值并不在于“爬虫”本身有多高级,而在于它覆盖了数据分析的完整链路。很多同学拿到这种题目容易犯一个错误:把精力全砸在爬虫上,结果分析部分就画两张柱状图草草了事。实际上,期末答辩时老师更看重的是你的数据思维——你有没有从数据里发现规律、得出对求职者有参考价值的结论。
我这次设计的核心思路是:以“数据分析可视化”作为项目落点,以“爬虫”作为数据获取手段,以“BOSS直聘网真实岗位数据”作为分析对象。整个项目围绕三个问题展开——这个城市/行业的薪资水平怎么样,企业对学历和经验的要求集中在什么区间,哪些岗位方向最热门。把这三个问题答清楚,项目就立住了。
1.2 技术栈选型:为什么是Python + Requests + pyecharts
技术选型上,我没有用Scrapy框架,也没有上Selenium无头浏览器,而是选择了最简单的组合:Requests发请求 + pandas做清洗 + pyecharts做可视化。
这么选有明确的理由。这个项目的核心目标是数据分析,不是爬虫架构设计。如果上Scrapy,你得先处理中间件、管道、Item定义这些概念,学习成本翻倍不说,期末答辩时老师问你“为什么这么设计”,解释起来也麻烦。而Requests + BeautifulSoup的组合,代码量少、逻辑直白,任何一个看过爬虫基础教程的人都能看懂。
可视化部分我坚持用pyecharts而不是Matplotlib,原因也很实际。一来这类期末项目的受众是老师,可视化大屏的视觉冲击力远强于Matplotlib画出来的折线图;二来pyecharts生成的图表是交互式的,鼠标悬停能看到具体数值,展示时天然有优势。后面我会细讲大屏怎么搭,这里只说结论:pyecharts是这类项目的首选。
1.3 项目结构设计与模块划分
代码组织上,我用了四个模块来隔离不同职责,避免所有代码堆在一个文件里。这是很多初学者容易忽视的坑——期末作业代码可以写得简单,但结构要清晰,这也是评分点之一。
boss_zhipin_analysis/ ├── spider/ # 爬虫模块 │ ├── boss_spider.py # 爬虫主逻辑,负责请求和解析 │ └── config.py # 请求头、URL参数等配置 ├── analysis/ # 分析模块 │ └── data_clean.py # 数据清洗和分析逻辑 ├── data/ # 数据目录 │ └── boss_jobs.csv # 爬取到的原始数据 ├── output/ # 输出目录 │ └── 可视化图表.html # 生成的可视化大屏 └── main.py # 主入口,串联整个流程这样的结构好在哪?第一,每个文件职责单一,哪里出了问题可以直接定位;第二,答辩时你可以很清楚地向老师介绍“这是数据采集模块、这是数据处理模块、这是可视化模块”,逻辑链条完整。后面每个模块的具体实现我都会展开讲。
2. 数据采集与清洗:细节决定成败
2.1 爬虫设计的几个关键点
爬虫部分是整个项目里最容易翻车的地方,主要问题集中在请求头设置、翻页逻辑和字段提取三个方面。
请求头这块,我第一版代码只写了User-Agent,结果请求了几十条就被反爬拦截了。后来我加上了Referer、Accept-Language等完整字段,同时在两次请求之间加了1到3秒的随机延时,才稳定跑通。这里有个经验:BOSS直聘的PC端网页对请求频率很敏感,实际测试下来,每页间隔2秒以上比较安全。如果你直接用requests.get而不做任何伪装,大概率拿到的是验证码页面而不是数据。
翻页逻辑上,BOSS直聘的URL参数是pn表示页码,比如pn=1是第一页,pn=2是第二页。我爬的是“数据分析”这个关键词在上海地区的岗位,每页10条,共爬了10页100条数据,用于期末作业足够了。这里不建议贪多,爬太多数据一是耗时,二是容易被封IP,三是数据量大到一定程度,分析和展示的难度也会增加,反而不利于期末答辩时把逻辑讲透。
字段提取这块,我最终保留了城市、岗位名称、公司名称、薪资区间、学历要求、经验要求、技能标签、职位描述摘要这8个字段。其中技能标签和职位描述摘要主要用于后续的词频分析,薪资以外字段的分析价值同样重要。
# spider/config.py HEADERS = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36", "Referer": "https://www.zhipin.com/web/geek/job?query=数据分析&city=101020100", "Accept-Language": "zh-CN,zh;q=0.9", } CITY_CODE = "101020100" # 上海 KEYWORD = "数据分析" PAGE_NUM = 102.2 数据清洗:从原始字段到可分析字段
爬下来的原始数据不能直接分析,这是很多人没有意识到的问题。我之前看过不少同学交上来的代码,拿到数据直接就groupby+绘图,做出来的图表信息完全错乱。问题就出在数据清洗这一步做得不够。
这个项目里有两个字段必须做加工处理。第一个是薪资字段。BOSS直聘的薪资显示的是区间,比如“15-25K·14薪”,这个格式必须拆分处理。我从里提取出最低薪资和最高薪资,并计算出平均薪资,统一转为数字类型,才能进行后续的均值计算和区间统计。第二个是岗位名称字段。不同公司对同一类岗位的命名五花八门,有的叫“数据分析师”,有的叫“数据分析专员”,还有的叫“商业分析”,我在清洗时做了归并处理,把相近的名称统一为“数据分析师”,这样统计岗位数量时才不会出现信息碎片化。
去重逻辑也很关键。我用公司名称+岗位名称+薪资区间三个字段组合来判断重复,实测下来能去掉大约5%的重复数据。这些细节在答辩时主动讲出来,老师会认为你具备真实的数据处理经验,而不是单纯跑通了一个爬虫。
# analysis/data_clean.py import pandas as pd df = pd.read_csv("../data/boss_jobs.csv") # 薪资区间拆分:'15-25K·14薪' -> min_salary / max_salary / avg_salary def split_salary(s): # 提取第一个数字区间 import re nums = re.findall(r"(\d+)-(\d+)K", s) if nums: low, high = map(int, nums[0]) return pd.Series([low, high, (low + high) / 2]) return pd.Series([None, None, None]) df[["min_salary", "max_salary", "avg_salary"]] = df["salary"].apply(split_salary)2.3 缺失值与异常值的处理策略
我爬下来的数据里,技能标签字段大约有8%的缺失,职位描述摘要有3%的缺失。处理方式要根据字段的分析用途来决定:技能标签缺失的我填空列表,职位描述缺失的直接删除对应行,因为后面做词频分析时,空值会影响统计准确性。
异常值上有个典型的案例:有一家公司的岗位薪资写的是“40-60K·20薪”,明显高于同批次的平均水平。一开始我以为这个值是合理的高端岗位,后来查看职位描述才发现这是一个管理层岗位,混入了普通数据分析师的样本里。这种情况如果不处理,统计出的平均薪资会被明显拉高。我的做法是把超过整体均值三倍标准差的记录单独标记出来,在分析环节排除,但保留在原始数据文件中,方便答辩时解释数据处理的依据。
提示:清洗逻辑每做一步都要输出一行日志,比如“删除重复数据5条”“薪资字段解析失败2条”。这样不仅能帮你定位清洗过程中的问题,答辩时还能展示你对数据质量的把控意识。
3. 可视化大屏实现:从数据到结论的最后一公里
3.1 图表选型逻辑:什么数据配什么图
可视化不是把所有图表堆在一起就完事了,每一张图都要能回答一个问题。我做这张大屏时花了最长时间的不是写代码,而是想清楚“我要呈现什么结论,什么图最合适”。
这次用了五类图表覆盖五个核心问题。第一是柱状图,展示不同学历要求的岗位数量分布,能直观看出招聘市场的主要学历门槛。第二是饼图/环形图,展示岗位的经验要求占比,用于回答“数据分析岗位到底需不需要工作经验”。第三是箱线图,展示不同规模公司之间的薪资水平和离散程度,这个图能同时呈现中位数、四分位距和异常值,信息量比单纯的均值柱状图大得多。第四是词云图,基于职位描述和技能标签做词频统计,用于呈现市场最看重哪些技能。第五是地图或城市对比横向条形图,因为这次数据聚焦上海,所以用了横向条形图来对比不同行政区的岗位数量。
选图的基本原则是:你要回答什么类型的问题,就选对应的图表。比较大小用柱状图,看占比用饼图,看分布用箱线图,看关键词聚合用词云。这个逻辑在答辩时一定要能讲清楚,如果被问到为什么不用折线图,你要能说出折线图适用于随时间变化的趋势分析,而这个项目的数据是截面数据,没有时间序列维度,所以不适用。
3.2 大屏布局与tab切换设计
大屏布局我用的是一个整体页面 + Tab标签页的方案。第一屏放总体概览:岗位数量、平均薪资、学历分布、经验分布四个核心指标卡片,外加一张岗位薪资Top12的横向条形图。第二屏放深度分析:公司规模薪资箱线图、技能词云图、行政区岗位对比。
之所以用Tab而不是把所有图挤在一个页面上,是因为期末答辩现场的屏幕大小不确定。如果一张页面上放太多图,字会变得很小,坐在后排的老师根本看不清。Tab方案的好处是可以一键逐屏展示,先讲整体结论,再展开细节分析,叙事节奏好控制。
3.3 核心代码:从DataFrame到HTML报告
pyecharts的用法相对简单,做这个项目时我用的是链式调用的方式,先创建图表对象,再set_global_opts设置标题、图例和坐标轴,最后用render函数直接输出独立HTML文件。
我这边实现的关键点是用Page组件把所有图表组合成单个HTML文件,这样不用启动本地服务,双击文件浏览器就能打开,答辩现场不用担心环境问题。
下面是薪资Top12岗位的横向条形图核心代码:
from pyecharts.charts import Bar, Pie, Boxplot, WordCloud, Tab from pyecharts import options as opts # 岗位平均薪资Top12 def make_salary_bar(df): top12 = ( df.groupby("job_name")["avg_salary"] .mean() .sort_values(ascending=False) .head(12) ) bar = ( Bar() .add_xaxis(top12.index.tolist()) .add_yaxis("平均薪资(K)", top12.values.tolist()) .reversal_axis() .set_global_opts( title_opts=opts.TitleOpts(title="岗位平均薪资Top12"), xaxis_opts=opts.AxisOpts(name="平均薪资(K)") ) ) return bar词云图用的是WordCloud组件,传入的词频数据格式是[("Python", 120), ("SQL", 100)]这样的二元组列表。我是先从所有职位描述文本里做jieba分词,再用Counter统计词频,最后截取前100个高频词传入词云。整个链路比较简单,但对期末项目来说效果非常好。
import jieba from collections import Counter def make_wordcloud(df): words = [] for desc in df["job_desc"].dropna(): words.extend(jieba.lcut(desc)) # 过滤无关词 stop_words = {"工作", "负责", "职位", "岗位", "相关", "任职", "要求"} filtered = [w for w in words if w not in stop_words and len(w) > 1] word_freq = Counter(filtered).most_common(100) wc = ( WordCloud() .add("", word_freq, word_size_range=[20, 80]) .set_global_opts(title_opts=opts.TitleOpts(title="职位描述高频技能词")) ) return wc3.4 渲染异常处理:一张图都别红
用pyecharts做这类项目,最容易遇到的就是图片渲染时中文字体显示为方块的问题。出现这个情况的原因通常是运行环境里缺少中文字体,pyecharts生成的HTML在调用浏览器渲染时找不到合适的字体就会乱码。实话说这个坑我调试了一个下午才解决,最后是通过手动指定字体的方式处理的,具体在做词云图时,把字体路径指到系统自带的中文字体文件上,比如C:/Windows/Fonts/msyh.ttc,问题就消失了。
另一个常见问题是Boxplot对数据格式有特殊要求。pyecharts的箱线图要求传入的是嵌套列表,即每个分组的数据是一个列表,然后把这些列表再包一层,与柱状图的数据格式不同,这点要特别注意。第一次用的时候直接把一维Series传进去,图形输出为空,看了半天官方文档才反应过来。
4. 数据结论与分析洞察
4.1 拼数据:从100个样本里看到了什么
用100条招聘数据做分析,样本量虽然不算大,但已经足够看出一些结构性规律了,做期末项目完全够用。
从学历要求来看,本科是绝对的主力,占比超过六成;大专学历的岗位约占两成,硕士及以上的岗位占比约一成。这与数据分析岗位的市场认知一致——大部分企业把本科作为基本门槛,硕士研究生学历在一些金融或算法方向的数据岗位会有明显优势,但总体不是普遍要求。
从经验要求来看,3-5年经验要求的岗位占比最高,接近四成;1-3年经验的岗位紧随其后,约有三成;不限经验的岗位占比约一成。这个分布说明数据分析岗位市场已经进入相对成熟期,企业更倾向于招聘有实操经验的人,纯零基础转行的机会在减少。
薪资维度上,核心发现是岗位平均薪资的中位数在18K左右,但不同行业方向差异非常大。互联网行业的数据分析岗平均薪资明显高于传统行业同类岗位,差距在30%左右。这组数据如果放在答辩场景下,可以成为引出“行业选择比岗位选择更重要”这个观点的事实论据。
4.2 技能需求的词频洞察
从职位描述和技能标签的词频统计数据看,出现频率最高的技能前三名是Excel、SQL和Python,其次是Tableau、PowerBI和机器学习相关词汇。
这个结论和很多人直觉中的“Python是数据分析的第一技能”有一定差异。实际上招聘市场最看重的仍然是常规办公工具和数据库查询能力,Python更多是锦上添花的加分项。还有一点值得注意,技能词云里“沟通能力”“业务理解”这类软技能的频率也不低,说明企业招聘数据分析师时,除了关注技术栈,也非常看重对接业务和跨部门沟通的能力。
4.3 分析结论在期末答辩中的呈现技巧
有了上面的分析结论后,建议在答辩时分三个层次讲:数据清洗环节做了什么、图表呈现了什么规律、这些规律在真实求职中意味着什么。前两层大部分同学都能讲到,第三层才是拉开差距的地方。
我当时是这么讲的:“从数据上看,三个月的爬取和分析我得到了一个结论——数据分析岗位的入门薪资并不低,但对复合能力的要求在提高。只会用Excel做表,或者只会跑Python脚本,都已经不能支撑一个完整的数据分析项目。市场更倾向于招聘能独立完成数据采集、清洗、分析和汇报的综合性候选人。”这段话不是AI生成的套话,而是基于100条真实岗位数据得出来的判断。如果你在答辩时能说出这种基于自己数据的独立见解,分数一定不会差。
5. 期末项目中的常见踩坑与排查实录
5.1 爬虫被反爬拦截,拿到的全是验证码
这个坑我几乎可以断定每个做过这类项目的同学都会遇到。第一版代码跑通后,我加了一个循环爬取多页的逻辑,结果跑到第三页返回的数据就不对劲了——每一条记录的职位名称都是“安全验证”。排查后发现是请求频率太快触发了BOSS直聘的反爬机制。
解决方法分两步。第一步把每页请求之间的延时从0.5秒提高到2~3秒,使用time.sleep()实现随机延时;第二步把请求头里的Accept、Referer等字段补全,重点是把Referer设置为搜索结果页的URL,模拟从页面点击进入详情页的操作路径。这两步做完后,连续爬取10页没有再出现验证码。我的判断是,对于这类期末小项目,别去研究什么代理池和JS逆向,把请求频率降下来、请求头伪装做好,就已经解决90%的问题了。
5.2 数据清洗时的中文编码问题
爬取到的数据写入CSV时,如果直接用to_csv()保存,用Excel打开很可能会出现乱码。因为pandas默认编码是utf-8,而Excel默认用gbk编码打开文本文件。写CSV时要加上encoding="utf-8-sig"参数,utf-8-sig会在文件头部自动添加一个BOM标记,Excel识别到BOM后就会用UTF-8格式正确解析。
同样的,在读取别人给的CSV文件时,如果遇到UnicodeDecodeError,说明文件本身的编码和读取时指定的编码不一致,可以通过尝试gbk、GB18030、utf-8等多种编码逐一判断,不要死磕一个。
5.3 pyecharts生成的HTML打开是空白
这种情况的高频原因有两个。第一个是浏览器兼容性问题,过旧版本的浏览器对ECharts 5.0的支持不完整,换用Chrome或Edge打开基本能解决。第二个是文件路径不正确,如果HTML文件里有引用的本地资源文件,移动了HTML文件位置后资源路径会失效,导致图表加载空白。解决办法是把所有图表输出到一个单一的自包含HTML文件里,pyecharts默认会把JS库嵌入页面,不依赖外部CDN,这样在无网络环境下也能正常展示。
5.4 答辩演示时的备用方案
这里分享一个小技巧。期末答辩现场不支持播放HTML文件的概率比你想象的高——不排除教室电脑没有浏览器、或者浏览器版本过旧的情况。所以我会在生成交互式HTML之外,每个图表再导出为静态PNG图片,做成一份PDF备用。pyecharts的chart.render()只输出HTML,导出图片需要额外使用snapshot-selenium或者直接截图工具,如果嫌麻烦,更省事的方案是用pyecharts自带的SnapshotPhantomJS插件,安装配置后一行代码就能导出PNG。至少保证即使现场环境不支持HTML展示,你也有一份随时能打开的图片版结果,不至于现场尴尬。
写在最后:一点个人的实操体会
这个项目做完复盘下来,我最想分享的一点是:期末作业型的数据分析项目,代码量真的不是核心,逻辑链完整度才是。爬虫只要不跑飞、数据清洗能解释理由、可视化能回答你提出的问题,就已经超出大多数同类作业的水准了。技术上不必追求高深,但一定要追求完整和自洽。
除了项目本身,还有一个扩展思路分享给大家。如果你时间有余力,可以在现有数据基础上,把这个项目横向扩展成“多城市对比分析”——爬取北京、上海、广州、深圳四个城市的数据,然后做一个城市间的薪资和岗位需求差异对比。这会让你从“会做单个项目的分析”进阶为“会做有对比维度的分析”,含金量完全不一样。
另外补充一个与项目无关但很实际的建议:期末项目的数据文件、代码文件、可视化HTML文件和报告文档,务必打包时分开目录存放,并在报告里附上运行说明。老师打开你提交的压缩包时,如果能在两分钟内找到入口文件和启动方式,印象分会好很多。
希望这份拆解对你有用,祝你的期末项目顺利过关。
本文还有配套的精品资源,点击获取