# JobData - 招聘数据采集与统计分析平台 ## 变更记录 (Changelog) | 版本 | 日期 | 说明 | |------|------|------| | 初始化 | 2026-03-20 | 首次生成架构文档,覆盖全部四个核心模块 | --- ## 项目愿景 JobData 是一个面向招聘市场的全栈数据采集与分析平台。系统从三大主流招聘平台(Boss 直聘、前程无忧、智联招聘)自动抓取职位与公司数据,统一存储到 ClickHouse 列式数据库,并通过 FastAPI 后端 + Vue3 前端提供数据查看、定向清洗、统计分析等能力。ECS 弹性实例管理模块支持在阿里云上按需批量启停爬虫节点。 --- ## 架构总览 ``` [招聘平台] [爬虫层] [后端 API] [数据库] Boss直聘 ──► jobs_spider/boss/ ──► ┌── MySQL 前程无忧 ──► jobs_spider/qcwy/ ──► app (FastAPI) ──► └── ClickHouse 智联招聘 ──► jobs_spider/zhilian/ ──► ▲ │ web (Vue3) ────────┘ (前端页面) ecs_full_pipeline.py ──► 阿里云 ECS ──► 批量启动爬虫节点 ``` **核心技术栈** | 层次 | 技术 | |------|------| | 后端 | Python 3.13, FastAPI 0.111, Tortoise-ORM 0.23, APScheduler | | 数据库(业务) | MySQL(用户/权限/审计/关键词/Token) | | 数据库(采集) | ClickHouse(职位/公司 JSON 原始数据 + 分析视图) | | 爬虫 | requests / httpx / Playwright(Python 脚本) | | 前端 | Vue 3.3, Vite 4, Naive UI, Pinia, ECharts | | 基础设施 | 阿里云 ECS(按量抢占实例),APScheduler 定时任务 | --- ## 模块结构图 ```mermaid graph TD ROOT["(根) JobData"] --> APP["app - FastAPI 后端"] ROOT --> WEB["web - Vue3 前端"] ROOT --> SPIDER["jobs_spider - 平台爬虫"] ROOT --> ECS["ecs_full_pipeline.py - ECS 批量部署"] APP --> APP_API["app/api - 路由层"] APP --> APP_SVC["app/services - 业务逻辑"] APP --> APP_CORE["app/core - 框架核心"] APP --> APP_MODELS["app/models - ORM 模型"] APP --> APP_REPO["app/repositories - 数据仓库"] SPIDER --> SP_BOSS["jobs_spider/boss"] SPIDER --> SP_QCWY["jobs_spider/qcwy"] SPIDER --> SP_ZL["jobs_spider/zhilian"] click APP "./app/AGENTS.md" "查看 app 模块文档" click WEB "./web/AGENTS.md" "查看 web 模块文档" click SPIDER "./jobs_spider/AGENTS.md" "查看 jobs_spider 模块文档" ``` --- ## 模块索引 | 模块路径 | 语言 | 职责简述 | |----------|------|----------| | `app/` | Python | FastAPI 后端,提供 REST API、权限管理、定时任务、数据入库与分析 | | `web/` | Vue3/JS | 前端管理界面,数据展示、关键词管理、代理管理、数据清洗操作 | | `jobs_spider/` | Python | 三大平台的爬虫脚本,独立运行,结果通过 HTTP 推送到后端 | | `ecs_full_pipeline.py` | Python | 阿里云 ECS 实例批量创建/销毁/命令下发全流程脚本 | | `reclean_qcwy_jobs.py` | Python | 前程无忧数据重清洗独立脚本 | --- ## 运行与开发 ### 后端启动 ```bash # 安装依赖(pipenv) pipenv install # 开发模式(默认端口 9999,20 个 worker) python run.py # 环境变量覆盖 APP_HOST=0.0.0.0 APP_PORT=9999 UVICORN_WORKERS=4 python run.py ``` **关键环境变量** | 变量 | 默认值 | 说明 | |------|--------|------| | `APP_HOST` | `0.0.0.0` | 监听地址 | | `APP_PORT` | `9999` | 监听端口 | | `UVICORN_WORKERS` | `20` | Worker 数量 | | `CLICKHOUSE_HOST` | `121.4.126.241` | ClickHouse 地址(需修改为实际地址) | | `CLICKHOUSE_USER` / `CLICKHOUSE_PASS` | 见 config.py | ClickHouse 认证 | | `SMTP_HOST` / `SMTP_USER` / `SMTP_PASS` | 见 config.py | 邮件告警配置 | | `REPORT_ENDPOINT` | 空 | 统计结果 Webhook 上报地址 | | `RUN_MIGRATIONS_ON_STARTUP` | `True` | 是否启动时自动迁移 | | `INITIALIZE_SEED_DATA_ON_STARTUP` | `True` | 是否启动时初始化种子数据 | > 安全警告:`config.py` 中 `SECRET_KEY`、数据库连接串、SMTP 密码均为硬编码默认值,生产环境必须通过环境变量覆盖。 ### 前端启动 ```bash cd web pnpm install pnpm dev # 开发模式,默认 http://localhost:5173 pnpm build # 构建产物到 web/dist ``` ### ECS 批量爬虫部署 ```bash # 需配置阿里云凭据(环境变量或 ~/.alibabacloud/credentials) python ecs_full_pipeline.py ``` --- ## 定时任务 APScheduler 在应用启动时注册以下任务(`app/core/scheduler.py`): | 任务 ID | 频率 | 职责 | |---------|------|------| | `stats_job` | 每 6 小时 | 统计 ClickHouse 各表总量并通过邮件/Webhook 上报 | | `ecs_full_pipeline` | 每 6 小时 | 调用 `ecs_full_pipeline.py` 批量刷新爬虫节点 | | `ip_alert_job` | 每 10 分钟 | 检查 IP 上报异常并告警 | | `company_cleaning_job` | 每 5 分钟 | 自动清洗待处理公司数据(collect 50 + process 30) | | `daily_cleanup_job` | 每天 00:05 | 清理历史任务运行记录 | 所有任务通过分布式文件锁(或可选 Redis 锁)保证多 Worker 下只执行一次。 --- ## 测试策略 - 当前代码库**无自动化测试文件**(缺口:单元测试、集成测试均缺失)。 - 推荐补充: 1. `app/services/` 的 service 层单元测试(使用 `pytest` + `anyio`) 2. `app/api/v1/` 的 API 集成测试(使用 `httpx.AsyncClient`) 3. `jobs_spider/` 的数据解析函数单元测试 --- ## 编码规范 - Python:使用 `ruff`(已在 Pipfile 中),格式化用 `black`,排序用 `isort`。 - 前端:ESLint(`@zclzone` + `@unocss` 规则集),`prettier` 格式化。 - 类型:后端强制 `pydantic` Schema 做入参校验;前端以 JS 为主(未启用严格 TS)。 - 日志:后端统一使用 `loguru`,结构化字段 `logger.info(...)` 方式输出。 --- ## AI 使用指引 - 修改爬虫逻辑时,重点关注反爬机制:`SmartIPManager`、`IPAnomalyDetector` 在 `jobs_spider/boss/boos_api.py` 中实现,随机延迟至少 10 秒。 - 新增 API 路由后需同步在 `app/api/v1/__init__.py` 注册,并执行 `api_controller.refresh_api()` 更新权限表。 - ClickHouse 表结构变更在 `app/core/clickhouse_init.py` 中维护,**不走 Aerich 迁移**。 - MySQL 模型变更走 Aerich(`aerich migrate && aerich upgrade`)。 - 前端新增页面需要在 `web/src/views/{模块}/route.js` 和后端 `init_menus()` 中同步注册菜单。 - `config.py` 中已硬编码真实 MySQL/ClickHouse 连接串和 SMTP 凭据,**提交代码前务必确认不泄露敏感信息**。