ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

Python数据分析实战:Boss直聘数据清洗与可视化大屏全流程

2026/9/20 11:59:44 拓冰建站 浏览量
Python数据分析实战:Boss直聘数据清洗与可视化大屏全流程 简介这份python数据分析与可视化项目以boss直聘网真实数据为源覆盖岗位、城市、薪资、学历、工作经验等维度适合数据分析初学者或期末大作业参考。项目包含完整数据清洗、重塑与plotly交互可视化流程并借助flask与bootstrap搭建网页展示界面。压缩包共60个文件包括ipynb分析代码、csv数据、py脚本、html展示页面、jpg/png结果图及说明文档大小6.15MB目录结构清晰。目前已有1389人学习下载。通过该项目可掌握从数据预处理、特征分析到可视化展示的完整思路还可直接复用代码与图表快速完成同类型数据分析大作业。 期末周收到“Python数据分析与可视化”课程的大作业要求时很多人的第一反应是去GitHub上找个现成项目结果答辩时导师随口问两个字段含义就露馅了。我这些年带过的学生里选boss直聘网数据分析这个题目的不在少数但真正能拿高分的往往不是代码写得最花哨的而是把“数据获取—清洗—分析—可视化—报告”这条链路完整走通的人。这个题目有个天然优势岗位名称、城市、薪资、经验学历要求这些字段语义非常明确不需要做复杂的情感分析或文本建模清洗完就能直接统计非常适合期末大作业的体量和评分要求。这篇内容我会从选题逻辑讲到最终打包成zip提交把每一步的取舍和坑都摊开说。无论你是刚学完pandas还是想拿高分的大三学生按这条路线走下来至少能省出一个通宵的调试时间。1. 选题和破题为什么boss直聘网的数据适合做期末作业1.1 数据选型的三个关键条件期末大作业最怕的不是题目难而是数据根本撑不起分析。选boss直聘网是因为它同时满足三个核心条件。第一数据维度足够丰富。一条招聘信息里自带岗位名称、薪资范围、城市、经验要求、学历要求、公司规模、融资阶段、技能标签等十几个字段。期末作业通常要求从多个角度切入分析这些字段可以直接支撑“不同城市薪资对比”“经验要求与薪资关系”“学历门槛分布”等常见选题不用额外造数据。第二数据量适合单机处理。单页搜索能爬到几百条翻几页加几个关键词就能积累几千条记录。这个量级用pandas跑groupby和agg操作都是秒级完成不需要上Spark也不需要考虑分布式期末答辩时现场演示不会卡顿。第三清洗规则有挑战性但不算变态。薪资字段是“15-20K·14薪”这种混合文本公司规模是“1000-9999人”这种区间字符串这些都需要正则和自定义函数处理恰好能体现你掌握了数据预处理能力又不至于难到做不完。1.2 课程评分视角下的项目设计思路期末大作业的评分维度通常包括选题意义、数据获取过程、预处理质量、分析内容深度、可视化表现、代码规范程度和文档完整性。很多人把精力全放在可视化大屏上结果分析部分只有几个count统计这其实是本末倒置。我建议这样分配项目模块数据采集占20%数据清洗占35%分析与可视化占35%报告和代码规范占10%。你不需要爬全网数据但一定要把清洗过程写成独立的处理函数把每一个字段的清洗规则讲清楚。比如薪资字段“15-20K·14薪”你应该拆出最低薪资、最高薪资、平均薪资、发薪月数四个字段而不是直接丢掉“14薪”里的信息。这种细节在答辩时一提出来就比“我用的平均值”高一个层次。我当时带的学生里有个做法很聪明他先自己列了10个“想问数据的问题”比如“哪些城市的前端岗位平均薪资最高”“学历要求和工作经验要求的相关性有多强”然后让每一个可视化图表都去回答其中一个问题。这样一来分析逻辑完整图表也都有了明确用途而不是为了凑数量硬画。2. 数据从哪来爬虫采集与数据预处理的边界2.1 爬虫采集的边界与落地实施方案这里先泼一盆冷水boss直聘的网页端有比较严格的反爬机制如果直接拿requests去硬请求搜索页很容易触发验证码。期末作业的体量不建议去死磕反爬我的做法是换一种更稳的思路。可以抓取boss直聘面向求职者开放的职位搜索接口但务必控制频率并且在代码里做好随机延时。更稳妥的方案是直接用浏览器开发者工具手动保存几页JSON数据或者使用Selenium/Playwright模拟浏览器滚动加载每加载一页后等待2到3秒再继续。无论是哪种方式都只能用于个人学习研究不能用于商业用途这一点会在代码注释和报告里写清楚。这里给一份关键代码用于把采集到的原始JSON统一转成DataFrameimport json import pandas as pd def parse_job_list(json_file): with open(json_file, r, encodingutf-8) as f: data json.load(f) job_list [] for item in data.get(jobList, []): job_list.append({ job_name: item.get(jobName), city: item.get(cityName), salary: item.get(salary), experience: item.get(jobExperience), education: item.get(jobDegree), company_name: item.get(brandName), company_size: item.get(brandScaleName), finance_stage: item.get(brandStageName) }) return pd.DataFrame(job_list) df parse_job_list(boss_jobs_1.json) print(df.shape, df.columns.tolist())这里有个小经验字段名最好在解析阶段就统一改名不要等到清洗阶段再rename否则多个JSON文件合并时很容易出问题。另外每爬一页就把原始JSON存一份不要直接覆盖因为你后面清洗规则改动了还需要重新读原始数据。2.2 清洗环节最容易翻车的几个字段第一个坑是薪资字段。boss直聘的薪资格式常见的有“15-20K”“20-30K·14薪”“200-300元/天”“面议”等统一处理逻辑必须考虑四种情况。我的正则方案是这样的import re import numpy as np def parse_salary(s): if not isinstance(s, str): return pd.Series([np.nan, np.nan, np.nan, np.nan]) s s.replace( , ) if 元/天 in s or 元/时 in s: return pd.Series([np.nan, np.nan, np.nan, np.nan]) if 面议 in s: return pd.Series([np.nan, np.nan, np.nan, np.nan]) match re.search(r(\d(?:\.\d)?)[Kk]?-(\d(?:\.\d)?)[Kk]?, s) if match: low float(match.group(1)) high float(match.group(2)) else: match re.search(r(\d(?:\.\d)?)[Kk], s) if match: low high float(match.group(1)) else: return pd.Series([np.nan, np.nan, np.nan, np.nan]) months 12 month_match re.search(r(\d)薪, s) if month_match: months int(month_match.group(1)) avg (low high) / 2 * months / 12 return pd.Series([low, high, avg, months]) df[[salary_low, salary_high, salary_avg, salary_months]] df[salary].apply(parse_salary)注意“200-300元/天”的实习岗处理逻辑里有意把它设为缺失值而不是强行换算成月薪。因为实习岗的天数和月薪口径不同混在一起做分析会让薪资整体偏低后面分组对比时也会出现异常点。这是实际项目里非常容易犯的错误答辩时能主动说出来会显得思考得很细。第二个坑是城市字段。boss直聘里有的岗位城市是“北京”有的是“上海·闵行区”甚至还有“异地招聘”。统一策略是只取第一个城市关键词用split(·)[0]处理如果包含“异地”则标记为“异地”。第三个坑是经验字段。“经验不限”“1-3年”“3-5年”“5-10年”“10年以上”这五类本身已经可以排序但如果你想做有序箱型图建议额外生成一个数值列不限为01-3年为23-5年为45-10年为710年以上为10。这样在后续相关性分析里才有数字可算。3. 分析框架与可视化大屏的设计逻辑3.1 分析维度拆解城市、薪资、经验、学历清洗完之后不要直接开始画图先建一个分析脑图。我的习惯是对着DataFrame的每一列问自己三个问题这个字段能回答什么问题答案对读者有没有价值最合适的图表是什么城市维度的经典分析是“不同城市平均薪资TOP15”用横向条形图展示接着可以钻取“北京不同岗位的薪资中位数”用箱线图展示分布。经验维度适合做“薪资随工作经验的变化趋势”一目了然地告诉大家5-10年经验的薪资是不是真的比3-5年高一截。学历维度可以用堆叠条形图看“不同学历对应的岗位数量”再结合经验字段做二维透视表比如“本科3-5年”最常见这类岗位的平均薪资是多少。岗位名称本身也需要清洗比如“高级Python开发工程师”和“Python开发工程师”应该归类到“Python开发”。你可以手写一个岗位方向的映射函数用关键词匹配def classify_job(name): if not isinstance(name, str): return 其他 if python in name.lower(): return Python开发 if java in name.lower(): return Java开发 if 前端 in name or web in name.lower(): return 前端开发 if 算法 in name or 机器学习 in name: return 算法 if 数据分析 in name or 数据运营 in name: return 数据分析 if 测试 in name: return 测试 return 其他 df[job_category] df[job_name].apply(classify_job)这样做的目的是让分析维度更有业务洞察感导师看到的不只是技术而是你会不会有意识地把原始文本转换成可分析的标签。3.2 从Matplotlib到Pyecharts的可视化选型期末大作业的可视化有两个方向静态图表和交互式大屏。如果时间紧张我更推荐用Pyecharts做几个独立的HTML文件再拼成一个简单的仪表板因为它们交互效果出色而且代码量少。Matplotlib更适合做深入分析比如箱线图、散点图、相关系数热力图这些在Pyecharts里要么支持不好要么配置繁琐。我的经验是把两类混着用统计探索用Matplotlib例如经验-薪资箱线图、学历分布饼图。结论展示用Pyecharts例如城市薪资排行Bar、岗位需求分布Pie、全国城市分布Geo地图。这里有一段Pyecharts绘制城市平均薪资排行的示例from pyecharts.charts import Bar from pyecharts import options as opts city_salary df.groupby(city)[salary_avg].median().nlargest(15) bar ( Bar() .add_xaxis(city_salary.index.tolist()) .add_yaxis(平均薪资(K), city_salary.round(1).tolist()) .set_global_opts( title_optsopts.TitleOpts(title热门城市Python岗位薪资中位数TOP15), xaxis_optsopts.AxisOpts(axislabel_optsopts.LabelOpts(rotate45)), yaxis_optsopts.AxisOpts(nameK/月) ) .set_series_opts(label_optsopts.LabelOpts(positiontop)) ) bar.render(output/city_salary_bar.html)注意这里用的是中位数而不是平均值。因为薪资数据里有不少异常高值和实习岗残留中位数能更好反映一般水平。答辩时如果能主动提一句“我选择中位数是因为数据分布右偏”评委印象分会明显提升。3.3 让大屏脚本能一键跑通的处理技巧“可视化大屏”在期末作业里天然加分但很多同学的脚本在别人电脑上跑不起来原因通常有三个。第一个是文件路径写死。正确做法是把项目根目录设为工作区用os.path.join拼接路径不要把C:/Users/xxx/...写进脚本。第二个是缺少依赖。建议在项目里放一个requirements.txt并且只列真正用到的库pandas、matplotlib、pyecharts、selenium。不要无脑把环境里的100多个包装进去。第三个是图表渲染问题。Pyecharts在Jupyter Notebook里直接渲染可能没有输出但生成HTML文件是稳定的所以大屏脚本一律执行后生成HTML文件。你可以建一个main.py结构是“读取数据—执行分析—生成所有图表”最后用一小段代码把多张图表拼成一个简易的dashboard.html。不用太复杂iframe嵌入几个HTML就可以html_parts [h1boss直聘数据分析大屏/h1] for file in [city_salary_bar.html, job_category_pie.html, experience_box.html]: html_parts.append(fiframe src{file} width100% height500/iframe) with open(output/dashboard.html, w, encodingutf-8) as f: f.write(\n.join(html_parts))这个技巧的实用价值在于答辩现场你是直接打开浏览器展示HTML不需要依赖Jupyter内核也不需要调整窗口大小非常稳。4. 期末答辩时的展示细节和代码健壮性4.1 图表数量与版面布局的黄金比例期末大作业不是图表越多越好。我在答辩现场见过最典型的反面教材十分钟时间里学生哐哐翻了二十多张图每张图讲不到半分钟评委根本记不住结论。我的建议是三加二原则三张核心图表必须做到信息密度高且能直接支持结论两张辅助图表用来展示过程或补充视角。比如核心图表可以是一场赛道薪资对比柱状图、一张经验-薪资箱线图、一张学历需求堆叠图辅助图表可以是一张城市分布热力图、一张岗位关键词词云。版面布局上dashboard.html不要堆成长条应该用CSS网格分成两列核心图表放前面辅助图表放后面。颜色风格统一用同一个主题色避免一红一绿一蓝显得非常杂。你是在做数据分析项目不是在做PPT模板。4.2 代码容错设计空数据、中文乱码、路径依赖代码健壮性是很多自学Python的人最容易忽略的部分。期末大作业的数据是爬来的难免有空值、缺失值、异常文本代码如果不做容错就可能中途报错答辩现场一旦报红哪怕只是一个小警告都会影响心态。几个必须处理的地方读取CSV时指定encodingutf-8-sig防止中文列名乱码。使用pd.to_numeric(..., errorscoerce)处理数值列避免文本混入。在groupby之前执行dropna(subset[salary_avg])过滤掉无法解析薪资的数据。每个图表生成函数用try...except包住即使某张图失败也不影响其他图表输出。下面这段代码我在教学生写项目时反复提def safe_save(chart_func, filename): try: chart chart_func() chart.render(filename) print(f[OK] {filename}) except Exception as e: print(f[WARN] {filename} 生成失败: {e}) safe_save(make_city_bar, output/city_salary_bar.html) safe_save(make_experience_box, output/experience_box.html)这个方法虽然简单但能让脚本一次跑通而且输出日志会告诉你怎么排查。很多同学觉得加try-except是偷懒实际上在数据处理项目里这就是对真实世界的尊重你永远不知道下一个数据里会混进来什么奇怪字符。4.3 答辩讲解的叙事主线代码写完了图表也生成了最后还要过一遍答辩的话术。我建议坚持“结论倒推”的讲法先抛出三个核心结论再通过图表证明这些结论。比如结论一招聘市场中Python相关岗位的需求高度集中在一线城市北京、上海、深圳、杭州四城合计占比超过60%。结论二薪资水平与经验年限明显正相关但从“3-5年”到“5-10年”增长的斜率放缓说明后段更多依赖管理岗位溢价。结论三学历门槛有明显分化算法和人工智能类岗位硕士学历占比显著高于其他岗位。这三条结论都来自你真实的数据分析结果不要为了让结论好看而去编造。如果分析出来的结果和直觉不同比如杭州薪资超过了上海这反而是加分项因为“发现了预期之外的规律”在数据分析中是很受肯定的能力。5. 打包成zip交作业前一定要做的三件事5.1 目录结构规范化期末大作业提交时是一整个zip包老师解压后要能快速看懂项目结构。我见过最乱的压缩包是几十个没命名的Python文件堆在一层目录里而且还有一堆test_final_最终版_改2.py这种文件名。这种包即使内容做得再好第一印象也已经扣分了。建议目录结构保持这样的清晰层次boss_jobs_analysis/ ├── data/ # 原始数据和清洗后的数据 │ ├── raw/ # 采集的原始json/csv │ └── cleaned/ # 清洗后的analysis_data.csv ├── code/ # 所有python脚本 │ ├── scraper.py # 数据采集 │ ├── data_clean.py # 数据清洗 │ ├── analysis.py # 统计分析 │ ├── visualization.py # 可视化输出 │ └── main.py # 一键执行入口 ├── output/ # 生成的图表和html │ ├── city_salary_bar.html │ ├── experience_box.png │ └── dashboard.html ├── requirements.txt └── README.md每个脚本的顶部用# 功能说明 注释开头参数配置集中放在脚本开头的全局变量里比如输入文件路径、输出目录、是否开启调试模式。这样就算老师不运行代码光看结构也会觉得你是个有条理的人。5.2 运行环境说明文档怎么写给分最高README.md是很多同学最后才写、甚至不写的部分但它其实是最容易拿印象分的地方。一个合格的README至少要包含四项内容项目背景、运行环境、运行步骤、结果说明。运行环境不要只写“Python3.8”要写清楚核心库版本号比如pandas1.5.3、pyecharts2.0.0。运行步骤要落实到命令行pip install -r requirements.txt python code/data_clean.py python code/analysis.py python code/visualization.py python code/main.py结果说明要写清楚每个输出文件的含义比如“city_salary_bar.html是全国主要城市Python岗位薪资中位数排名数据口径为清洗后的全职岗位”千万别让老师自己去猜。如果只是交作业而不用现场答辩我建议在README末尾加上一段“项目亮点”用三四句话总结你在清洗或分析中做得最用心的地方例如你对“14薪”的换算处理、对实习岗薪资的剔除逻辑。这既是给老师看的也是给自己答辩准备的提纲。5.3 常见扣分点复盘根据我看到的期末作业评分反馈扣分最多的不是技术实现而是下面这三类问题。第一类是结论缺失。图表很多但文字分析几乎没有老师不知道你想表达什么。解决办法是在每个图表下面配一段“这张图说明……”的解读甚至可以输出到HTML页面里让图表和结论绑定在一起。第二类是数据来源不清晰。README里不写数据是怎么拿到的字段规则不交代老师对数据可信度存疑。解决办法是在README里增加“数据说明”章节写清楚采集时间、采集关键词、清洗规则。第三类是打包前不检查。压缩包里残留了没用的文件比如desktop.ini、.DS_Store、中途调试的temp.py、重复图表文件这些都会显得很不专业。最后分享一个我常用的土办法在打包之前把zip解压到一台纯净的虚拟环境电脑上严格按README从头执行一遍。如果能一键跑通这个包就可以交了如果中途报错马上就能在打包前修复。大部分期末作业项目根本不需要用到高深算法能让人顺利跑完、看懂结论就是最高效的拿分方式。把这一步做完压缩包交出去心里就有底了。本文还有配套的精品资源点击获取