You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
EMWebApi/docs/blueprint.md

161 lines
9.5 KiB

# EMWeb API 项目施工蓝图
> 记录项目目标、架构、接口清单、实施进度与施工规范,避免"做到一半忘记当初的规划"。
---
## 1. 项目简介
**目标**:以东方财富 CHOICE 数据接口为基础,封装一套稳定、可复用的财务数据抓取服务,对外以 FastAPI 提供 HTTP 接口。
**核心诉求**
- 不需要登录 / cookie,直接调公开接口即可拿到数据
- 每个数据模块独立成文件,可脚本直接调用,也可通过 API 暴露
- 数据以 pandas DataFrame 为内部统一载体,出 HTTP 时转 JSON-safe 结构
**技术栈**:Python >= 3.11 · FastAPI + Uvicorn · requests · pandas · uv 管理依赖
---
## 2. 架构总览
```
EMWebApi/
├── api.py # FastAPI 入口, 聚合各 utils 模块对外暴露 HTTP 接口
├── utils/
│ ├── fin_summary.py # 财务摘要(报告期) —— 最底层, 含共享常量/SSL修复
│ ├── _emchoice.py # 内部共享请求辅助 (emws 跳转取 URL / datacenter 报表拉取)
│ ├── fin_quarterly.py # 财务摘要(单季度)
│ ├── fin_main_business.py # 主营构成(按产品/地区)
│ ├── fin_balance.py # 资产负债表
│ ├── fin_income.py # 利润表
│ ├── fin_cashflow.py # 现金流量表
│ ├── fin_profitability.py # 盈利能力与收益质量
│ ├── fin_capital_structure.py # 资本结构与偿债能力
│ ├── fin_operate.py # 营运能力
│ ├── fin_growth.py # 成长能力
│ ├── fin_dupont.py # 杜邦分析
│ ├── fin_dividend.py # 分红明细 + 分红统计
│ ├── fin_free_holders.py # 十大流通股东
│ ├── fin_holders.py # 十大股东明细
│ ├── fin_holder_num.py # 股东户数
│ ├── fin_mda.py # 管理层讨论与分析(MD&A)
│ ├── fin_equity.py # 股本结构
│ ├── fin_company.py # 公司介绍 + 所属行业
│ ├── fin_belong_index.py # 所属指数分类/统计/成分权重
│ └── fin_major_events.py # 重大事项(并购/激励/诉讼/关联/违规/担保)
├── tests/
│ └── test_interfaces.py # 冒烟测试 (连真实接口)
└── docs/
├── api_docs.md # 从 Reqable 抓包沉淀的原始接口记录
├── api_manual.md # 对外 HTTP 接口使用文档
└── blueprint.md # 本文件: 施工蓝图
```
**依赖方向**
- `fin_quarterly.py` / `fin_main_business.py` 复用 `fin_summary.py` 里的 `HEADERS` / `TIMEOUT` / `BASE_URL`(顺带触发其模块级的 SSL 自动修复)
- 其余新模块复用 `_emchoice.py``get_data_url` / `fetch_report`(同样会触发 SSL 修复)
- `fin_major_events.py` / `fin_company.py` / `fin_belong_index.py` 内部有 `_run` / `_fetch_one` 复用,避免六接口重复样板
---
## 3. 数据源接口清单(源自 docs/api_docs.md)
| # | 接口 | 报表名/路径 | 实现状态 |
|---|------|-------------|----------|
| 1 | 财务摘要(单季度) | `RPT_HSF9_FIN_SUMMARYQUARTERNEW` | ✅ 已实现 |
| 2 | 主营构成(产品/地区) | `ZYGC_AFLZS``RPT_HSF9_FN_MAINOPBUSINESS` | ✅ 已实现 |
| 3 | 资产负债表 | `CWSJ_ZCFZB``RPT_CUSTOM_HSF9_FINA_GBALANCE` | ✅ 已实现 |
| 4 | 利润表 | `CWSJ_LRB``RPT_CUSTOM_HSF9_FINA_GINCOMESYN` | ✅ 已实现 |
| 5 | 现金流量表 | `CWSJ_XJLLB``RPT_CUSTOM_HSF9_FINA_GCASHFLOW` | ✅ 已实现 |
| 6 | 盈利能力与收益质量 | `CWFX_YLNLYSYZL``RPT_HSF9_FINA_PROFITEARNING` | ✅ 已实现 |
| 7 | 资本结构与偿债能力 | `CWFX_ZBJGYCZNL``RPT_HSF9_FINA_CAPPAYAB` | ✅ 已实现 |
| 8 | 营运能力 | `RPT_HSF9_FINA_OPERATEABILITY` | ✅ 已实现 |
| 9 | 成长能力 | `CWFX_CZNL``RPT_HSF9_FINA_GROWTH` | ✅ 已实现 |
| 10 | 杜邦分析 | `RPT_HSF9_FINA_DUPONT` | ✅ 已实现 |
| 11 | 分红明细 + 分红统计 | `RPT_HSF9_ASSIGNPLAN_DETAIL` / `_STATICS` | ✅ 已实现 |
| 12 | 十大流通股东 | `RPT_F10_EH_FREEHOLDERS` | ✅ 已实现 |
| 13 | 十大股东明细 | `RPT_DMSK_HOLDERS` | ✅ 已实现 |
| 14 | 股东户数 | `RPT_F10_EH_HOLDERNUM` | ✅ 已实现 |
| 15 | 管理层讨论与分析 | `RPT_BUSINESSANALYSIS` | ✅ 已实现 |
| 16 | 股本结构 | `RPT_F10_EH_EQUITY` | ✅ 已实现 |
| 17 | 公司介绍 | `RPT_HSF9_BASIC_ORGINFO` | ✅ 已实现 |
| 18 | 所属行业 | `RPT_STOCKF9_INDUSTRY` | ✅ 已实现 |
| 19 | 指数分类 | `RPT_HSF9_BELONGINDEX_CLASSIF` | ✅ 已实现 |
| 20 | 纳入指数统计 | `RPT_CUSTOM_HSF9_BELONG_INDEX` | ✅ 已实现 |
| 21 | 指数成分权重 | `RPT_HSF9_BELONG_INDEX` | ✅ 已实现 |
| 22 | 并购事件 | `RPT_HS_ACQUISITIONS_EVENT` | ✅ 已实现 |
| 23 | 股权激励 | `RPT_DMSK_SH_EQUITYINCENTIVE` | ✅ 已实现 |
| 24 | 诉讼仲裁 | `RPT_LITIGATION_ARBITRATION_BSINFO` | ✅ 已实现 |
| 25 | 关联交易 | `RPT_RELATED_TRANSACTION` | ✅ 已实现 |
| 26 | 违规处罚 | `RPT_HSF9_OP_VIOLATION` | ✅ 已实现 |
| 27 | 对外担保 | `RPT_F9_GUARANTEE` | ✅ 已实现 |
**文档外补充**:财务摘要(报告期) 用 `RPT_CUSTOM_ORGF9_FIN_SUMMARY`,需 ORG_CODE(不在 api_docs.md 里)。
---
## 4. 实施进度
### ✅ 已完成(api_docs.md 全部 27 项落地)
| 功能 | 核心文件 | HTTP 接口 |
|------|----------|-----------|
| 健康检查 | `api.py` | `GET /health` |
| 财务摘要(报告期) | `utils/fin_summary.py` | `GET /fin/summary` |
| 财务摘要(单季度) | `utils/fin_quarterly.py` | `GET /fin/quarterly-summary` |
| 主营构成(产品/地区) | `utils/fin_main_business.py` | `GET /fin/main-business` |
| 资产负债表 | `utils/fin_balance.py` | `GET /fin/balance` |
| 利润表 | `utils/fin_income.py` | `GET /fin/income` |
| 现金流量表 | `utils/fin_cashflow.py` | `GET /fin/cashflow` |
| 盈利能力与收益质量 | `utils/fin_profitability.py` | `GET /fin/profitability` |
| 资本结构与偿债能力 | `utils/fin_capital_structure.py` | `GET /fin/capital-structure` |
| 营运能力 | `utils/fin_operate.py` | `GET /fin/operate-ability` |
| 成长能力 | `utils/fin_growth.py` | `GET /fin/growth` |
| 杜邦分析 | `utils/fin_dupont.py` | `GET /fin/dupont` |
| 分红明细 + 统计 | `utils/fin_dividend.py` | `GET /fin/dividend-detail` / `GET /fin/dividend-statics` |
| 十大流通股东 | `utils/fin_free_holders.py` | `GET /fin/free-holders` |
| 十大股东明细 | `utils/fin_holders.py` | `GET /fin/holders` |
| 股东户数 | `utils/fin_holder_num.py` | `GET /fin/holder-num` |
| 管理层讨论与分析 | `utils/fin_mda.py` | `GET /fin/mda` |
| 股本结构 | `utils/fin_equity.py` | `GET /fin/equity` |
| 公司介绍 | `utils/fin_company.py` | `GET /fin/company-info` |
| 所属行业 | `utils/fin_company.py` | `GET /fin/industry` |
| 指数分类/统计/成分 | `utils/fin_belong_index.py` | `GET /fin/index-classif` / `GET /fin/belong-index` / `GET /fin/index-membership` |
| 并购事件 | `utils/fin_major_events.py` | `GET /fin/acquisitions` |
| 股权激励 | `utils/fin_major_events.py` | `GET /fin/equity-incentive` |
| 诉讼仲裁 | `utils/fin_major_events.py` | `GET /fin/litigation` |
| 关联交易 | `utils/fin_major_events.py` | `GET /fin/related-transaction` |
| 违规处罚 | `utils/fin_major_events.py` | `GET /fin/violation` |
| 对外担保 | `utils/fin_major_events.py` | `GET /fin/guarantee` |
| 测试 | `tests/test_interfaces.py` | `uv run pytest tests/ -q` (56 用例) |
### 🧹 待清理
- `fin_summary.py` 里的 `_debug_report`(向 `127.0.0.1:7777/event` 发 POST)是调试残留,可移除
- `_auto_fix_ssl` 里残留 Windows 路径(`%USERPROFILE%\...`),运行环境是 macOS,可精简
---
## 5. 施工规范(新模块必须遵守)
1. **文件命名**:`utils/fin_<主题>.py`,一个主题一个文件,内部函数私有化(`_` 开头);仅内部共享的请求辅助放 `utils/_emchoice.py`
2. **结构**:`_build_*(参数构造)` → `_fetch_one(单只拉取)``get_<主题>(批量主入口)`
3. **共享**:`from utils.fin_summary import HEADERS, TIMEOUT`,不重复定义;不同 base_url 的接口在本文件内定义新常量;emws 跳转接口用 `_emchoice.get_data_url`,datacenter 报表用 `_emchoice.fetch_report`
4. **数据流**:内部统一 `pandas.DataFrame`,每行冗余 `SECUCODE` 列便于多股票合并
5. **校验**:`fetch_report` 中 `success=False` 且 message 为"返回数据为空/暂无数据/无数据"时按空结果处理(返回空列表),其余失败抛 `RuntimeError`;空数据返回空 DataFrame 而非报错
6. **接口暴露**:api.py 中每个接口必须用显式 `@app.get` 装饰器 + `Query` 参数(不使用程序化注册),返回 `{success, count, columns, data, errors}` 风格,NaN/NaT/inf 转 None(复用 `_df_to_json_payload`),无数据统一走 `_empty_response`;纯 `stocks` 参数用 `_split_codes` 解析
7. **礼貌抓取**:批量循环中加随机延时(参考 `SLEEP_RANGE`
8. **注释语言**:中文,解释"为什么"(如接口编码映射差异)
9. **测试**:新模块在 `tests/test_interfaces.py` 注册冒烟用例(连真实接口取 1 年数据,断言非空 + 关键列)
---
## 6. 常用命令
```bash
uv sync # 创建环境并安装依赖
uv run python api.py # 启动服务 (默认端口 8765)
uv run pytest tests/ -q # 跑冒烟测试 (连真实接口)
uv run python -c "..." # 直接跑脚本
```