news 2026/9/24 20:04:05

Python招聘数据分析与可视化:从CSV清洗到Echarts大屏实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Python招聘数据分析与可视化:从CSV清洗到Echarts大屏实战

简介:这是一套基于Python实现的招聘网站数据分析与可视化项目源码,面向计算机相关专业的毕业设计、期末大作业与课程设计场景,也适合想通过完整案例入门数据分析的初学者。项目已通过老师指导并取得高分,代码为纯手写实现,实战门槛较低。压缩包共54个文件,约6.68MB,包含4个py脚本与4个ipynb笔记本用于数据获取、清洗与分析,8个csv存放前程无忧等招聘原始数据,另有html、js、css等前端文件支撑Echarts大屏展示,以及png、jpg图表与词云素材、xml配置和字体文件。目录按数据获取、数据清洗、数据分析、数据可视化、Echarts大屏展示等模块划分,结构清晰。目前已有573人学习下载。读者可据此掌握招聘信息的采集、清洗、统计与可视化全流程,直接复用词云图、工作经验与学历分布饼图等成果,并参考大屏展示方案快速完成自己的项目。

1. 从一份招聘 CSV 到能跑的大屏:这套 Python 数据分析源码到底能干什么

如果你手头正压着一个「招聘网站数据分析及数据可视化」的课设或毕设,大概率卡在同一个地方:爬虫能跑,但数据脏得没法看;图表能画,但拼不成一张能交差的大屏。这套基于 Python 的招聘网站数据分析及数据可视化源码,解决的正是从原始 CSV 到可视化大屏的完整链路问题。它把数据获取、数据清洗、数据分析、可视化展示拆成了四个独立目录,每个环节都有对应的 ipynb 和 py 文件,不是那种只丢一个 notebook 的半成品。适合两类人:一是需要快速交付课程设计的学生,二是想拿真实招聘数据练手 pandas 和 Echarts 的入门开发者。下面我按实际拆包顺序,把每个模块的用法和坑讲清楚。

2. 数据获取与清洗:前程无忧 CSV 怎么从脏数据变成可用表

2.1 数据获取目录里的三个脚本各管什么

打开数据获取文件夹,能看到前程无忧.py中国大学.py测试.py三个文件,外加两份 CSV。这里的分工很明确:前程无忧.py负责抓取招聘岗位信息,中国大学.py大概率是抓取院校维度数据用于交叉分析,测试.py是调试用的临时脚本。我一般会先看测试.py,因为它通常保留了最原始的请求逻辑,能快速判断目标站点当前的结构有没有变。

# 前程无忧.py 典型结构(根据目录推断的常见写法) import requests from bs4 import BeautifulSoup import pandas as pd def get_page(url): headers = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36" } resp = requests.get(url, headers=headers, timeout=10) resp.encoding = "gbk" # 前程无忧老页面常用 gbk,不设会乱码 return resp.text def parse_jobs(html): soup = BeautifulSoup(html, "html.parser") items = soup.select(".j_joblist .e") # 岗位卡片选择器,站点改版会失效 rows = [] for item in items: rows.append({ "岗位": item.select_one(".jname").get_text(strip=True), "公司": item.select_one(".cname").get_text(strip=True), "薪资": item.select_one(".sal").get_text(strip=True), "地点": item.select_one(".d.at").get_text(strip=True), }) return rows if __name__ == "__main__": all_data = [] for page in range(1, 11): # 翻 10 页,别贪多,容易被限 html = get_page(f"https://search.51job.com/list/000000,000000,0000,00,9,99,python,2,{page}.html") all_data.extend(parse_jobs(html)) pd.DataFrame(all_data).to_csv("前程无忧.csv", index=False, encoding="utf-8-sig")

这段代码的关键参数有三个:encoding="gbk"不设会得到一堆问号;timeout=10防止单页卡死拖垮整个循环;encoding="utf-8-sig"写 CSV 时用,保证 Excel 打开不乱码。翻页范围我建议控制在 10 页以内,超过之后返回空列表的概率明显上升,这是血泪经验。

