案例 03 · 数据产品 · 毕业设计

薪资分析预测系统:拆掉后端,做成一张纯静态的网站

从爬虫采集、Spark 清洗分析,到六维可视化、薪资预测和 AI 岗位匹配。 为了让招聘方点开链接就能看,我把它从 Django + MySQL 改造成了 333 个不需要任何服务的静态页面。

我的角色
独立完成:采集 · 分析 · 后端 · 前端 · 部署
数据规模
采集 2 万+ 条,上线快照保留 10560 条岗位全量
技术栈
Python 爬虫 · Spark / Scala · Django · MySQL · ECharts
线上地址
itjobs.pages.dev

一句话摘要

IT 岗位的薪资信息散落在招聘平台上,求职者想知道「我这个城市、这个学历、 这个经验年限,大概值多少钱」,只能一页页翻岗位自己猜。

这个系统把这件事做完了:爬取岗位数据 → Spark 分布式清洗与统计 → 六个维度的交互式可视化 → 随机森林薪资预测 → 接入 DeepSeek 的简历与岗位匹配。

六个分析维度,加两个「不只是看图」的模块

模块它回答的问题
薪资情况不同学历 × 经验年限下,薪资区间怎么变
企业情况不同类型的公司都在招什么岗、给多少钱
学历分布这个岗位到底卡不卡学历
企业融资融资阶段的公司薪资是否更有竞争力
城市类型一线 / 新一线 / 二线的岗位需求差异
福利词云JD 里被反复提到的福利关键词是什么
薪资预测输入城市、学历、经验、公司类型,直接给出预测薪资
AI 岗位匹配上传简历,由大模型解析并与岗位做匹配打分和 JD 分析

前六个是「看得懂数据」,后两个才是「能帮你做决定」—— 这也是我在这个项目里最在意的部分。

关键决策:把后端拆掉

原系统是 Django + MySQL,要跑起来得有服务器和数据库。 这在答辩时没问题,但它带来一个很实际的后果: 我把链接发给面试官,对方点开看到的是一张打不开的页面。

所以我做了一个决定:把整个系统在本地离线渲染成静态页面, 不接数据库、不做后端,发布到 Cloudflare Pages。 代价是放弃一部分动态能力,换来的是「任何人点开链接就能看」。

最难的一块:让薪资预测在纯静态环境里活下来

静态化本身不难,难的是那些依赖后端的交互。最先保不住的就是薪资预测—— 它原本是提交表单、后端调用随机森林模型、返回结果。 没有后端,这个功能按理说应该直接砍掉。

我换了个思路:模型只有四个输入项——城市、学历、经验、公司类型。 它们的组合数是有限的,一共 6720 种。 与其在线调模型,不如把这 6720 种组合的预测结果提前算好写进页面, 用户点「开始预测」时直接在浏览器里查表出结果。

这本质上是一次成本、延迟与质量的取舍: 预计算的代价是产物变大、也无法覆盖新的输入组合; 换来的是零推理成本、零等待,以及在任意静态托管上都能跑起来。 对「发给别人看一眼」这个场景来说,这个交换明显划算。

同样处理的还有筛选和分页:原本是 GET 参数,现在全部预生成为页面之间的跳转。 最终产物是 333 个 HTML 页面,数据概览里 10560 条岗位一条不少, 分页、筛选、预测都能真点。

脱敏:要公开,先得干净

这份数据来自真实招聘平台,里面带着真实的人。所以我先做了脱敏, 再考虑发布:

  • 招聘者姓名与职务(数万行)统一替换为「招聘者」
  • 用户表里的真实用户名(原本是手机号之类)改成「用户 8」「用户 11」
  • 用户密码(MD5)与真实头像全部清除,不进入产物
  • 手机号字段根本不写进数据库,因此不会出现在任何页面上

做完这些之后,我又对最终 609 个文件做了一轮正则扫描—— 手机号、32 位哈希、API Key、内网 IP、邮箱、姓名模式,确认没有命中才发布。

这件事让我意识到一个容易被忽略的点:作品集的公开范围,是一个需要主动决定的产品决策, 不是做完顺手一传的事。带真实个人信息的演示数据,传上去的那一刻就收不回来了。

静态版的边界,我也写在页面上

拆掉后端之后,有几处功能确实用不了。我没有把它们藏起来或者做成假按钮:

  • AI 岗位匹配不可用——它需要调用 DeepSeek 的后端接口。 点击时页面会明确提示「静态演示版:AI 功能需要 DeepSeek 后端接口,此处未启用」。
  • 登录 / 注册 / 修改密码保留页面但只做展示,提交时说明需要后端数据库。
  • 历史记录保留页面,写库动作不生效。

我的判断是:一个产品的边界和它的能力同样重要。 与其让面试官点进去发现是假的,不如直接写清楚哪里是演示、哪里是真的。

截图

下面是静态版实际运行的样子,可以直接去 itjobs.pages.dev 点。

系统首页截图
① 首页 —— 六个可视化模块的入口,以及数据概览和 AI 岗位匹配。
薪资情况分析截图
② 薪资情况 —— 按学历和经验筛选,图表随筛选变化。 静态版里这些筛选是预生成好的页面跳转。
薪资预测截图
③ 薪资预测 —— 原本依赖后端模型推理,现在靠预计算的 6720 种组合在浏览器里直接出结果。
AI 岗位匹配截图
④ AI 岗位匹配 —— 接入 DeepSeek 做简历解析和岗位打分。 这一块需要后端接口,所以在静态版里是明确标注为不可用的。

如果重来一次

踩过的坑里有两个值得说,因为它们都不是技术问题,而是流程问题。

第一个:我一开始手工改了十几个已生成的页面,结果重跑构建时全部被覆盖, 页面上出现一批死链。教训很直接——对产物做的手工修改,一定要先回到生成它的脚本里, 否则下一次构建就是一次事故。

第二个:打包时用了 PowerShell 的 Compress-Archive, 它写出的条目名是用反斜杠分隔的,Cloudflare 会把整个路径当成文件名, 结果 static/ 目录下全部 404。改用 Python 的 zipfile 手动指定正斜杠之后就正常了。 这件事让我明白,部署链路上的细节和功能本身一样会影响成败, 而且它们的失败方式往往是「看起来部署成功了,实际全是坏的」。

至于 AI 岗位匹配,如果重做,我会把它和薪资预测放在同等优先级: 前者是「大模型能做什么」的展示,后者是「不用大模型也能做得更好」的展示, 两者放在一起才是完整的产品判断。

说明

数据来自公开招聘平台,仅供学习研究使用。已对招聘者信息、用户账号、 联系方式等完成脱敏,产物中不含任何真实个人信息。 本项目为毕业设计,AI 匹配模块在静态演示版中未启用后端接口。