本项目包含三个 Python 脚本,用于从东方财富定期报告中提取普通股股东总数和前十名股东,并生成股东变化结果。
- Python 3.10 或更高版本
- 推荐安装并使用
uv - 运行时需要访问东方财富公开网页、行情接口和 PDF 附件
三个脚本使用 PEP 723 声明依赖,通过 uv run 启动时会自动安装所需依赖。
cd /home/lich/work/tools/eastmoney文件:eastmoney_shareholders.py
用途:
- 查询指定股票的完整定期报告。
- 排除年度报告摘要、半年度报告摘要和非目标财务报告。
- 按报告期选择最新两个不同定期报告。
- 提取报告期末普通股股东总数和前十名股东。
- 输出相邻两期的股东人数、持股数、持股比例和前十名单变化。
uv run eastmoney_shareholders.py 300894默认输出:
300894_股东变化.txt
指定输出文件:
uv run eastmoney_shareholders.py 300894 -o 火星人股东变化.txt查看帮助:
uv run eastmoney_shareholders.py --help文件:eastmoney_state_team.py
用途:
- 获取全部沪深北 A 股及总市值。
- 默认只保留总市值低于 100 亿元的股票。
- 比较每只股票最新两个不同定期报告期。
- 筛选最新一期新进入前十名股东、而上一期没有的国家队机构。
- 输出公司、新进入国家队股东、总市值和报告时间的 Markdown 表格。
当前识别的国家队机构包括:
- 中央汇金投资有限责任公司
- 中央汇金资产管理有限责任公司
- 中国证券金融股份有限公司
- 全国社会保障基金理事会
全国社保基金...组合
uv run eastmoney_state_team.py默认输出:
国家队新进股东.md
国家队新进股东.errors.log
国家队新进股东.skipped.log
只有存在对应项目时才生成日志。.errors.log 记录解析或下载失败,.skipped.log 记录无完整报告或报告期不足等正常跳过项;每行格式为 类别<TAB>代码<TAB>公司<TAB>详情。
uv run eastmoney_state_team.py \
--workers 12 \
--parse-workers 2 \
--max-download-mbps 45 \
--max-requests-per-second 3 \
--batch-size 250 \
--batch-pause-seconds 60 \
--cache-dir .eastmoney_cache \
-o 国家队新进股东_全量测试.md参数说明:
--workers 12:最多 12 个网络任务并发。--parse-workers 2:使用 2 个进程解析 PDF;局部 OCR 单进程峰值约 400 MiB,不建议默认开到 4。--max-download-mbps 45:单个程序总下载带宽上限为 45 Mbps;设为0表示不限速。--max-requests-per-second 3:所有线程合计每秒最多发起 3 次请求。--batch-size 250:每批处理 250 只股票。--batch-pause-seconds 60:批次之间主动冷却 60 秒,降低接口临时封锁风险。--market-cache-minutes 15:市值列表默认缓存 15 分钟。--keep-pdf:解析成功后仍保留原始 PDF;默认成功后删除 PDF。
uv run eastmoney_state_team.py \
--codes 300894,600519,920002 \
--max-market-cap 200 \
-o 指定股票测试.mduv run eastmoney_state_team.py --limit 100 -o 前100只测试.md文件:eastmoney_state_team_increase.py
该脚本比较每只股票最新两个不同的定期报告期,只筛选满足以下全部条件的记录:
- 股票总市值低于 100 亿元(默认值,可通过
--max-market-cap调整)。 - 同一国家队机构在前后两期都位于前十名股东中。
- 后一期持股数量严格大于前一期;新进入前十名不计为增持。
- 两期快照都具有完整持股数和持股比例;仅名称级快照会写入跳过日志。
默认运行:
uv run eastmoney_state_team_increase.py默认输出:
国家队增持股票.md
国家队增持股票.errors.log
国家队增持股票.skipped.log
指定股票进行小规模验证:
uv run eastmoney_state_team_increase.py --codes 300894,600000 -o 国家队增持测试.mdMarkdown 每行对应一个“股票 + 国家队机构”,包含前后持股数、增持股数、增持比例、持股比例变化、比较报告期和总市值。网络并发、解析进程、批次、限速和缓存参数与 eastmoney_state_team.py 相同。
根目录只保留源码、测试、项目说明、配置、运行缓存和统一的 artifacts/ 入口。需要长期保留的全量报告、分批结果、错误日志与跳过日志统一放在:
artifacts/runs/<运行日期>-<用途>/
├── README.md # 本次运行结论、统计和追溯入口
├── final/ # 最终报告及同名 errors/skipped 日志
├── batches/ # 分批运行的原始报告及日志(如有)
└── validation/ # 小规模测试、错误复验等材料(如有)
运行前先创建对应目录,再通过 -o 将 Markdown 写入该目录;同名 .errors.log 和 .skipped.log 会自动写在 Markdown 旁边。重新执行全量扫描时应新建运行目录,不覆盖旧记录。
已归档运行及其摘要见 artifacts/README.md。
uv run eastmoney_state_team.py --market-cache-minutes 0uv run eastmoney_state_team.py --help脚本二默认使用:
.eastmoney_cache/
├── market_stocks.json # 市值列表缓存
├── pdf/ # 下载或解析失败后保留的 PDF
└── snapshot/ # 成功解析的结构化股东快照
处理策略:
- 已有有效快照时不重复解析 PDF。
- 快照包含 schema、解析器版本、公告编号和 PDF 大小;版本不兼容时自动重新解析。
- 解析成功后默认删除 PDF,只保留较小的 JSON 快照。
- 解析失败时保留 PDF,方便后续排查。
- 使用
--keep-pdf时保留所有成功下载的 PDF。
脚本二生成的 Markdown 示例:
| 公司 | 新股东(国家队) | 总市值 | 报告时间 |
|---|---|---:|---|
| 某某股份(600000) | 中国证券金融股份有限公司 | 68.32亿元 | 2026年一季度报告(2026-03-31) |“退出前十”或“上一期没有”只表示该机构未出现在上一期前十名股东中,不代表此前完全未持股。
uv run --with 'httpx>=0.28,<1' --with 'pdfplumber>=0.11,<1' \
--with 'pypdf>=6,<7' --with 'pypdfium2>=5.12,<6' \
--with 'rapidocr-onnxruntime>=1.4,<2' --with 'onnxruntime==1.20.1' \
python -m unittest discover -s tests -v
uv run python -m py_compile eastmoney_shareholders.py eastmoney_state_team.py eastmoney_state_team_increase.pyuv run python -m unittest 不会自动读取其他脚本中的 PEP 723 依赖声明,因此测试命令需要显式提供同一组依赖。
onnxruntime 固定为 1.20.1,因为较新版本在当前 Windows 环境中会发生 DLL 初始化失败。
本地保留失败 PDF 时,可按公告编号逐份回归,避免超大年报累积内存:
uv run tests/run_pdf_regression.py --check AN202604241821560161- 东方财富接口可能临时拒绝高频请求,不建议取消请求频率限制后长期全量运行。
- 带宽限制以单个程序为单位;同时启动两个 45 Mbps 进程,合计可能接近 90 Mbps。
- 扫描 PDF 会明确标记为
ocr_required;未启用 OCR 时不会生成猜测结果。 - 中断后使用相同缓存目录重新运行,可复用已经完成的 PDF 和结构化快照。