2.2 数据清洗.ipynb 里的四步标准流程

数据清洗目录下的数据清洗.ipynb是整个项目最值得细看的部分。它处理的输入是前程无忧.csv,输出是干净的招聘信息.csv。我拆开看,核心就四步:去重、去空、薪资字段结构化、地点字段归一化。

import pandas as pd import re df = pd.read_csv("前程无忧.csv") # 第一步:按岗位+公司去重,招聘网站重复投放很常见 df = df.drop_duplicates(subset=["岗位", "公司"]) # 第二步:丢掉关键字段为空的行 df = df.dropna(subset=["岗位", "薪资", "地点"]) # 第三步:薪资区间拆成最低和最高两列,单位统一为千/月 def parse_salary(s): s = str(s).replace("万/月", "0000").replace("千/月", "000") nums = re.findall(r"\d+", s) if len(nums) >= 2: return int(nums[0]), int(nums[1]) return None, None df[["薪资下限", "薪资上限"]] = df["薪资"].apply( lambda x: pd.Series(parse_salary(x)) ) # 第四步:地点只保留城市名,去掉区级后缀 df["城市"] = df["地点"].str.split("-").str[0] df.to_csv("招聘信息.csv", index=False, encoding="utf-8-sig")

parse_salary这个函数是清洗环节最容易翻车的地方。前程无忧的薪资写法至少有五种:1.5-2万/月8-10千/月15-20万/年200元/天面议。上面这段只覆盖了前两种,遇到年薪和日薪会返回 None。常见做法是再加一层判断,把「万/年」除以 12 换算成月薪,把「元/天」乘以 21.75 换算成月薪。面议直接丢弃,不要试图填充,填充出来的数字会污染后续的薪资分布分析。

提示:清洗后的招聘信息.csv才是后续所有分析和可视化的输入,不要跳过这一步直接拿原始 CSV 画图,否则学历饼图里会出现「学历不限」「不限」两个几乎一样的扇区。

3. 数据分析与词云:从招聘信息里挖出学历、经验和福利关键词

3.1 数据分析.ipynb 的三个分析维度

数据分析.ipynb承接清洗后的招聘信息.csv,主要做三件事:学历分布统计、工作经验分布统计、福利关键词提取。这三个维度对应后面三张核心图表,是整个项目的分析骨架。

import pandas as pd from collections import Counter import jieba df = pd.read_csv("招聘信息.csv") # 学历分布:value_counts 直接出频次 edu_dist = df["学历"].value_counts() print(edu_dist) # 工作经验分布:注意字段里可能有「经验不限」「1年以下」等混合值 exp_dist = df["工作经验"].value_counts() # 福利词云:把福利字段拼接后分词统计 all_welfare = " ".join(df["福利"].dropna().astype(str)) words = jieba.lcut(all_welfare) # 过滤掉单字和常见停用词 stopwords = {"的", "和", "等", "有", "无", "不限"} word_freq = Counter([w for w in words if len(w) > 1 and w not in stopwords]) with open("福利词云图.txt", "w", encoding="utf-8") as f: for word, freq in word_freq.most_common(100): f.write(f"{word} {freq}\n")

value_counts()默认按频次降序,直接喂给饼图就行。词云这部分的关键在停用词表,这类词不滤掉,词云图会被它们占满,真正的「五险一金」「带薪年假」「年终奖」反而被挤小。word_freq.most_common(100)取前 100 个词写入 txt,这个 txt 就是后面词云图的输入。

3.2 词云图.ipynb 的字体与蒙版参数

数据可视化目录下的词云图.ipynb读取福利词云图.txt招聘信息词云图.txt,生成带形状的词云。目录里那几张蜡笔小新.jpg哆啦A梦.jpg就是蒙版图,用来控制词云的轮廓。

