Files
EMWebApi/utils/fin_growth.py
T
toor 11ddbd3c49 实现全部 CHOICE 财务接口, 补充测试/文档/部署配置
- 新增 9 个抓取模块: 三大报表/盈利能力/资本结构/营运能力/成长能力/杜邦/分红
- api.py 新增 10 个 /fin/* 接口并统一无数据返回
- 新增 _emchoice.py 共享请求辅助 (emws 跳转取 URL / datacenter 报表拉取)
- 新增冒烟测试 tests/test_interfaces.py (24 用例)
- 新增接口文档 api_manual.md 与施工蓝图 blueprint.md
- 新增 Dockerfile / docker-compose.yml / deploy.sh 部署配置
2026-08-15 09:19:11 +08:00

75 lines
2.0 KiB
Python

"""东方财富 CHOICE API 成长能力抓取工具。
- 输入: 股票代码列表 (如 ['603233.SH'])
- 输出: pandas DataFrame (按报告期的成长能力指标)
- 不需要登录, 不需要 cookie, 无文件落盘
"""
from __future__ import annotations
import pandas as pd
from utils._emchoice import get_data_url, fetch_report
_PATH = "/stock/f9/CWFX_CZNL"
# 默认报告期类型: 1=一季报, 3=三季报, 5=中报, 6=年报
_DEFAULT_REPORT_PERIOD_TYPE = "1,5,3,6,7"
def _build_params(
secucode: str,
start_date: str,
end_date: str,
report_period_type: str,
) -> dict[str, str]:
"""构造 CWFX_CZNL 请求参数 (其余参数沿用 docs/api_docs.md 抓包值)."""
return {
"SecurityCode": secucode,
"StartDate": start_date,
"EndDate": end_date,
"ReportPeriodType": report_period_type,
"Digits": "2",
"Sort": "-1",
"IsShowEmptyRow": "true",
}
def _fetch_one(
secucode: str,
years: int,
report_period_type: str,
) -> pd.DataFrame:
"""拉一只股票的成长能力指标."""
today = pd.Timestamp.today()
start = (today - pd.DateOffset(years=years)).strftime("%Y-%m-%d")
end = today.strftime("%Y-%m-%d")
params = _build_params(secucode, start, end, report_period_type)
data_url = get_data_url(_PATH, params)
rows = fetch_report(data_url)
df = pd.DataFrame(rows)
if not df.empty:
df["SECUCODE"] = secucode
return df
def get_growth(
secucodes: list[str],
years: int = 3,
report_period_type: str = _DEFAULT_REPORT_PERIOD_TYPE,
) -> pd.DataFrame:
"""抓取指定股票的成长能力指标并按股票合并。"""
codes = [code.strip() for code in secucodes if code.strip()]
if not codes:
return pd.DataFrame()
frames: list[pd.DataFrame] = []
for code in codes:
df = _fetch_one(code, years, report_period_type)
if not df.empty:
frames.append(df)
if not frames:
return pd.DataFrame()
return pd.concat(frames, ignore_index=True)