""" 福彩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()