from wordcloud import WordCloud import numpy as np from PIL import Image # 读取蒙版图,非白区域才会填词 mask = np.array(Image.open("蜡笔小新.jpg")) # 读取词频文件 freq = {} with open("福利词云图.txt", encoding="utf-8") as f: for line in f: word, count = line.strip().split() freq[word] = int(count) wc = WordCloud( font_path="C:/Windows/Fonts/simhei.ttf", # 不指定中文字体全是方块 background_color="white", mask=mask, max_words=150, max_font_size=120, colormap="viridis" ) wc.generate_from_frequencies(freq) wc.to_file("福利词云图.png")

font_path是词云图最大的坑,不指定中文字体,生成出来全是豆腐块。Windows 用simhei.ttf,Mac 换成/System/Library/Fonts/PingFang.ttcmask参数要求蒙版图的背景是纯白,如果蒙版图背景带一点灰,词会填到轮廓外面去。max_words=150控制词的数量,太多会糊成一团,太少又看不出分布。

3.3 饼图.py 与 HTML 输出的分工

饼图.py是独立脚本,生成工作经验饼图.html学历.html。这里用的是 pyecharts,不是 matplotlib。选 pyecharts 的理由很实际:输出的 HTML 可以直接嵌进大屏,交互式悬停显示数值,比静态 PNG 好看得多。

from pyecharts import options as opts from pyecharts.charts import Pie import pandas as pd df = pd.read_csv("招聘信息.csv") edu = df["学历"].value_counts() pie = ( Pie() .add("", [list(z) for z in zip(edu.index.tolist(), edu.values.tolist())]) .set_global_opts(title_opts=opts.TitleOpts(title="学历分布")) .set_series_opts(label_opts=opts.LabelOpts(formatter="{b}: {c} ({d}%)")) ) pie.render("学历.html")

formatter="{b}: {c} ({d}%)"里的{b}是类别名,{c}是数值,{d}是百分比,这三个占位符是 pyecharts 的固定写法,改顺序可以,改字母会报错。render输出的 HTML 自带 echarts.min.js 的 CDN 引用,离线打开会白屏,这是后面大屏部署时要注意的点。

4. Echarts 大屏展示:把散落的 HTML 拼成一张能交差的页面

4.1 myEcharts 目录的结构与入口文件

Echarts大屏展示下的myEcharts是整个项目的门面。它不是一个单独的 HTML,而是一组文件配合:入口 HTML、样式 CSS、数据 JS,可能还有几张背景图。我一般先找index.html,打开看它引了哪些 JS 和 CSS,就能反推出数据从哪来。

<!-- index.html 典型结构 --> <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <link rel="stylesheet" href="css/style.css"> <script src="js/echarts.min.js"></script> <!-- 本地引入,不依赖 CDN --> </head> <body> <div id="eduChart" style="width:600px;height:400px;"></div> <div id="expChart" style="width:600px;height:400px;"></div> <script src="js/data.js"></script> <script src="js/chart.js"></script> </body> </html>

关键点是echarts.min.js用本地引入而不是 CDN。很多同学直接把 pyecharts 生成的 HTML 往大屏里嵌,结果一断网就白屏,答辩现场翻车。正确做法是把 echarts.min.js 下载到js目录,所有图表共用一份。

4.2 数据对接:从 CSV 到 JS 数组的转换

大屏里的图表数据不是实时读 CSV 的,而是提前转成 JS 数组写进data.js。转换方式有两种:手动复制,或者写个 Python 脚本自动生成。

import pandas as pd import json df = pd.read_csv("招聘信息.csv") edu = df["学历"].value_counts() # 转成 echarts 需要的 [{name: "本科", value: 120}, ...] 格式 data = [{"name": k, "value": int(v)} for k, v in edu.items()] with open("data.js", "w", encoding="utf-8") as f: f.write("var eduData = " + json.dumps(data, ensure_ascii=False) + ";")

ensure_ascii=False必须加,否则中文会变成\u672c\u79d1这种转义序列,虽然浏览器能解析,但调试时看着头疼。生成的data.js里就是一个全局变量eduDatachart.js里直接引用即可。

