zhaogebanshang
聚合来自企业官网、招聘站点、招聘公众号等多渠道的招聘信息,统一标准化展示,帮助应届生更方便地发现校招、实习、全职机会,并跳转到原始投递页面完成投递。
用户痛点
- 很多企业只在官网招聘页发布岗位,不会同步到主流招聘平台
- 学生不知道企业官网入口,导致根本看不到岗位
- 招聘信息分散在不同站点,查找成本高
- 校招窗口期短,错过就没了
- 部分机构靠“信息差”收费,学生求职前就先承担成本
产品价值
- 聚合全网分散的招聘信息
- 降低信息获取门槛
- 给应届生提供统一入口
- 强调“只做信息聚合和导航,不代替企业招聘系统”
技术选型
- 后端:Python + FastAPI
- 数据库:MySQL
- 缓存:Redis
- 前端:Next.js
页面设计
目标非常纯粹:让学生方便地发现职位,并快速跳转到官方招聘入口。
1. 首页
作用:
- 让用户快速进入“找职位”或“找公司”
- 展示最新职位、热门公司、热门城市、校招入口
建议模块:
-
顶部搜索框
-
两个主入口:
- 找职位
- 找公司
-
最新发布职位
-
热门公司/常年招聘公司
-
按城市快速入口
-
按类型快速入口(校招 / 实习 / 全职)
2. 职位列表页
功能
-
展示职位列表
-
支持搜索职位关键词
-
支持筛选:
- 地域
- 学历
- 工作类型(全职/实习/兼职)
- 是否校招
- 公司类型/行业(后续)
- 发布时间(最近3天/7天/30天)
-
排序:
- 最新发布
- 最近更新
- 相关度
每条职位卡片展示建议
- 职位名
- 公司名
- 地点
- 学历要求
- 工作类型
- 薪资(有就显示)
- 发布时间
- 来源标识(官网 / 某平台)
- “查看详情”
3. 职位详情页
作用:
- 完整展示岗位信息
- 提供跳转官网/原投递页
建议展示:
- 职位名称
- 公司名称(可点进公司页)
- 地点
- 学历
- 经验
- 工作性质
- 薪资
- 发布时间
- 岗位职责
- 任职要求
- 福利
- 来源
- 原始链接
- 投递按钮(跳转原站)
4. 公司列表页
作用:
- 用户可以按公司维度寻找招聘入口
- 特别适合“我想看看有哪些公司在招”
建议支持:
-
搜索公司名
-
筛选地域 / 行业 / 公司类型(后续)
-
排序:
- 最近有新职位
- 招聘岗位数
- 热门公司
公司卡片建议展示
- 公司名称
- logo
- 行业
- 总部/主要城市
- 公司简介简述
- 官网入口
- 招聘入口
- 当前职位数
5. 公司详情页
“方便找到公司官网”
建议包含:
- 公司名称
- logo
- 公司介绍
- 官网链接
- 招聘官网链接
- 公司标签(行业、规模、性质)
- 当前开放职位列表
- 最近更新时间
- 可能还可以有“历年常招岗位”这种后续能力
6. 来源说明 / 关于我们 页面
建议有一个很简单的页面,说明:
- 这是招聘信息聚合站
- 职位来源于公开招聘信息
- 投递请前往原官网/原页面
- 如有错误或侵权可联系处理
这个页面虽然不直接带来流量,但很重要:
- 增加可信度
- 减少误解
- 对合规更友好
7. 反馈页面
建议有:
- 信息纠错
- 失效链接反馈
- 公司信息补充
- 合作联系
因为招聘信息很容易过期、失效、变动,用户反馈机制会非常有价值。
最简单可以只是一个:
- 反馈邮箱
- 表单页
8. 404 / 空结果页
这个也要设计好。 比如用户搜索不到职位时,不要只是空白,而要引导:
- 换关键词
- 看相似公司
- 看热门职位
9.通用组件
1.全局搜索框
可以支持搜:
- 职位关键词
- 公司名称
2. 筛选栏
职位页至少有:
- 地域
- 学历
- 工作类型
- 是否校招/实习
- 发布时间
公司页至少有:
- 公司名称
- 地域(总部/招聘地)
- 行业
- 公司类型
3. 跳转按钮
一定要明确写:
- 去官网查看
- 去原页面投递
- 查看招聘主页
避免用户误以为你站内能投递。
4. 来源标识
比如:
- 官网
- BOSS直聘
- 公司招聘系统
- 公众号整理
这个对信任感很重要。
数据库设计
目标
数据库设计要服务于这几个核心场景:
1. 展示职位
支持:
- 职位列表
- 职位详情
- 按地域/学历/工作类型/是否校招筛选
- 搜索职位关键词
2. 展示公司
支持:
- 公司列表
- 公司详情
- 查公司官网、招聘官网
- 查看公司当前开放职位
3. 聚合多来源数据
支持:
- 同一个职位来自多个来源
- 同一来源重复抓取
- 保存原始抓取数据
- 后续重新解析
4. 数据标准化与追溯
支持:
- 原始字段保留
- 解析后的标准字段展示
- 出问题时能回溯原始内容
原则
1. 原始数据和标准化数据分开
不要只存清洗后的字段。 必须保留原始数据,方便:
- 重新解析
- 修正规则
- 排查错误
- 做去重
2. 公司、职位、来源分开
因为:
- 一个公司有多个职位
- 一个职位可能有多个来源
- 一个来源可能被抓多次
3. 原文和标准值同时保留
例如:
salary_text = "15k-25k·14薪"salary_min = 15000salary_max = 25000
4. 先满足 MVP,不一开始过度设计
第一版把结构搭稳,后面再加收藏、订阅、推荐。
核心数据表
companies 公司表
用于存储公司基础信息。
用途
- 公司列表页
- 公司详情页
- 关联职位
- 展示官网/招聘官网
CREATE TABLE companies (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(255) NOT NULL COMMENT '公司名称',
alias_name VARCHAR(255) DEFAULT NULL COMMENT '公司简称/别名',
logo_url VARCHAR(500) DEFAULT NULL COMMENT '公司logo',
website_url VARCHAR(500) DEFAULT NULL COMMENT '公司官网',
career_page_url VARCHAR(500) DEFAULT NULL COMMENT '公司招聘官网/招聘入口',
industry VARCHAR(100) DEFAULT NULL COMMENT '行业',
company_type VARCHAR(100) DEFAULT NULL COMMENT '公司类型,如民企/外企/国企',
size_range VARCHAR(100) DEFAULT NULL COMMENT '公司规模,如100-499人',
headquarters VARCHAR(255) DEFAULT NULL COMMENT '总部所在地',
description TEXT DEFAULT NULL COMMENT '公司介绍',
tags JSON DEFAULT NULL COMMENT '标签,如["校招常开","大厂"]',
status TINYINT NOT NULL DEFAULT 1 COMMENT '状态:1有效 0无效',
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
UNIQUE KEY uk_name (name),
KEY idx_industry (industry),
KEY idx_company_type (company_type),
KEY idx_headquarters (headquarters)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='公司表';
jobs 职位表
这是最核心的标准化职位表。 用于前端展示、搜索、筛选。
用途
- 职位列表页
- 职位详情页
- 筛选搜索
- 按公司查看职位
CREATE TABLE jobs (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
company_id BIGINT NOT NULL COMMENT '关联公司ID',
title VARCHAR(255) NOT NULL COMMENT '职位名称',
normalized_title VARCHAR(255) DEFAULT NULL COMMENT '标准化职位名称',
department VARCHAR(255) DEFAULT NULL COMMENT '部门',
job_category VARCHAR(100) DEFAULT NULL COMMENT '职类,如技术/产品/运营',
employment_type VARCHAR(50) DEFAULT NULL COMMENT '工作类型,如全职/兼职/实习',
is_campus TINYINT NOT NULL DEFAULT 0 COMMENT '是否校招',
is_intern TINYINT NOT NULL DEFAULT 0 COMMENT '是否实习',
location_text VARCHAR(255) DEFAULT NULL COMMENT '工作地点原文',
city VARCHAR(100) DEFAULT NULL COMMENT '标准化城市',
province VARCHAR(100) DEFAULT NULL COMMENT '省份',
district VARCHAR(100) DEFAULT NULL COMMENT '区县',
location_list JSON DEFAULT NULL COMMENT '多地点列表',
education_requirement VARCHAR(255) DEFAULT NULL COMMENT '学历要求原文',
education_level VARCHAR(50) DEFAULT NULL COMMENT '标准化学历,如本科/硕士/不限',
experience_requirement VARCHAR(255) DEFAULT NULL COMMENT '经验要求原文',
experience_min_months INT DEFAULT NULL COMMENT '最低经验月数',
experience_max_months INT DEFAULT NULL COMMENT '最高经验月数',
salary_text VARCHAR(255) DEFAULT NULL COMMENT '薪资原文',
salary_min INT DEFAULT NULL COMMENT '最低薪资',
salary_max INT DEFAULT NULL COMMENT '最高薪资',
salary_unit VARCHAR(50) DEFAULT NULL COMMENT '薪资单位,如月/年/天/小时',
salary_months INT DEFAULT NULL COMMENT '几薪,如12/13/14',
salary_currency VARCHAR(20) DEFAULT 'CNY' COMMENT '币种',
job_description MEDIUMTEXT DEFAULT NULL COMMENT '岗位描述/JD',
job_requirements MEDIUMTEXT DEFAULT NULL COMMENT '任职要求',
job_responsibilities MEDIUMTEXT DEFAULT NULL COMMENT '岗位职责',
benefits TEXT DEFAULT NULL COMMENT '福利待遇',
skill_tags JSON DEFAULT NULL COMMENT '技能标签',
major_requirement VARCHAR(255) DEFAULT NULL COMMENT '专业要求',
apply_url VARCHAR(500) DEFAULT NULL COMMENT '原始投递链接',
detail_url VARCHAR(500) DEFAULT NULL COMMENT '原始职位详情链接',
source_site VARCHAR(100) DEFAULT NULL COMMENT '主来源站点',
source_job_id VARCHAR(255) DEFAULT NULL COMMENT '来源站职位ID',
published_at DATETIME DEFAULT NULL COMMENT '职位发布时间',
deadline_at DATETIME DEFAULT NULL COMMENT '截止时间',
first_seen_at DATETIME DEFAULT NULL COMMENT '首次抓取到时间',
last_seen_at DATETIME DEFAULT NULL COMMENT '最近抓取到时间',
status VARCHAR(50) NOT NULL DEFAULT 'open' COMMENT '职位状态:open/closed/expired',
is_active TINYINT NOT NULL DEFAULT 1 COMMENT '是否可展示',
quality_score INT DEFAULT NULL COMMENT '数据质量分',
dedupe_key VARCHAR(255) DEFAULT NULL COMMENT '去重键',
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
KEY idx_company_id (company_id),
KEY idx_title (title),
KEY idx_normalized_title (normalized_title),
KEY idx_city (city),
KEY idx_province (province),
KEY idx_education_level (education_level),
KEY idx_employment_type (employment_type),
KEY idx_is_campus (is_campus),
KEY idx_is_intern (is_intern),
KEY idx_status (status),
KEY idx_published_at (published_at),
KEY idx_last_seen_at (last_seen_at),
KEY idx_dedupe_key (dedupe_key),
CONSTRAINT fk_jobs_company FOREIGN KEY (company_id) REFERENCES companies(id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='标准化职位表';
job_sources 职位来源表
这个表用于记录:
- 一个职位是从哪里来的
- 是否官网来源
- 是否主来源
- 多来源关联
- 来源链接、来源ID
为什么这个表必须有
因为同一个职位可能:
- 来自公司官网
- 又出现在某招聘站点
- 或者你重复抓了多次
职位主表应该保留“标准化结果”, 来源表专门记录“来源关系”。
CREATE TABLE job_sources (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
job_id BIGINT NOT NULL COMMENT '关联职位ID',
source_site VARCHAR(100) NOT NULL COMMENT '来源站点',
source_type VARCHAR(50) DEFAULT NULL COMMENT '来源类型:官网/招聘站/公众号',
source_job_id VARCHAR(255) DEFAULT NULL COMMENT '来源站职位ID',
source_url VARCHAR(500) DEFAULT NULL COMMENT '来源详情页链接',
apply_url VARCHAR(500) DEFAULT NULL COMMENT '来源投递链接',
is_official TINYINT NOT NULL DEFAULT 0 COMMENT '是否官网源',
is_primary_source TINYINT NOT NULL DEFAULT 0 COMMENT '是否主来源',
published_at DATETIME DEFAULT NULL COMMENT '来源发布时间',
first_seen_at DATETIME DEFAULT NULL COMMENT '首次抓到该来源时间',
last_seen_at DATETIME DEFAULT NULL COMMENT '最近抓到该来源时间',
record_hash VARCHAR(255) DEFAULT NULL COMMENT '来源内容哈希',
status VARCHAR(50) NOT NULL DEFAULT 'active' COMMENT '来源状态',
raw_record_id BIGINT DEFAULT NULL COMMENT '关联原始抓取记录ID',
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
KEY idx_job_id (job_id),
KEY idx_source_site (source_site),
KEY idx_source_job_id (source_job_id),
KEY idx_is_official (is_official),
KEY idx_raw_record_id (raw_record_id),
CONSTRAINT fk_job_sources_job FOREIGN KEY (job_id) REFERENCES jobs(id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='职位来源表';
raw_job_records 原始抓取表
这个表非常重要。 存你抓到的原始内容。
作用
- 保留原始 HTML / JSON / 文本
- 排查解析错误
- 重新跑标准化逻辑
- 做内容比对和去重
CREATE TABLE raw_job_records (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
source_site VARCHAR(100) NOT NULL COMMENT '来源站点',
source_type VARCHAR(50) DEFAULT NULL COMMENT '来源类型:官网/招聘站/公众号',
source_url VARCHAR(500) DEFAULT NULL COMMENT '抓取页面URL',
source_job_id VARCHAR(255) DEFAULT NULL COMMENT '来源站职位ID',
fetch_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '抓取时间',
http_status INT DEFAULT NULL COMMENT '抓取HTTP状态码',
content_type VARCHAR(50) DEFAULT NULL COMMENT '内容类型:html/json/text',
raw_title VARCHAR(500) DEFAULT NULL COMMENT '原始标题',
raw_text MEDIUMTEXT DEFAULT NULL COMMENT '提取后的原始正文文本',
raw_html MEDIUMTEXT DEFAULT NULL COMMENT '原始HTML',
raw_json JSON DEFAULT NULL COMMENT '原始JSON结构',
raw_fields JSON DEFAULT NULL COMMENT '解析前的原始字段映射',
content_hash VARCHAR(255) DEFAULT NULL COMMENT '原始内容哈希',
parse_status VARCHAR(50) NOT NULL DEFAULT 'pending' COMMENT '解析状态:pending/success/failed',
parse_error TEXT DEFAULT NULL COMMENT '解析错误信息',
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
KEY idx_source_site (source_site),
KEY idx_source_job_id (source_job_id),
KEY idx_fetch_time (fetch_time),
KEY idx_parse_status (parse_status),
KEY idx_content_hash (content_hash)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='原始抓取记录表';
系统设计
项目结构
zhaogebanshang/
├── crawler/ # 爬虫模块(独立运行)
│ ├── config/
│ │ └── sites.json # 站点配置(核心:加站点只改这里)
│ ├── fetchers/
│ │ ├── static_fetcher.py # requests + lxml
│ │ ├── dynamic_fetcher.py # Playwright
│ │ └── api_fetcher.py # 直调接口
│ ├── parsers/
│ │ └── {company_name}.py # 每个站点一个解析文件
│ ├── processors/
│ │ ├── normalizer.py # 标准化(城市/学历/薪资)
│ │ └── deduplicator.py # 去重
│ ├── storage/
│ │ └── db_writer.py # 写库
│ ├── scheduler.py # 主调度入口
│ └── requirements.txt
│
├── api/ # FastAPI 后端
│ ├── routers/
│ │ ├── jobs.py
│ │ └── companies.py
│ ├── models/ # Pydantic 模型
│ ├── db.py # 数据库连接
│ └── main.py
│
└── frontend/ # Next.js
💬 评论