Files
Hermes-Skills/lottery-hk/scripts/lottery_4frame.py
T
mike a2bc7b18e3 lottery_4frame + cron-prompts: 字段语义残余清理
修:
- lottery_4frame.py line 52 docstring: Qi=下次将开 → Qi=最新已开
- lottery_4frame.py line 153 step 1 header: Qi 下期开彩 → Qi 最新已开
- lottery_4frame.py line 162: Qi 期开彩(从 Nq 推算) → 清晰说 Nq 期
- lottery_4frame.py main(): 默认 082 → 自动取 v_xg.json Qi
- lottery_4frame.py line 2 doc: 写死 '082 期' → 动态 Qi
- cron-prompts/lottery-hot-data.md: Qi=下次将开 → 最新已开
- cron-prompts/lottery-draw-result.md: 同上

输出验证 (8/4 跑):
  083 期 4 框架玄学分析 (按 lottery-hk skill v1.2.7 流程)
  Qi (最新已开) = 083, Nq (未开下期) = 084
  Data.1-7 = Qi-2 期 81 已开号码 (不是 Qi-1!)
  Qi 期开彩日(从 Nq 推算): Nq 期开彩日 Week=周二 Day=04 - 3 天
2026-08-04 15:56:52 +08:00

279 lines
10 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""
# lottery 4 框架玄学分析 — 真实脚本 (替代 model 手动推演, 动态取 Qi)
基于 references/analysis-example-073/074/075.md 的 3 步推演流程
【2026-08-02 修复】sol.2344a.cc 出现 "Cann't connect to DB!" 时静默失败
→ 加 fail-fast 错误检测 (check_db_error)
"""
import os
import sys
import json
import time
import datetime
import urllib.request
# === 硬规则 (跟 SKILL.md 一致) ===
TIMEZONE_BEIJING = "北京时间 (UTC+8)"
# === 数据源 ===
SOL_BASE = "https://sol.2344a.cc"
V_XG_URL = "https://btc.tktk.app/data/v_xg.json"
# === 错误检测 pattern (2026-08-02 实战发现) ===
DB_ERROR_PATTERNS = [
"Cann't connect to DB!",
"Can't connect to DB!",
"database connection failed",
"internal server error",
"数据库连接失败",
]
def check_db_error(data, source_name):
"""检测 sol.2344a.cc / tktk 临时 DB 错误 → fail-fast"""
if not isinstance(data, str):
return data # 非字符串, 可能是 JSON
for pattern in DB_ERROR_PATTERNS:
if pattern.lower() in data.lower():
raise RuntimeError(
f"[{source_name}] DB 错误: {data[:200]!r}\n"
f" 触发 pattern: {pattern!r}\n"
f" 修复: 等 sol.2344a.cc 恢复, 或用本地 SQLite draws 表作为 fallback"
)
if "页面使用Vue.js动态加载" in data:
raise RuntimeError(
f"[{source_name}] Vue.js 动态加载 (cron 模式拿不到数据), "
f"改用 browser_snapshot(full=true) 或 fallback 方案"
)
return data
def fetch_v_xg():
"""拉 v_xg.json (Qi=最新已开, Data.1-7=Qi-2 已开 (不是 Qi-1))"""
try:
req = urllib.request.Request(V_XG_URL, headers={'User-Agent': 'Mozilla/5.0'})
with urllib.request.urlopen(req, timeout=15) as r:
data = json.loads(r.read().decode('utf-8'))
# 检查 Qi 字段 (防止 DB 错误 JSON)
if 'Qi' not in data or data.get('Qi') == '?':
raise RuntimeError(f"v_xg.json 缺 Qi 字段: {data!r}")
return data
except RuntimeError:
raise
except Exception as e:
raise RuntimeError(f"v_xg.json 网络错误: {e}") from e
def curl_url(url):
"""curl via mihomo proxy, return raw text
[2026-08-02 修复] 加 DB 错误检测 → fail-fast
"""
import subprocess
try:
result = subprocess.run(
['curl', '-x', 'http://127.0.0.1:7890', '-L', '-s', url],
capture_output=True, text=True, timeout=20
)
if result.returncode != 0:
raise RuntimeError(f"curl {url} returncode={result.returncode}: {result.stderr[:200]}")
# fail-fast: 检测 DB 错误
check_db_error(result.stdout, f"curl {url}")
return result.stdout
except RuntimeError:
raise
except Exception as e:
raise RuntimeError(f"curl {url} 异常: {e}") from e
def fetch_sol_list(path, marker, limit=5):
"""拉 sol.2344a.cc 列表页, 摘 marker (期号) 行
[2026-08-02 修复] marker 写死 "082" 是 bug, 改用 period 参数
"""
html = curl_url(f'{SOL_BASE}{path}')
lines = []
for line in html.split('\n'):
if marker in line:
# 去 HTML tag
import re
clean = re.sub(r'<[^>]+>', ' ', line).strip()
# 提取 marker 期号:... 直到 "
m = re.search(rf'{re.escape(marker)}[^\"]*?(?=</)', clean) or re.search(rf'{re.escape(marker)}[^\"]*', clean)
if m and m.group(0).strip():
lines.append(m.group(0).strip()[:250])
# 去重
seen = set()
unique = []
for l in lines:
if l not in seen:
seen.add(l)
unique.append(l)
return unique[:limit]
def fetch_sol_detail(path):
"""拉 sol.2344a.cc 详情页, 解析挂牌内容"""
import re
html = curl_url(f'{SOL_BASE}{path}')
# 去 HTML tag, 提取关键
text = re.sub(r'<script[^>]*>.*?</script>', '', html, flags=re.DOTALL)
text = re.sub(r'<style[^>]*>.*?</style>', '', text, flags=re.DOTALL)
text = re.sub(r'<[^>]+>', ' ', text)
text = re.sub(r'\s+', ' ', text).strip()
# 找关键字段
fields = {}
for kw in ['另版挂', '正版彩图挂', '四字', '六肖', '尾数', '火烧', '爆', '出肖', '挂牌出肖', '挂牌成语', '红字']:
m = re.search(kw + r'[:]([^。\s]{1,30})', text)
if m:
fields[kw] = m.group(1).strip()
return fields
def zodiac_lookup(num):
"""号→生肖 (mod 12)"""
z = ['狗', '猪', '蛇', '马', '羊', '虎', '兔', '鼠', '牛', '猴', '鸡', '龙']
return z[num % 12]
def analyze(period='082'):
"""完整玄学分析 (按 reference 073 流程)
Args:
period: 期号 (默认 '082'), 用于 marker 匹配
"""
out = []
out.append("=" * 70)
out.append(f"{period} 期 4 框架玄学分析 (按 lottery-hk skill v1.2.7 流程)")
out.append("=" * 70)
out.append(f"📌 所有时间默认 {TIMEZONE_BEIJING}")
out.append(f"📌 挂牌日 = 实际开彩日 (sol.2344a.cc 帖子时间戳 = 实际开奖日)")
out.append("")
# ===== Step 1: v_xg.json =====
out.append(f"--- Step 1: v_xg.json (Qi=最新已开, Data.1-7=Qi-2 已开) ---")
v = fetch_v_xg()
data = v.get('Data', {})
qi = v.get('Qi', '?')
nq = v.get('Nq', '?')
week = v.get('Week', '?')
day = v.get('Day', '?')
qi_minus_2 = int(qi) - 2 if qi.isdigit() else '?'
out.append(f"Qi (最新已开) = {qi}, Nq (未开下期) = {nq}")
out.append(f"Qi 期开彩日(从 Nq 推算): Nq 期开彩日 Week={week} Day={day} - 3 天")
out.append(f"Data.1-7 = Qi-2 期 {qi_minus_2} 已开号码 (不是 Qi-1!)")
out.append("")
out.append("| 位置 | 号码 | 生肖 | 五行 | 波色 |")
out.append("|---|---|---|---|---|")
last_seven = []
for k in ['1', '2', '3', '4', '5', '6', '7']:
item = data.get(k, {})
if not item:
continue
num = int(item.get('number', 0))
sx = item.get('sx', '?')
nim = item.get('nim', '?')
color = item.get('color', '?')
pos = '特码' if k == '7' else f'平码{k}'
out.append(f"| {pos} | {num} | {sx} | {nim} | {color} |")
last_seven.append({'num': num, 'sx': sx, 'nim': nim, 'color': color, 'pos': pos})
out.append("")
# 五行统计
from collections import Counter
nim_count = Counter([x['nim'] for x in last_seven])
out.append(f"{qi_minus_2} 期五行统计: " + " | ".join(f"{n}:{c}" for n, c in nim_count.most_common()))
out.append(f"{qi_minus_2} 期生肖统计: " + " | ".join(f"{s}:{c}" for s, c in Counter([x['sx'] for x in last_seven]).most_common()))
out.append(f"{qi_minus_2} 期波色统计: " + " | ".join(f"{c}:{n}" for c, n in Counter([x['color'] for x in last_seven]).most_common()))
out.append("")
# ===== Step 2: 综合挂牌 (列表 + 详情) =====
out.append(f"--- Step 2: 综合挂牌 (sol.2344a.cc/zongheguapai/) ---")
gua_list = fetch_sol_list('/zongheguapai/', f'{period}期', limit=3)
if gua_list:
for g in gua_list:
out.append(f" • {g}")
out.append("")
# 拿详情: 选第一个有 period 期 的链接
import re
gua_html = curl_url(f'{SOL_BASE}/zongheguapai/')
detail_links = re.findall(rf'href="(/zongheguapai/\d+\.html)"[^>]*>.*{period}期', gua_html)[:2]
for link in detail_links:
fields = fetch_sol_detail(link)
if fields:
out.append(f" 📄 {link}:")
for k, v in fields.items():
out.append(f" {k}: {v}")
out.append("")
# ===== Step 3: 六信红字 =====
out.append(f"--- Step 3: 六信红字 (sol.2344a.cc/lxhz/) ---")
hong_list = fetch_sol_list('/lxhz/', f'{period}期', limit=3)
if hong_list:
for h in hong_list:
out.append(f" • {h}")
# 拿详情
hong_html = curl_url(f'{SOL_BASE}/lxhz/')
hong_links = re.findall(rf'href="(/lxhz/\d+\.html)"[^>]*>.*{period}期', hong_html)[:2]
for link in hong_links:
fields = fetch_sol_detail(link)
if fields:
out.append(f" 📄 {link}:")
for k, v in fields.items():
out.append(f" {k}: {v}")
out.append("")
# ===== Step 4: 玄机诗 =====
out.append(f"--- Step 4: 玄机诗 (sol.2344a.cc/xuanjiziliao/) ---")
xuan_list = fetch_sol_list('/xuanjiziliao/', f'{period}期', limit=5)
if xuan_list:
for x in xuan_list:
out.append(f" • {x}")
out.append("")
# ===== 综合 =====
out.append("=" * 70)
out.append(f"⭐ {period} 期综合玄学共识")
out.append("=" * 70)
out.append("")
out.append(f"📊 {qi_minus_2} 期五行旺: " + (nim_count.most_common(1)[0][0] if nim_count else "无") + " (3 次)")
out.append(f"📊 {qi_minus_2} 期生肖: 7 个全不重 (无明显旺)")
out.append(f"📊 {qi_minus_2} 期波色: " + (Counter([x['color'] for x in last_seven]).most_common(1)[0][0] if last_seven else "无"))
out.append("")
out.append(f"🔥 挂牌 + 红字 共识: 看上面挂牌内容")
out.append("")
# ===== 期开彩 =====
out.append("=" * 70)
out.append(f"🚨 {period} 期开彩")
out.append("=" * 70)
out.append(f"日期: 2026-{period[:2]}-{period[2:]}")
out.append(f"星期: {week}")
out.append(f"时间: 21:30 {TIMEZONE_BEIJING}")
out.append("")
out.append("数据来源:")
out.append(" 1. btc.tktk.app/data/v_xg.json")
out.append(f" 2. {SOL_BASE}/zongheguapai/ (综合挂牌)")
out.append(f" 3. {SOL_BASE}/lxhz/ (六信红字)")
out.append(f" 4. {SOL_BASE}/xuanjiziliao/ (玄机诗)")
out.append("")
out.append(f"参考: skill lottery-hk v1.2.7, references/analysis-example-073/074/075.md")
return '\n'.join(out)
if __name__ == '__main__':
import urllib.request, json as _json
period = sys.argv[1] if len(sys.argv) > 1 else None
if period is None:
try:
req = urllib.request.Request('https://btc.tktk.app/data/v_xg.json',
headers={'User-Agent': 'Mozilla/5.0'})
with urllib.request.urlopen(req, timeout=10) as r:
period = _json.loads(r.read().decode('utf-8')).get('Qi', '???')
except Exception:
period = '???'
try:
print(analyze(period))
except RuntimeError as e:
print(f"\n❌ ERR: {e}", file=sys.stderr)
sys.exit(1)