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 = 15000
  • salary_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='原始抓取记录表';

系统设计

image-ab8e416d

项目结构

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

项目分区导航爬虫系统建设实战 ⬅️ | 04-zhaogebanshang | ➡️ 学习顺序