init: 福彩3D数据分析工具

This commit is contained in:
Colin
2026-08-03 17:22:18 +08:00
commit e974939b8a
22 changed files with 37382 additions and 0 deletions
+166
View File
@@ -0,0 +1,166 @@
"""
福彩3D历史数据抓取脚本
数据来源:中国福利彩票官网 (cwl.gov.cn)
输出格式:JSON,字段 { period, date, hundreds, tens, ones }
"""
import requests
import json
import time
import os
import sys
# 输出路径
OUTPUT_FILE = os.path.join(os.path.dirname(__file__), '..', 'src', 'data', 'history.json')
# 福彩3D API
BASE_URL = 'https://www.cwl.gov.cn/cwl_admin/front/cwlkj/search/kjxx/findDrawNotice'
HEADERS = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
'Referer': 'https://www.cwl.gov.cn/',
}
def fetch_page(page_no, page_size=100):
"""获取一页数据"""
params = {
'name': '3d',
'issueCount': '',
'issueStart': '',
'issueEnd': '',
'dayStart': '',
'dayEnd': '',
'pageNo': page_no,
'pageSize': page_size,
'systemType': 'PC',
}
try:
resp = requests.get(BASE_URL, params=params, headers=HEADERS, timeout=30)
resp.raise_for_status()
data = resp.json()
return data
except requests.exceptions.RequestException as e:
print(f' [请求失败] 第 {page_no} 页: {e}')
return None
except json.JSONDecodeError as e:
print(f' [解析失败] 第 {page_no} 页: {e}')
return None
def parse_result(item):
"""解析单条开奖数据"""
# 开奖号码格式: "9,7,8" 或 "1 4 7"
code = item.get('red', '')
if not code:
return None
# 支持逗号或空格分隔
code = code.replace(',', ' ')
parts = code.strip().split()
if len(parts) != 3:
parts = list(code.replace(' ', '').strip())
try:
hundreds = int(parts[0])
tens = int(parts[1])
ones = int(parts[2])
except (ValueError, IndexError):
return None
# 日期格式 "2026-08-02(日)" -> "2026-08-02"
date_str = item.get('date', '')
date_str = date_str.split('(')[0]
return {
'period': item.get('code', ''), # 期号
'date': date_str, # 日期
'hundreds': hundreds,
'tens': tens,
'ones': ones,
}
def main():
print('福彩3D历史数据抓取')
print('=' * 50)
all_data = []
page_no = 1
max_consecutive_empty = 3 # 连续空页数上限
empty_count = 0
while True:
print(f'正在获取第 {page_no} 页...', end=' ')
data = fetch_page(page_no)
if not data:
empty_count += 1
if empty_count >= max_consecutive_empty:
print(f'\n连续 {max_consecutive_empty} 页失败,停止')
break
page_no += 1
time.sleep(1)
continue
empty_count = 0
items = data.get('result', [])
if not items:
print('无数据,抓取完成')
break
page_data = []
for item in items:
parsed = parse_result(item)
if parsed:
page_data.append(parsed)
all_data.extend(page_data)
print(f'获取 {len(page_data)} 条')
# 检查是否还有更多页
total_pages = data.get('pageNum', 0)
if page_no >= total_pages:
print(f'已获取全部 {total_pages} 页')
break
page_no += 1
time.sleep(0.5) # 避免请求过快
# 去重并排序(按日期升序)
seen = set()
unique_data = []
for d in all_data:
if d['period'] not in seen:
seen.add(d['period'])
unique_data.append(d)
unique_data.sort(key=lambda x: (x['date'], x['period']))
print(f'\n总计获取 {len(unique_data)} 条唯一数据')
if not unique_data:
print('未获取到任何数据,可能 API 有变动。')
print('可以尝试手动从 https://www.cwl.gov.cn/ 下载数据。')
return
# 写入文件
os.makedirs(os.path.dirname(OUTPUT_FILE), exist_ok=True)
json_str = json.dumps(unique_data, ensure_ascii=False, indent=2)
with open(OUTPUT_FILE, 'w', encoding='utf-8') as f:
f.write(json_str)
print(f'已保存到: {OUTPUT_FILE}')
# 摘要
first = unique_data[0]
last = unique_data[-1]
print(f'数据范围: {first["period"]} ({first["date"]}) ~ {last["period"]} ({last["date"]})')
# 构建后重新运行
print(f'\n数据已更新,重新构建项目即可生效:')
print(f' npm run build')
if __name__ == '__main__':
main()