Bank Wealth Yield Report
Overview
从理财子公司官网 API 采集母公司销售的理财产品数据,完成「采集 → 收益率解析 → 分类打标 → 分位数统计 → 图表 → 综合报告」的端到端流水线。调用者只需提供理财子产品收益率展示页面的网址(如 https://www.cibwm.com.cn/org-products、https://www.citic-wealth.com/),即可产出 Excel 与可视化报告。
内置两套已验证的数据源:兴银理财(兴业银行渠道,cibwm.com.cn)和信银理财(中信银行渠道,citic-wealth.com)。接入新理财公司时参照「接入新数据源」一节。
运行环境
- Python:一律使用 venv 解释器
C:/Users/林紫盈/.workbuddy/binaries/python/envs/default/Scripts/python.exe - 依赖:
requests、openpyxl、playwright(缺 playwright 浏览器时执行python -m playwright install chromium) - 脚本均假设在当前工作目录读写
cib_products.json、citic_products.json、chart_*.svg等文件,运行前先cd到输出目录
标准流程(六步)
第一步:数据采集
- 兴业银行:运行
scripts/scrape_cib_v2.py。POSThttps://www.cibwm.com.cn/api/public/pc/productInfo/getProdInfoByPage,筛选 orgType(机构/个人)、distributionChannel=兴业银行、币种 CNY、状态=预售+募集+存续,分页拉全量,输出cib_products.json。 - 信银理财:运行
scripts/scrape_citic_v4.py。GEThttps://www.citic-wealth.com/was5/web/search,按 5 个标签(募集期 223318、每日购 232545、定开 240190、货币 259020、封闭 299180)分别拉取并合并去重,输出citic_products.json。API 返回的 JSON 经常格式异常(缺失值、888888 占位、尾部逗号),必须先经脚本内fix_json()修复再解析。 - 信银详情补采:运行
scripts/scrape_detail_v2.py。对列表中缺 7 日年化收益率的产品,调用wechat.citic-wealth.com的详情 API 补收益率。需要 HMAC-SHA256 签名,且 SSL 必须开启OP_LEGACY_SERVER_CONNECT(ctx.options |= 0x4),否则握手失败。
各 API 的完整参数、签名算法、修复规则见 references/api_details.md。
第二步:收益率解析(最易出错)
两家数据源的收益率格式不同,接入任何新数据源时必须先用 1~2 条真实样本确认格式:
- 数值若形如
0.0234→ 小数格式,×100 转百分比(当前信银理财如此:sevenDaysIncomeRate 等字段) - 数值若形如
2.34或字符串"6.789%"→ 已是百分比,直接使用(当前兴业银行的 sinceInceptionAnnualReturn 如此;其 benchmarkLowerLimit 为小数需 ×100) - 范围字符串如
"2.580-2.780%"/"2.580~2.780%"→ 取下限 - 负值保留负号;0 或空视为无效
参考 scripts/fix_and_regen.py 中 parse_yield_cib / parse_yield_citic / parse_yield_string。
第三步:产品分类
按优先级分 6 大类(优先级即下列顺序,命中即返回):
- 现金管理类(货币型)
- 每日申赎(每日可申赎、无最短持有要求)
- 最短持有期:细分 7天 / 14天 / 21天 / 30天 / >30天
- 封闭式:细分 ≤3个月 / 4-6个月 / 7-12个月 / 13-18个月 / 19-24个月 / 25-36个月 / >36个月
- 固收增强(固收+):按持有期细分
- 其他
分类依据:产品名称、投资性质、产品形态(开放式/封闭式)、期限字段、渠道标签。兴业封闭式产品跳过最短持有期检查。参考 fix_and_regen.py 中 classify_product 及 extract_hold_days 等辅助函数(持有期从名称正则提取:\d+天持有、\d+个月持有 等,月×30、年×365 换算)。
第四步:统计与可视化
- 有效产品筛选:收益率在 -5% ~ 15% 之间,且净值日期为当月(当月无数据则回退用全部有效产品)
- 分位数用线性插值法(
percentile()):现金管理类/每日申赎算 P50/P60/P70/P80/P90/P95;最短持有期/封闭式/固收增强按期限分组算 P50/P70/P90/P95 - 图表配色固定:兴业=蓝色渐变、信银/中信=红色渐变,P50 浅 → P95 深;柱高=收益率、柱宽∝产品数量
- 生成 5 张 SVG:chart_1 现金管理+每日申赎、chart_2 最短持有期、chart_3 封闭式、chart_4 固收增强、chart_5 各大类对比
运行 scripts/fix_and_regen.py 一次完成第二~五步(读取两个 JSON → 输出 Excel × 2、chart_1~5.svg、report_data.json)。
第五步:输出文件
产品分类标签表.xlsx:全部产品,第 1 列大类、第 2 列期限标签,后接银行、代码、名称、风险等级、收益率等完整字段收益率分位数报告.xlsx:3 个 sheet(完整 P50-P95 分位数数据含产品数、期限分位数对比、说明)chart_1.svg~chart_5.svg
第六步:综合报告
运行 scripts/gen_report.py:读取 report_data.json + 5 张 SVG,生成 银行理财产品收益率分析报告.html,并用 Playwright(chromium headless,file:// URL 加载)自动转:
银行理财产品收益率分析报告.pdf(A4、打印背景色、10mm 边距)银行理财产品收益率分析报告.png(全页面长截图,viewport 宽 1200)
完成后将 PDF、PNG、两个 Excel 一起用 present_files 展示给用户。
接入新数据源(新理财公司)
当用户提供一个新的理财子产品展示网址时:
- 抓 API:用浏览器自动化或 fetch 打开该页面,抓取其列表接口(XHR/fetch),确认分页方式、筛选参数(机构/个人、渠道、币种、状态)
- 写采集脚本:仿照
scrape_cib_v2.py/scrape_citic_v4.py写新脚本,输出统一的<source>_products.json;注意 JSON 修复、反爬签名、SSL 兼容等问题(模式见references/api_details.md) - 确认收益率格式:取真实样本判断小数 vs 百分比(见第二步),写对应的
parse_yield_* - 复用分类与流水线:在
fix_and_regen.py的normalize_products()中按统一 schema(bank/productCode/productName/yield/nav/navDate/category/periodLabel…)接入新源,classify_product增加对应分支;更新 bank_order、配色和报告文案 - 其余步骤(分位数、图表、Excel、报告)原样复用
Resources
scripts/
scrape_cib_v2.py— 兴业银行机构理财产品列表采集scrape_citic_v4.py— 信银理财 5 标签采集合并(含 JSON 修复)scrape_detail_v2.py— 信银详情页收益率补采(HMAC 签名 + SSL legacy)fix_and_regen.py— 收益率解析、分类、分位数统计、Excel 与 SVG 图表生成gen_report.py— HTML/PDF/PNG 综合报告生成
references/
api_details.md— 各 API 完整规格:请求参数、JSON 修复规则、HMAC-SHA256 签名算法、SSL 处理、收益率字段格式对照、分类规则细节、配色规范
微信扫一扫