4.3 大屏自适应与分辨率适配

大屏最常见的翻车是换台电脑就错位。原因是图表容器用了固定像素宽高,而不同屏幕的缩放比例不一样。常见做法是用 rem 或者 vw/vh 做相对单位,配合window.onresize重绘。

// chart.js 里的自适应逻辑 var eduChart = echarts.init(document.getElementById('eduChart')); eduChart.setOption({ series: [{ type: 'pie', data: eduData }] }); window.onresize = function() { eduChart.resize(); // 窗口变化时重绘,不加重绘会拉伸变形 };

resize()这个方法不调用,图表在窗口缩放后不会跟着变,而是保持初始尺寸被拉伸,饼图会变成椭圆。如果大屏里有多个图表,每个实例都要单独调resize(),或者用echarts.connect统一管理。

注意:答辩用的投影仪分辨率通常是 1024x768 或 1280x720,开发时按 1920x1080 做的大屏投上去会溢出。我一般把设计稿按 1280 宽做,再用 CSS 的transform: scale()适配大屏,这样两边都不吃亏。

5. 避坑与排查:这套源码跑不起来时先查这五处

5.1 现象:前程无忧.py返回空列表,CSV 只有表头

原因:目标站点改版,.j_joblist .e这个选择器失效,或者请求头被识别。解决:先用测试.py单独请求一页,把resp.text打印出来看结构,用浏览器的开发者工具重新定位岗位卡片的选择器。如果返回的是验证页,说明请求频率过高,把翻页间隔加到 3 秒以上。

5.2 现象:词云图全是方块,一个中文都看不到

原因:WordCloudfont_path没设,或者设了一个不存在的路径。解决:Windows 确认C:/Windows/Fonts/simhei.ttf存在,Mac 用/System/Library/Fonts/PingFang.ttc。路径里的斜杠用正斜杠,反斜杠在 Python 字符串里是转义符,会报错。

5.3 现象:pyecharts 生成的 HTML 打开是空白页

原因:pyecharts 默认引用在线 CDN 的 echarts.min.js,断网或 CDN 被墙时加载失败。解决:在render之前调pie.render("学历.html")后手动把 HTML 里的 CDN 地址换成本地路径,或者用CurrentConfig.ONLINE_HOST指定本地资源目录。

5.4 现象:薪资分析结果明显偏低,大量岗位薪资为 0

原因:parse_salary没覆盖「万/年」和「元/天」两种格式,返回 None 后被填充成 0。解决:在函数里加分支判断,遇到「万/年」先乘 10000 再除以 12,遇到「元/天」乘 21.75。填充 0 是最坏的选择,会让薪资分布图整体左移。

5.5 现象:大屏在别人电脑上打开,图表全部叠在一起

原因:CSS 用了绝对定位但没设z-index,或者容器宽高用了百分比但父元素没有明确高度。解决:给每个图表容器设position: relative和明确的height,父容器用 flex 布局而不是绝对定位。如果必须绝对定位,给每个图表加不同的z-index

6. 进阶技巧:用 pyecharts 的 Timeline 做动态学历变化图

基础饼图只能展示某一时刻的学历分布,但招聘数据里往往带时间维度。如果 CSV 里有「发布日期」字段,可以用 pyecharts 的Timeline做按季度播放的动态图,答辩时比静态图多一个记忆点。

from pyecharts.charts import Pie, Timeline import pandas as pd df = pd.read_csv("招聘信息.csv") df["季度"] = pd.to_datetime(df["发布日期"]).dt.to_period("Q") timeline = Timeline() for quarter in df["季度"].unique(): sub = df[df["季度"] == quarter]["学历"].value_counts() pie = ( Pie() .add("", [list(z) for z in zip(sub.index.tolist(), sub.values.tolist())]) .set_global_opts(title_opts=opts.TitleOpts(title=f"{quarter} 学历分布")) ) timeline.add(pie, str(quarter)) timeline.render("学历变化时间轴.html")

