Initial commit: Hermes Agent skills collection
- Trading skills (OKX, dividend, lottery, quantitative) - Creative skills (ASCII art, diagrams, video) - Development skills (GitHub, debugging, TDD) - Research skills (arXiv, blog monitoring) - Productivity skills (email, documents, notes) - MCP integration skills - Custom user skills
This commit is contained in:
@@ -0,0 +1,405 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
香港六合彩开奖抓取与分析(SQLite版)
|
||||
数据源: https://tktk.tktk4.cc/ww.htm (天空彩票)
|
||||
|
||||
用法:
|
||||
python3 lottery.py fetch # 抓取最新开奖结果
|
||||
python3 lottery.py add <期号> <号码> # 手动添加
|
||||
python3 lottery.py add_full <期号> <号码> <生肖> # 带生肖添加
|
||||
python3 lottery.py history [期数] # 查看历史记录
|
||||
python3 lottery.py analyze # 分析(频率/热号/冷号/生肖)
|
||||
python3 lottery.py zodiac # 生肖属性表
|
||||
python3 lottery.py next # 下期开奖时间
|
||||
python3 lottery.py import_json <文件> # 导入JSON历史数据
|
||||
"""
|
||||
|
||||
import json, os, sys, re, sqlite3
|
||||
from datetime import datetime
|
||||
from collections import Counter
|
||||
|
||||
DATA_DIR = os.path.expanduser("~/.hermes/trading")
|
||||
DB_FILE = os.path.join(DATA_DIR, "lottery.db")
|
||||
|
||||
# 生肖对照表(网站实际映射,从浏览器071期数据验证)
|
||||
ZODIAC_BY_MOD = {
|
||||
0: "狗", 1: "猪", 2: "蛇", 3: "马", 4: "羊", 5: "虎",
|
||||
6: "兔", 7: "鼠", 8: "牛", 9: "猴", 10: "鸡", 11: "龙"
|
||||
}
|
||||
|
||||
# 五行对照表
|
||||
ELEMENT_MAP = {
|
||||
1: "木", 2: "木", 3: "火", 4: "火", 5: "土", 6: "土",
|
||||
7: "金", 8: "金", 9: "水", 10: "水", 11: "木", 12: "木",
|
||||
13: "火", 14: "火", 15: "土", 16: "土", 17: "金", 18: "金",
|
||||
19: "水", 20: "水", 21: "木", 22: "木", 23: "火", 24: "火",
|
||||
25: "土", 26: "土", 27: "金", 28: "金", 29: "水", 30: "水",
|
||||
31: "木", 32: "木", 33: "火", 34: "火", 35: "土", 36: "土",
|
||||
37: "金", 38: "金", 39: "水", 40: "水", 41: "木", 42: "木",
|
||||
43: "火", 44: "火", 45: "土", 46: "土", 47: "金", 48: "金",
|
||||
49: "水",
|
||||
}
|
||||
|
||||
# 波色对照表
|
||||
COLOR_MAP = {
|
||||
"红波": [1, 2, 7, 8, 12, 13, 18, 19, 23, 24, 29, 30, 34, 35, 40, 45, 46],
|
||||
"蓝波": [3, 4, 9, 10, 14, 15, 20, 25, 26, 31, 36, 37, 41, 42, 47, 48],
|
||||
"绿波": [5, 6, 11, 16, 17, 21, 22, 27, 28, 32, 33, 38, 39, 43, 44, 49],
|
||||
}
|
||||
|
||||
def get_zodiac(num):
|
||||
return ZODIAC_BY_MOD.get(num % 12, "?")
|
||||
|
||||
def get_element(num):
|
||||
return ELEMENT_MAP.get(num, "?")
|
||||
|
||||
def get_color(num):
|
||||
for color, nums in COLOR_MAP.items():
|
||||
if num in nums:
|
||||
return color
|
||||
return "未知"
|
||||
|
||||
def get_db():
|
||||
os.makedirs(DATA_DIR, exist_ok=True)
|
||||
conn = sqlite3.connect(DB_FILE)
|
||||
conn.row_factory = sqlite3.Row
|
||||
conn.execute("""CREATE TABLE IF NOT EXISTS draws (
|
||||
period TEXT PRIMARY KEY,
|
||||
date TEXT,
|
||||
n1 INTEGER, n2 INTEGER, n3 INTEGER, n4 INTEGER, n5 INTEGER, n6 INTEGER,
|
||||
special INTEGER,
|
||||
z1 TEXT, z2 TEXT, z3 TEXT, z4 TEXT, z5 TEXT, z6 TEXT, z_special TEXT,
|
||||
e1 TEXT, e2 TEXT, e3 TEXT, e4 TEXT, e5 TEXT, e6 TEXT, e_special TEXT,
|
||||
c1 TEXT, c2 TEXT, c3 TEXT, c4 TEXT, c5 TEXT, c6 TEXT, c_special TEXT,
|
||||
created_at TEXT DEFAULT CURRENT_TIMESTAMP
|
||||
)""")
|
||||
conn.execute("""CREATE TABLE IF NOT EXISTS cold_data (
|
||||
key TEXT PRIMARY KEY,
|
||||
content TEXT,
|
||||
updated_at TEXT DEFAULT CURRENT_TIMESTAMP
|
||||
)""")
|
||||
conn.commit()
|
||||
return conn
|
||||
|
||||
def add_draw(period, numbers, zodiacs=None):
|
||||
"""添加开奖结果"""
|
||||
conn = get_db()
|
||||
|
||||
existing = conn.execute("SELECT period FROM draws WHERE period=?", (period,)).fetchone()
|
||||
if existing:
|
||||
print(f"⚠️ 第{period}期已存在,跳过")
|
||||
conn.close()
|
||||
return
|
||||
|
||||
nums = [int(n) for n in numbers[:6]]
|
||||
special = int(numbers[6]) if len(numbers) > 6 else 0
|
||||
|
||||
zodiac_list = []
|
||||
element_list = []
|
||||
color_list = []
|
||||
all_nums = nums + [special]
|
||||
|
||||
for i, num in enumerate(all_nums):
|
||||
if zodiacs and i < len(zodiacs):
|
||||
zodiac_list.append(zodiacs[i])
|
||||
else:
|
||||
zodiac_list.append(get_zodiac(num))
|
||||
element_list.append(get_element(num))
|
||||
color_list.append(get_color(num))
|
||||
|
||||
conn.execute("""INSERT INTO draws
|
||||
(period, date, n1,n2,n3,n4,n5,n6,special, z1,z2,z3,z4,z5,z6,z_special, e1,e2,e3,e4,e5,e6,e_special, c1,c2,c3,c4,c5,c6,c_special)
|
||||
VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)""",
|
||||
(period, datetime.now().strftime("%Y-%m-%d"),
|
||||
*nums, special,
|
||||
*zodiac_list,
|
||||
*element_list,
|
||||
*color_list))
|
||||
conn.commit()
|
||||
conn.close()
|
||||
|
||||
nums_str = " ".join([f"{n:02d}" for n in nums])
|
||||
print(f"✅ 第{period}期已添加: {nums_str} + {special:02d}")
|
||||
|
||||
def show_history(limit=10):
|
||||
"""显示历史记录"""
|
||||
conn = get_db()
|
||||
rows = conn.execute("SELECT * FROM draws ORDER BY CAST(period AS INTEGER) DESC LIMIT ?", (limit,)).fetchall()
|
||||
conn.close()
|
||||
|
||||
if not rows:
|
||||
print("📭 暂无历史记录")
|
||||
return
|
||||
|
||||
print(f"📋 最近{len(rows)}期开奖记录:\n")
|
||||
for r in rows:
|
||||
nums = [r['n1'], r['n2'], r['n3'], r['n4'], r['n5'], r['n6']]
|
||||
special = r['special']
|
||||
zodiacs = [r['z1'], r['z2'], r['z3'], r['z4'], r['z5'], r['z6']]
|
||||
elements = [r['e1'], r['e2'], r['e3'], r['e4'], r['e5'], r['e6']]
|
||||
|
||||
nums_str = " ".join([f"{n:02d}" for n in nums])
|
||||
print(f"第{r['period']}期 ({r['date']}): {nums_str} + {special:02d}")
|
||||
|
||||
info = []
|
||||
for i in range(6):
|
||||
info.append(f"{nums[i]:02d}({zodiacs[i]}/{elements[i]})")
|
||||
info.append(f"+ {special:02d}({r['z_special']}/{r['e_special']})特")
|
||||
print(f" {' '.join(info)}")
|
||||
print()
|
||||
|
||||
def analyze():
|
||||
"""分析开奖数据"""
|
||||
conn = get_db()
|
||||
rows = conn.execute("SELECT * FROM draws").fetchall()
|
||||
conn.close()
|
||||
|
||||
if not rows:
|
||||
print("📭 暂无数据")
|
||||
return
|
||||
|
||||
print(f"📊 共{len(rows)}期数据分析:\n")
|
||||
|
||||
all_nums = []
|
||||
special_nums = []
|
||||
zodiac_counter = Counter()
|
||||
element_counter = Counter()
|
||||
color_counter = Counter()
|
||||
|
||||
for r in rows:
|
||||
nums = [r['n1'], r['n2'], r['n3'], r['n4'], r['n5'], r['n6']]
|
||||
all_nums.extend(nums)
|
||||
special_nums.append(r['special'])
|
||||
|
||||
for i in range(1, 7):
|
||||
zodiac_counter[r[f'z{i}']] += 1
|
||||
element_counter[r[f'e{i}']] += 1
|
||||
color_counter[r[f'c{i}']] += 1
|
||||
zodiac_counter[r['z_special']] += 1
|
||||
element_counter[r['e_special']] += 1
|
||||
color_counter[r['c_special']] += 1
|
||||
|
||||
freq = Counter(all_nums)
|
||||
special_freq = Counter(special_nums)
|
||||
|
||||
print("🔥 热号(出现最多):")
|
||||
for num, count in freq.most_common(10):
|
||||
print(f" {num:02d} ({get_zodiac(num)}): {count}次")
|
||||
|
||||
print("\n❄️ 冷号(出现最少):")
|
||||
for num, count in freq.most_common()[-10:]:
|
||||
print(f" {num:02d} ({get_zodiac(num)}): {count}次")
|
||||
|
||||
print("\n🎯 特码频率:")
|
||||
for num, count in special_freq.most_common(10):
|
||||
print(f" {num:02d} ({get_zodiac(num)}): {count}次")
|
||||
|
||||
print("\n🐉 生肖频率:")
|
||||
for zodiac, count in zodiac_counter.most_common():
|
||||
print(f" {zodiac}: {count}次")
|
||||
|
||||
print("\n🌊 五行频率:")
|
||||
for element, count in element_counter.most_common():
|
||||
print(f" {element}: {count}次")
|
||||
|
||||
print("\n🎨 波色频率:")
|
||||
for color, count in color_counter.most_common():
|
||||
print(f" {color}: {count}次")
|
||||
|
||||
big = sum(1 for n in all_nums if n >= 25)
|
||||
small = sum(1 for n in all_nums if n < 25)
|
||||
odd = sum(1 for n in all_nums if n % 2 == 1)
|
||||
even = sum(1 for n in all_nums if n % 2 == 0)
|
||||
print(f"\n📏 大小: 大{big} / 小{small}")
|
||||
print(f"📏 单双: 单{odd} / 双{even}")
|
||||
|
||||
def save_cold_data(key, content):
|
||||
"""保存冷数据到数据库"""
|
||||
conn = get_db()
|
||||
conn.execute("""INSERT OR REPLACE INTO cold_data (key, content, updated_at)
|
||||
VALUES (?, ?, ?)""", (key, content, datetime.now().isoformat()))
|
||||
conn.commit()
|
||||
conn.close()
|
||||
print(f"✅ 冷数据已保存: {key}")
|
||||
|
||||
def get_cold_data(key):
|
||||
"""获取冷数据"""
|
||||
conn = get_db()
|
||||
row = conn.execute("SELECT content FROM cold_data WHERE key=?", (key,)).fetchone()
|
||||
conn.close()
|
||||
return row['content'] if row else None
|
||||
|
||||
def import_json(filepath):
|
||||
"""导入JSON历史数据到SQLite"""
|
||||
with open(filepath) as f:
|
||||
data = json.load(f)
|
||||
|
||||
conn = get_db()
|
||||
count = 0
|
||||
for item in data:
|
||||
period = item.get('period')
|
||||
if not period:
|
||||
continue
|
||||
|
||||
existing = conn.execute("SELECT period FROM draws WHERE period=?", (period,)).fetchone()
|
||||
if existing:
|
||||
continue
|
||||
|
||||
numbers = item.get('numbers', [])
|
||||
special = item.get('special', 0)
|
||||
zodiacs_raw = [d.get('zodiac') for d in item.get('details', [])]
|
||||
|
||||
if len(numbers) < 6:
|
||||
continue
|
||||
|
||||
all_nums = numbers[:6] + [special]
|
||||
zodiac_list = []
|
||||
element_list = []
|
||||
color_list = []
|
||||
|
||||
for i, num in enumerate(all_nums):
|
||||
if zodiacs_raw and i < len(zodiacs_raw) and zodiacs_raw[i]:
|
||||
zodiac_list.append(zodiacs_raw[i])
|
||||
else:
|
||||
zodiac_list.append(get_zodiac(num))
|
||||
element_list.append(get_element(num))
|
||||
color_list.append(get_color(num))
|
||||
|
||||
conn.execute("""INSERT INTO draws
|
||||
(period, date, n1,n2,n3,n4,n5,n6,special, z1,z2,z3,z4,z5,z6,z_special, e1,e2,e3,e4,e5,e6,e_special, c1,c2,c3,c4,c5,c6,c_special)
|
||||
VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)""",
|
||||
(period, item.get('date', ''),
|
||||
*numbers[:6], special,
|
||||
*zodiac_list, *element_list, *color_list))
|
||||
count += 1
|
||||
|
||||
conn.commit()
|
||||
conn.close()
|
||||
print(f"✅ 导入{count}条记录")
|
||||
|
||||
def zodiac_table():
|
||||
"""显示生肖属性表"""
|
||||
print("🐉 2026年生肖号码对照表(网站实际映射):\n")
|
||||
zodiac_nums = {}
|
||||
for num in range(1, 50):
|
||||
zodiac = get_zodiac(num)
|
||||
if zodiac not in zodiac_nums:
|
||||
zodiac_nums[zodiac] = []
|
||||
zodiac_nums[zodiac].append(num)
|
||||
for zodiac in ["鼠", "牛", "虎", "兔", "龙", "蛇", "马", "羊", "猴", "鸡", "狗", "猪"]:
|
||||
nums = zodiac_nums.get(zodiac, [])
|
||||
print(f" {zodiac}: {', '.join([f'{n:02d}' for n in nums])}")
|
||||
|
||||
def next_draw():
|
||||
conn = get_db()
|
||||
r = conn.execute("SELECT * FROM draws ORDER BY CAST(period AS INTEGER) DESC LIMIT 1").fetchone()
|
||||
conn.close()
|
||||
|
||||
if r:
|
||||
nums = [r['n1'], r['n2'], r['n3'], r['n4'], r['n5'], r['n6']]
|
||||
print(f"📊 最新开奖: 第{r['period']}期")
|
||||
print(f" 号码: {' '.join([f'{n:02d}' for n in nums])} + {r['special']:02d}")
|
||||
print(f"\n⏰ 下期开奖时间: 每周二、四、六 21:30")
|
||||
print(f" 数据源: https://tktk.tktk4.cc/ww.htm")
|
||||
|
||||
def save_image_link(category, title, url, period=None):
|
||||
"""保存图片链接到数据库"""
|
||||
conn = get_db()
|
||||
conn.execute("INSERT INTO image_links (category, title, url, period) VALUES (?,?,?,?)",
|
||||
(category, title, url, period))
|
||||
conn.commit()
|
||||
conn.close()
|
||||
print(f"✅ 图片链接已保存: {category}/{title}")
|
||||
|
||||
def list_image_links(category=None, period=None):
|
||||
"""列出图片链接"""
|
||||
conn = get_db()
|
||||
sql = "SELECT * FROM image_links WHERE 1=1"
|
||||
params = []
|
||||
if category:
|
||||
sql += " AND category=?"
|
||||
params.append(category)
|
||||
if period:
|
||||
sql += " AND period=?"
|
||||
params.append(period)
|
||||
sql += " ORDER BY created_at DESC LIMIT 50"
|
||||
rows = conn.execute(sql, params).fetchall()
|
||||
conn.close()
|
||||
if not rows:
|
||||
print("📭 暂无图片链接")
|
||||
return
|
||||
for r in rows:
|
||||
print(f"[{r['category']}] {r['title']}: {r['url']}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
if len(sys.argv) < 2:
|
||||
print(__doc__)
|
||||
sys.exit(0)
|
||||
|
||||
cmd = sys.argv[1]
|
||||
|
||||
if cmd == "fetch":
|
||||
print("⚠️ 页面使用Vue.js动态加载,开奖时间段外(21:14-21:40)可能无数据")
|
||||
print(" 建议开奖期间用浏览器抓取,或用 add 命令手动添加")
|
||||
|
||||
elif cmd == "history":
|
||||
limit = int(sys.argv[2]) if len(sys.argv) > 2 else 10
|
||||
show_history(limit)
|
||||
|
||||
elif cmd == "analyze":
|
||||
analyze()
|
||||
|
||||
elif cmd == "zodiac":
|
||||
zodiac_table()
|
||||
|
||||
elif cmd == "next":
|
||||
next_draw()
|
||||
|
||||
elif cmd == "add":
|
||||
if len(sys.argv) < 4:
|
||||
print("用法: python3 lottery.py add <期号> <号码,逗号分隔>")
|
||||
sys.exit(1)
|
||||
add_draw(sys.argv[2], [int(x) for x in sys.argv[3].split(",")])
|
||||
|
||||
elif cmd == "add_full":
|
||||
if len(sys.argv) < 5:
|
||||
print("用法: python3 lottery.py add_full <期号> <号码> <生肖>")
|
||||
sys.exit(1)
|
||||
add_draw(sys.argv[2], [int(x) for x in sys.argv[3].split(",")], sys.argv[4].split(","))
|
||||
|
||||
elif cmd == "import_json":
|
||||
if len(sys.argv) < 3:
|
||||
print("用法: python3 lottery.py import_json <文件路径>")
|
||||
sys.exit(1)
|
||||
import_json(sys.argv[2])
|
||||
|
||||
elif cmd == "save_cold":
|
||||
if len(sys.argv) < 4:
|
||||
print("用法: python3 lottery.py save_cold <key> <content>")
|
||||
sys.exit(1)
|
||||
save_cold_data(sys.argv[2], sys.argv[3])
|
||||
|
||||
elif cmd == "get_cold":
|
||||
if len(sys.argv) < 3:
|
||||
print("用法: python3 lottery.py get_cold <key>")
|
||||
sys.exit(1)
|
||||
content = get_cold_data(sys.argv[2])
|
||||
if content:
|
||||
print(content)
|
||||
else:
|
||||
print("📭 无数据")
|
||||
|
||||
elif cmd == "save_image":
|
||||
if len(sys.argv) < 5:
|
||||
print("用法: python3 lottery.py save_image <类别> <标题> <URL> [期号]")
|
||||
sys.exit(1)
|
||||
period = sys.argv[5] if len(sys.argv) > 5 else None
|
||||
save_image_link(sys.argv[2], sys.argv[3], sys.argv[4], period)
|
||||
|
||||
elif cmd == "list_images":
|
||||
category = sys.argv[2] if len(sys.argv) > 2 else None
|
||||
list_image_links(category)
|
||||
|
||||
else:
|
||||
print(f"未知命令: {cmd}")
|
||||
print(__doc__)
|
||||
Reference in New Issue
Block a user