"""东方财富 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)