to_period("Q")把日期转成季度,Timeline.add的第二个参数是时间轴上的标签。播放速度用timeline.add_schema(play_interval=1000)控制,1000 毫秒一帧,太快看不清,太慢答辩时间不够。这个技巧的边界是:数据量少于 4 个季度时,时间轴只有三四帧,动画效果不明显,不如直接画分组柱状图。

还有一个验证技巧:跑完所有 notebook 后,用招聘信息.csv的行数反推清洗保留率。如果原始 CSV 有 5000 行,清洗后只剩 800 行,说明去重和去空太激进,可能把有效数据也丢了。我一般把保留率控制在 60% 以上,低于这个数就回头检查dropna的 subset 是不是设多了。

从那以后我每次拿到这类项目,都强制先跑一遍数据清洗.ipynb看保留率,再动可视化。希望帮到你。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/24 20:03:21

YashanDB数据利用率提升指南:从分区、索引到SQL优化的实战技巧

干了十多年数据库运维&#xff0c;我见过太多项目上线时各种指标都很好看&#xff0c;但跑上几个月之后就完全变了样&#xff1a;磁盘空间报警、报表查询越来越慢、业务方天天抱怨“数据都在库里&#xff0c;为什么就是调不出来”。这种问题不是数据库“容量不够”&#xff0c;…

作者头像 李华
网站建设 2026/9/24 20:02:48

2026国产大模型客户端深度测评:九大势力多模态与智能体能力横向对比

1. 国产大模型客户端测评的背景与选型逻辑1.1 为什么客户端体验成了分水岭2026年这个时间节点回头看&#xff0c;国产大模型在底层能力上的差距已经明显收窄。各家旗舰模型的跑分你追我赶&#xff0c;MMLU、C-Eval、数学推理、代码生成这些硬指标拉不开代差。真正让用户用脚投票…

作者头像 李华
网站建设 2026/9/24 20:02:43

元数据管理平台选型指南:OpenMetadata、DataHub、Atlas、Gravitino 横向对比

1. 四款元数据平台选型的真实背景 数据治理这个领域&#xff0c;做了几年之后你会发现一个规律&#xff1a;真正难的不是采集数据&#xff0c;而是搞清楚"我们到底有哪些数据、它们长什么样、谁在用、从哪来到哪去"。元数据管理平台就是干这个的。过去几年里&#xf…

作者头像 李华
网站建设 2026/9/24 20:02:33

中小制造企业DeepSeek私有化部署:边缘AI质检实战指南

简介&#xff1a;这份PDF文档面向中小制造企业的技术负责人、AI工程师与数字化转型实践者&#xff0c;系统讲解如何将DeepSeek私有化部署并落地为AI质检系统。内容从质检现状与需求分析切入&#xff0c;覆盖硬件与软件环境准备、数据收集与预处理、DeepSeek模型选型与微调、系统…

作者头像 李华
网站建设 2026/9/24 20:02:00

数据库国产化升级实战:从分库分表到TiDB的迁移之路

去年双十一晚上&#xff0c;一个做零售系统的朋友给我打电话&#xff0c;说他们新上的数据库集群在零点峰值算是稳住了&#xff0c;但代价是整整半年都在做分库分表改造&#xff0c;业务代码改得面目全非。而这只是国产化升级浪潮里再普通不过的一个缩影。3月14日&#xff0c;T…

作者头像 李华
网站建设 2026/9/24 20:01:59

Fusion 360 英汉速查表:建模、装配、CAM与STL单位核心术语详解

1. 为什么你需要一份英汉速查表1.1 英文界面不是门槛&#xff0c;而是学习路径很多刚接触 Fusion 360 的朋友&#xff0c;第一次打开软件就是一脸懵。整个界面全是英文&#xff0c;建模这边是 Sketch、Extrude、Revolve&#xff0c;那边是 Assemble、Constraint、Joint&#xf…

作者头像 李华