# 候选表「来源」列硬编码陷阱 (2026-08-13 用户发现) ## 🚨 事故时间线 - **2026-07-30 → 2026-08-13**: `format_te_ma_result` 第 313-323 行有一张硬编码 `src_map` 字典, 只覆盖 8 个特殊号码 (1, 3, 5, 8, 9, 13, 31, 33, 47), 其他号码全部 fallback 到 "其他挂牌提示"。 - **2026-08-13 12:04 北京**: 用户问 "分析资料来源怎么没了?" — 实际 088 期 (今天 8/13 周四 21:30 未开) 抓取结果: 42 (权重 3, 来自挂牌另版挂), 3/4/13/14/23/24/33/34 (来自挂牌尾数)。除了 3/13/33 之外, 其他 5 个号码全部 fallback 到 "其他挂牌提示"。 ## 根因 硬编码字典覆盖范围有限, 与 `get_te_ma_candidates` 实际抓取逻辑完全脱节: - 挂牌 (zongheguapai/) 给号: 彩图挂直接给号, 另版挂, 尾数 → 1, 11, 13, 31, 33, 41 等等 - 玄机诗 (xuanjiziliao/) 给号: 诗象, 彩霸王 三一, 玄机字, 红马蓝狗 → 9, 47, 3, 13, 31, 8, 12, 18 - 六信红字 (lxhz/) 给号: 頤養/天年大数偏多 (25-49) 实际抓取结果里 42, 49, 4, 14, 24, 34, 23, 33 都不在硬编码字典里 → fallback "其他挂牌提示"。 ## 修法 (2026-08-13) `get_te_ma_candidates` 内部用 `src_tracker = defaultdict(list)` 同步记录每个号码的真实来源: ```python def get_te_ma_candidates(period='088'): weights = Counter() src_tracker = defaultdict(list) def add(n, w, src): if 1 <= n <= 49: weights[n] += w if src not in src_tracker[n]: src_tracker[n].append(src) # ... 抓取时 ... if '另版挂' in f: m = re.search(r'\d+', f['另版挂']) if m: add(int(m.group(0)), 3, f'挂牌 另版挂 ({f["另版挂"]})') # ... 尾数/玄机诗/红字 同理 ... return weights, src_tracker ``` `format_te_ma_result` 优先用 `src_tracker`, 硬编码字典删除: ```python def get_src(num): if src_tracker and num in src_tracker and src_tracker[num]: srcs = src_tracker[num][:2] txt = ' + '.join(srcs) if len(src_tracker[num]) > 2: txt += f' (+{len(src_tracker[num]) - 2})' return txt return '其他挂牌提示' ``` ## 验证 跑 `bash lottery_特码_cron.sh` 后, 看候选表「来源」列: - 期望: 「来源」列反映实际抓取 (挂牌另版挂, 尾数3尾, 尾数4尾 等) - 不期望: 「其他挂牌提示」占多数 (硬编码字典残余症状) ## 教训 1. **任何"展示抓取数据来源"的 UI 组件, 禁止用硬编码字典当 fallback** — 字典维护成本高, 抓取逻辑每天变, 字典永远跟不上 2. **抓取 + 来源绑定应该同步进行** — 在 `add(weight, src)` 那一刻就一起记录, 不要等输出时再回头查 3. **fallback 字符串一定要谨慎** — "其他挂牌提示" 看起来"无害", 实际把 bug 藏得很深 (用户问"资料来源怎么没了"才暴露) 4. **跨 session 维护** — 写新抓取规则时 (例如加挂牌出肖, 加灼码诗), 同步加 `add(num, w, '新源 描述')` 一行, 不要只改 weights 不改 src_tracker