8.6 KiB
8.6 KiB
根目录 > app
app - FastAPI 后端模块
模块职责
提供 JobData 平台的 REST API 服务,包含:用户/角色/权限/菜单/部门管理(RBAC),招聘数据入库、查询、清洗与分析,Token 与代理 IP 管理,定时任务调度,以及审计日志记录。
入口与启动
| 文件 | 说明 |
|---|---|
run.py(根目录) |
uvicorn 启动入口,读取 APP_HOST/APP_PORT/UVICORN_WORKERS 环境变量 |
app/__init__.py |
FastAPI 应用工厂 create_app(),注册中间件、异常处理器、路由,以及 lifespan 钩子 |
app/core/init_app.py |
lifespan 内部逻辑:DB 迁移、种子数据、ClickHouse 初始化 |
app/core/scheduler.py |
APScheduler 启动与任务注册 |
启动顺序
- Tortoise-ORM 连接 MySQL,生成 schema
- 按环境变量执行数据库迁移(Aerich)
- 初始化种子数据(超级管理员、菜单、API、角色)
- 初始化 ClickHouse 表/视图(可选)
- APScheduler 启动定时任务
- FastAPI 开始接受请求
对外接口
API 前缀:/api/v1,完整路由注册见 app/api/v1/__init__.py。
| 路由前缀 | 标签 | 权限 | 说明 |
|---|---|---|---|
/base |
基础模块 | 无 | 登录、获取用户信息、菜单树 |
/user |
用户管理 | DependPermission | 用户 CRUD |
/role |
角色管理 | DependPermission | 角色 CRUD、菜单/API 分配 |
/menu |
菜单管理 | DependPermission | 菜单树 CRUD |
/api |
API 管理 | DependPermission | 接口注册与权限管理 |
/dept |
部门管理 | DependPermission | 部门树 CRUD |
/auditlog |
审计日志 | DependPermission | 操作日志查询 |
/job & /universal |
数据入库/通用数据接口 | 无鉴权(内部调用) | 职位/公司数据批量入库 |
/token |
Token 管理 | 无鉴权 | Boss Token CRUD |
/proxy |
代理 IP 管理 | DependPermission | 代理池管理 |
/stats |
数据统计 | 无 | 各平台数据量统计 |
/pipeline |
流水线 | 无 | 触发 ECS pipeline |
/keyword |
关键词管理 | 无 | 爬虫关键词(城市+职位)管理 |
/cleaning |
数据清理 | DependPermission | 定向清洗操作 |
/analytics |
数据分析 | 无 | 趋势、来源分布统计 |
/company |
公司搜索 | 无 | 公司信息查询 |
认证机制:JWT(HS256,有效期 7 天),通过 DependPermission 依赖注入检查路由级别权限。
关键依赖与配置
配置集中在 app/settings/config.py(pydantic-settings.BaseSettings,支持环境变量覆盖):
# 关键字段(需通过环境变量覆盖)
SECRET_KEY = "CHANGE_ME_DEV_ONLY" # JWT 签名密钥
TORTOISE_ORM.connections.default # MySQL 连接串(含密码)
CLICKHOUSE_HOST / USER / PASS # ClickHouse 连接
SMTP_USER / SMTP_PASS # 邮件凭据
中间件链(从外到内):
CORSMiddleware- 跨域(默认允许http://localhost:5173)BackGroundTaskMiddleware- 后台任务支持HttpAuditLogMiddleware- HTTP 审计日志(排除登录接口)IpTrackingMiddleware- IP 请求追踪
数据模型
MySQL(Tortoise-ORM)
| 表 | 模型文件 | 说明 |
|---|---|---|
user |
app/models/admin.py |
用户(含角色多对多) |
role |
app/models/admin.py |
角色(含菜单、API 多对多) |
api |
app/models/admin.py |
接口注册表 |
menu |
app/models/admin.py |
菜单树(parent_id 自引用) |
dept |
app/models/admin.py |
部门树 + 闭包表 |
auditlog |
app/models/admin.py |
HTTP 操作审计 |
boss_token |
app/models/token.py |
Boss 直聘登录 Token |
cleaning_* |
app/models/cleaning.py |
数据清洗任务状态 |
scheduled_task_run / stats_total |
app/models/metrics.py |
定时任务运行记录与统计汇总 |
ClickHouse(原始数据存储)
| 表/视图 | 引擎 | 说明 |
|---|---|---|
boss_job |
MergeTree | Boss 职位原始 JSON,job_id 去重 |
boss_company |
MergeTree | Boss 公司原始 JSON,company_name 去重 |
qcwy_job |
MergeTree | 前程无忧职位,job_id + update_date_time 去重 |
qcwy_company |
MergeTree | 前程无忧公司 |
zhilian_job |
MergeTree | 智联招聘职位,number + first_publish_time 去重 |
zhilian_company |
MergeTree | 智联招聘公司 |
pending_company |
ReplacingMergeTree | 待处理公司队列,(source, company_id) 去重 |
job_analytics |
VIEW | 三平台统一分析视图(UNION ALL) |
ClickHouse 表结构在 app/core/clickhouse_init.py 中通过 CREATE TABLE IF NOT EXISTS 管理。
核心服务
| 服务文件 | 职责 |
|---|---|
app/services/cleaning.py |
CleaningService:多平台定向清洗(URL/ID/公司名/公司ID),自动识别平台 |
app/services/company_cleaner.py |
公司数据自动清洗:collect 待处理 → process → 入库 |
app/services/analytics_service.py |
AnalyticsService:封装 ClickHouse 分析查询 |
app/services/job.py |
DataRouterService:数据路由入库(去重逻辑) |
app/services/ingest_service.py |
批量数据摄入 |
app/services/crawler/boss.py |
Boss 爬虫 Service 封装(HTTP 层) |
app/services/crawler/qcwy.py |
前程无忧爬虫 Service |
app/services/crawler/zhilian.py |
智联招聘爬虫 Service |
app/repositories/clickhouse_repo.py |
ClickHouse Repository(ClickHouseBaseRepo + JobAnalyticsRepo) |
app/core/scheduler.py |
定时任务:stats、ip_alert、ecs_pipeline、company_cleaning、daily_cleanup |
app/core/locks.py |
DistributedLock:基于文件/Redis 的分布式锁,防多 Worker 重复执行 |
app/core/algorithms/antispider.py |
反爬虫算法(签名生成等) |
测试与质量
- 当前无测试文件,属于主要缺口。
- 代码质量工具:
ruff(lint)、black(格式)、isort(导入排序)。 - 建议优先补充的测试:
CleaningService.clean_target_auto()的平台识别逻辑DataRouterService.store_data()的去重逻辑app/api/v1/analytics.py接口集成测试
常见问题 (FAQ)
Q: 启动报 ClickHouse 连接失败?
A: 检查 CLICKHOUSE_HOST 环境变量,或在 config.py 中将 CLICKHOUSE_HOST 置为空字符串跳过初始化。
Q: 多 Worker 下任务重复执行?
A: 通过文件锁(.startup_lock 目录)和 DistributedLock 保护,若 Worker 异常退出可能导致锁残留,手动删除 .startup_lock 目录即可。
Q: 新增 API 接口后权限不生效?
A: 在路由文件中注册路由后,重启应用会触发 api_controller.refresh_api() 自动扫描 FastAPI 路由表并更新 api 表,然后在角色管理中分配权限。
相关文件清单
app/
├── __init__.py # 应用工厂 create_app()
├── settings/config.py # 全局配置(Settings)
├── api/v1/__init__.py # 路由聚合
├── api/v1/analytics.py # 数据分析接口
├── api/v1/cleaning/ # 数据清理接口
├── api/v1/job/ # 数据入库接口
├── api/v1/keyword/ # 关键词管理接口
├── api/v1/company/ # 公司搜索接口
├── controllers/ # 业务控制器(CRUD 封装)
├── core/
│ ├── init_app.py # lifespan 初始化
│ ├── scheduler.py # APScheduler 定时任务
│ ├── clickhouse.py # ClickHouse 连接管理
│ ├── clickhouse_init.py # ClickHouse 表/视图 DDL
│ ├── locks.py # 分布式锁
│ ├── middlewares.py # 中间件
│ └── algorithms/ # 签名/反爬虫算法
├── models/
│ ├── admin.py # User, Role, Api, Menu, Dept, AuditLog
│ ├── token.py # BossToken
│ ├── metrics.py # ScheduledTaskRun, StatsTotal
│ └── cleaning.py # 清洗任务状态
├── repositories/
│ └── clickhouse_repo.py # ClickHouse 查询仓库
├── services/
│ ├── cleaning.py # CleaningService
│ ├── company_cleaner.py # 公司自动清洗
│ ├── analytics_service.py # 数据分析 Service
│ ├── job.py # DataRouterService(数据入库路由)
│ └── crawler/ # 各平台爬虫 Service 封装
└── schemas/ # Pydantic 请求/响应 Schema
变更记录 (Changelog)
| 日期 | 说明 |
|---|---|
| 2026-03-20 | 初始化模块文档 |