From 13a259b0f8e52cf64fdebe854b6315df71d81bdb Mon Sep 17 00:00:00 2001 From: bizwings Date: Fri, 3 Jul 2026 16:39:21 +0800 Subject: [PATCH] =?UTF-8?q?chore:=20initial=20commit=20=E2=80=94=20existin?= =?UTF-8?q?g=20lottoData=20codebase?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Files: - lottery.py (1189 lines) — DoubleColorBallGenerator core engine - fetch_data.py (131 lines) — history data fetcher from 55128.cn - web_executor.py (216 lines) — data fetch Web console (Flask :5000) - app.py (505 lines) — number generation Web service (Flask :8085) - index.html (1171 lines) — frontend SPA - web_console.html (323 lines) — fetch console frontend - deploy/ — systemd service + cron script + logs BIZ-74 architecture review baseline --- .gitignore | 7 + app.py | 505 +++++++ deploy/DEPLOY.md | 178 +++ deploy/fetch_daily.sh | 17 + deploy/lotto-web.service | 16 + docs/PRD-20260619-双色球数据抓取系统.md | 396 ++++++ docs/PRD-双色球 WebUI-v1.0.md | 361 +++++ docs/PRD-操作界面系统.md | 512 +++++++ fetch_data.py | 132 ++ index.html | 1171 ++++++++++++++++ lottery.py | 1189 +++++++++++++++++ .../双色球模拟号码-1000注-20260122-001.xlsx | Bin 0 -> 64306 bytes lottery/双色球模拟号码-2注-20260208-001.xlsx | Bin 0 -> 6208 bytes lottery/双色球模拟号码-2注-20260521-001.xlsx | Bin 0 -> 6202 bytes lottery/双色球模拟号码-3注-20260208-001.xlsx | Bin 0 -> 11125 bytes lottery/双色球模拟号码-3注-20260521-001.xlsx | Bin 0 -> 10082 bytes lottery/双色球模拟号码-5注-20260130-001.xlsx | Bin 0 -> 10305 bytes lottery/双色球模拟号码-5注-20260130-002.xlsx | Bin 0 -> 6371 bytes lottery/双色球模拟号码-5注-20260205-001.xlsx | Bin 0 -> 11488 bytes lottery/双色球模拟号码-5注-20260205-002.xlsx | Bin 0 -> 6373 bytes lottery/双色球模拟号码-5注-20260208-001.xlsx | Bin 0 -> 11298 bytes lottery/双色球模拟号码-5注-20260210-001.xlsx | Bin 0 -> 11266 bytes lottery/双色球模拟号码-5注-20260503-001.xlsx | Bin 0 -> 6375 bytes lottery/双色球模拟号码-5注-20260503-002.xlsx | Bin 0 -> 10218 bytes web_console.html | 324 +++++ web_executor.py | 217 +++ 双色球历史数据.xlsx | Bin 0 -> 12808 bytes 27 files changed, 5025 insertions(+) create mode 100644 .gitignore create mode 100644 app.py create mode 100644 deploy/DEPLOY.md create mode 100755 deploy/fetch_daily.sh create mode 100644 deploy/lotto-web.service create mode 100644 docs/PRD-20260619-双色球数据抓取系统.md create mode 100644 docs/PRD-双色球 WebUI-v1.0.md create mode 100644 docs/PRD-操作界面系统.md create mode 100644 fetch_data.py create mode 100644 index.html create mode 100644 lottery.py create mode 100644 lottery/双色球模拟号码-1000注-20260122-001.xlsx create mode 100644 lottery/双色球模拟号码-2注-20260208-001.xlsx create mode 100644 lottery/双色球模拟号码-2注-20260521-001.xlsx create mode 100644 lottery/双色球模拟号码-3注-20260208-001.xlsx create mode 100644 lottery/双色球模拟号码-3注-20260521-001.xlsx create mode 100644 lottery/双色球模拟号码-5注-20260130-001.xlsx create mode 100644 lottery/双色球模拟号码-5注-20260130-002.xlsx create mode 100644 lottery/双色球模拟号码-5注-20260205-001.xlsx create mode 100644 lottery/双色球模拟号码-5注-20260205-002.xlsx create mode 100644 lottery/双色球模拟号码-5注-20260208-001.xlsx create mode 100644 lottery/双色球模拟号码-5注-20260210-001.xlsx create mode 100644 lottery/双色球模拟号码-5注-20260503-001.xlsx create mode 100644 lottery/双色球模拟号码-5注-20260503-002.xlsx create mode 100644 web_console.html create mode 100644 web_executor.py create mode 100644 双色球历史数据.xlsx diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e559128 --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +__pycache__/ +*.pyc +.DS_Store +venv/ +.venv/ +LottoSpider/ +*.log diff --git a/app.py b/app.py new file mode 100644 index 0000000..8226c27 --- /dev/null +++ b/app.py @@ -0,0 +1,505 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +双色球 Web UI 服务 +集成号码生成、历史数据查看、生成记录管理 +监听 0.0.0.0,支持 PC 端和移动端响应式访问 +""" + +import os +import sys +import json +import uuid +import shutil +import traceback +from datetime import datetime +from flask import Flask, send_from_directory, jsonify, request, send_file, abort +from functools import wraps + +# 将项目目录加入路径,以便导入 lottery.py +BASE_DIR = os.path.dirname(os.path.abspath(__file__)) +sys.path.insert(0, BASE_DIR) + +# 导入号码生成器 +from lottery import DoubleColorBallGenerator + +app = Flask(__name__) + +# ============================================================ +# 配置 +# ============================================================ +CONFIG = { + 'host': '0.0.0.0', + 'port': 8085, + 'history_file': os.path.join(BASE_DIR, '双色球历史数据.xlsx'), + 'lottery_output_dir': os.path.join(BASE_DIR, 'lottery'), + 'records_file': os.path.join(BASE_DIR, '.generation_records.json'), + 'api_token': 'lotto2026', + 'auth_enabled': False, + 'max_tickets': 1000, + 'default_tickets': 10, +} + +# ============================================================ +# 生成记录管理 +# ============================================================ +def load_records(): + """加载生成记录""" + if os.path.exists(CONFIG['records_file']): + try: + with open(CONFIG['records_file'], 'r', encoding='utf-8') as f: + return json.load(f) + except: + return [] + return [] + +def save_records(records): + """保存生成记录""" + os.makedirs(os.path.dirname(CONFIG['records_file']), exist_ok=True) + with open(CONFIG['records_file'], 'w', encoding='utf-8') as f: + json.dump(records, f, ensure_ascii=False, indent=2) + +def add_record(strategy, num_tickets, filename): + """添加一条生成记录""" + records = load_records() + records.insert(0, { + 'id': str(uuid.uuid4())[:8], + 'created_at': datetime.now().strftime('%Y-%m-%d %H:%M:%S'), + 'strategy': '高级策略' if strategy == 'advanced' else '基础策略', + 'num_tickets': num_tickets, + 'filename': filename, + 'filesize': os.path.getsize(os.path.join(BASE_DIR, filename)) if os.path.exists(os.path.join(BASE_DIR, filename)) else 0 + }) + save_records(records) + return records[0] + +# ============================================================ +# 认证装饰器(可选) +# ============================================================ +def require_auth(f): + @wraps(f) + def decorated(*args, **kwargs): + if CONFIG['auth_enabled']: + token = request.headers.get('Authorization', '').replace('Bearer ', '') + if token != CONFIG['api_token']: + return jsonify({'success': False, 'error': '未授权访问'}), 401 + return f(*args, **kwargs) + return decorated + +# ============================================================ +# API:号码生成 +# ============================================================ +@app.route('/api/generate', methods=['POST']) +@require_auth +def api_generate(): + """生成双色球号码""" + try: + data = request.get_json(force=True, silent=True) or {} + num_tickets = int(data.get('num_tickets', CONFIG['default_tickets'])) + strategy = data.get('strategy', 'advanced') + + # 参数校验 + if num_tickets < 1 or num_tickets > CONFIG['max_tickets']: + return jsonify({ + 'success': False, + 'error': f'注数必须在 1-{CONFIG["max_tickets"]} 之间' + }), 400 + + if strategy not in ('advanced', 'basic'): + return jsonify({'success': False, 'error': '策略参数无效,请使用 advanced 或 basic'}), 400 + + # 初始化生成器 + generator = DoubleColorBallGenerator(CONFIG['history_file']) + if not generator.load_history_data(): + return jsonify({'success': False, 'error': '无法加载历史数据'}), 500 + + # 生成号码 + tickets_df = generator.generate_multiple_tickets(num_tickets, strategy) + if tickets_df.empty: + return jsonify({'success': False, 'error': '号码生成失败'}), 500 + + # 保存到 Excel + filename = generator.save_to_excel(tickets_df, num_tickets, strategy) + if not filename: + return jsonify({'success': False, 'error': '文件保存失败'}), 500 + + # 获取相对路径 + rel_path = os.path.relpath(filename, BASE_DIR) + + # 添加生成记录 + record = add_record(strategy, num_tickets, rel_path) + + # 构建返回数据 + tickets_data = [] + for _, row in tickets_df.iterrows(): + tickets_data.append({ + 'index': int(row['序号']), + 'reds': [int(row[f'红球{i}']) for i in range(1, 7)], + 'blue': int(row['蓝球']), + 'sum_value': int(row['和值']), + 'odd_even': row['奇偶比'], + 'size_ratio': row['大小比'], + 'span': int(row['跨度']) + }) + + # 获取统计信息 + stats = get_statistics_data(generator) + + return jsonify({ + 'success': True, + 'data': { + 'tickets': tickets_data[:50], # 前端最多展示 50 注 + 'total': len(tickets_data), + 'filename': rel_path, + 'download_url': f'/api/download/{rel_path}', + 'record': record, + 'statistics': stats + } + }) + + except Exception as e: + return jsonify({'success': False, 'error': f'生成失败: {str(e)}'}), 500 + + +def get_statistics_data(generator=None): + """获取统计数据""" + import pandas as pd + import re + from collections import Counter + + if not os.path.exists(CONFIG['history_file']): + return {} + + # 直接解析 Excel,跳过描述行 + df = pd.read_excel(CONFIG['history_file'], header=None) + data_df = df.iloc[1:].copy() + data_df.columns = ['开奖日期', '期号', '红球', '开机号', '和值特征', '奇偶形态', '大小比', '奇偶形态2', '跨度', '其他'] + + # 解析红球和蓝球 + red_ball_counts = Counter() + blue_ball_counts = Counter() + sum_values = [] + span_values = [] + + for _, row in data_df.iterrows(): + s = str(row['红球']).strip() + if len(s) >= 14: + reds = [int(s[i:i+2]) for i in range(0, 12, 2)] + blue = int(s[12:14]) + if all(1 <= r <= 33 for r in reds) and 1 <= blue <= 16: + red_ball_counts.update(reds) + blue_ball_counts[blue] += 1 + sum_values.append(sum(reds)) + span_values.append(max(reds) - min(reds)) + + stats = {} + + if red_ball_counts: + sorted_reds = sorted(red_ball_counts.items(), key=lambda x: x[1], reverse=True) + stats['hot_reds'] = [x[0] for x in sorted_reds[:15]] + stats['cold_reds'] = [x[0] for x in sorted_reds[-15:]] + + if blue_ball_counts: + sorted_blues = sorted(blue_ball_counts.items(), key=lambda x: x[1], reverse=True) + stats['hot_blues'] = [x[0] for x in sorted_blues[:8]] + + # 奇偶比统计 + odd_even_ratios = Counter() + size_ratios = Counter() + for _, row in data_df.iterrows(): + oe = str(row['奇偶形态']).strip() + sz = str(row['大小比']).strip() + if oe and oe != 'nan': + odd_even_ratios[oe] += 1 + if sz and sz != 'nan': + size_ratios[sz] += 1 + + if odd_even_ratios: + stats['common_odd_even'] = max(odd_even_ratios, key=odd_even_ratios.get) + + if size_ratios: + stats['common_size_ratio'] = max(size_ratios, key=size_ratios.get) + + # 和值 + if sum_values: + import numpy as np + arr = np.array(sum_values) + stats['sum_range'] = { + 'min': int(arr.min()), + 'max': int(arr.max()), + 'mean': float(arr.mean()), + 'std': float(arr.std()) + } + + # 跨度 + if span_values: + import numpy as np + arr = np.array(span_values) + stats['span_range'] = { + 'min': int(arr.min()), + 'max': int(arr.max()), + 'mean': float(arr.mean()), + 'std': float(arr.std()) + } + + stats['history_count'] = len(data_df) + + return stats + + +# ============================================================ +# API:获取统计数据 +# ============================================================ +@app.route('/api/statistics') +@require_auth +def api_statistics(): + """获取统计数据""" + try: + stats = get_statistics_data() + return jsonify({'success': True, 'data': stats}) + except Exception as e: + return jsonify({'success': False, 'error': str(e)}), 500 + + +# ============================================================ +# API:获取生成记录 +# ============================================================ +@app.route('/api/records') +@require_auth +def api_records(): + """获取生成记录列表""" + try: + page = int(request.args.get('page', 1)) + page_size = int(request.args.get('page_size', 20)) + records = load_records() + + total = len(records) + start = (page - 1) * page_size + end = start + page_size + page_records = records[start:end] + + return jsonify({ + 'success': True, + 'data': { + 'records': page_records, + 'total': total, + 'page': page, + 'page_size': page_size + } + }) + except Exception as e: + return jsonify({'success': False, 'error': str(e)}), 500 + + +# ============================================================ +# API:删除生成记录 +# ============================================================ +@app.route('/api/records/', methods=['DELETE']) +@require_auth +def api_delete_record(record_id): + """删除生成记录""" + try: + records = load_records() + target = None + for r in records: + if r['id'] == record_id: + target = r + break + + if not target: + return jsonify({'success': False, 'error': '记录不存在'}), 404 + + # 删除文件 + filepath = os.path.join(BASE_DIR, target['filename']) + if os.path.exists(filepath): + os.remove(filepath) + + # 删除记录 + records = [r for r in records if r['id'] != record_id] + save_records(records) + + return jsonify({'success': True, 'message': '记录已删除'}) + except Exception as e: + return jsonify({'success': False, 'error': str(e)}), 500 + + +# ============================================================ +# API:文件下载 +# ============================================================ +@app.route('/api/download/') +@require_auth +def api_download(filepath): + """下载文件""" + try: + # 安全检查:防止目录遍历 + safe_path = os.path.normpath(filepath) + if safe_path.startswith('..') or safe_path.startswith('/'): + abort(403) + + full_path = os.path.join(BASE_DIR, safe_path) + if not os.path.exists(full_path): + abort(404) + + return send_file(full_path, as_attachment=True) + except Exception: + abort(404) + + +# ============================================================ +# API:历史数据查看 +# ============================================================ +@app.route('/api/history') +@require_auth +def api_history(): + """获取双色球历史开奖数据""" + try: + page = int(request.args.get('page', 1)) + page_size = int(request.args.get('page_size', 20)) + search = request.args.get('search', '').strip() + + # 读取历史数据 + if not os.path.exists(CONFIG['history_file']): + return jsonify({'success': False, 'error': '历史数据文件不存在'}), 404 + + import pandas as pd + import re + df = pd.read_excel(CONFIG['history_file'], header=None) + + # 第一行是描述行,跳过 + data_df = df.iloc[1:].copy() + data_df.columns = ['开奖日期', '期号', '红球', '开机号', '和值特征', '奇偶形态', '大小比', '奇偶形态2', '跨度', '其他'] + data_df = data_df.reset_index(drop=True) + + # 解析红球(红球列是6个红球+蓝球的拼接字符串,如 '09101316192108') + def parse_red_balls(val): + s = str(val).strip() + if len(s) >= 12: + return [int(s[i:i+2]) for i in range(0, 12, 2)] + return [] + + def parse_blue_ball(val): + s = str(val).strip() + if len(s) >= 14: + return int(s[12:14]) + return None + + data_df['红球列表'] = data_df['红球'].apply(parse_red_balls) + data_df['蓝球'] = data_df['红球'].apply(parse_blue_ball) + + # 搜索过滤 + if search: + mask = data_df.astype(str).apply( + lambda row: row.astype(str).str.contains(search, na=False).any(), axis=1 + ) + data_df = data_df[mask] + + total = len(data_df) + + # 分页 + start = (page - 1) * page_size + end = start + page_size + page_df = data_df.iloc[start:end] + + # 转换为 JSON + records = [] + for _, row in page_df.iterrows(): + reds = row['红球列表'] + record = { + '开奖日期': str(row['开奖日期']), + '期号': str(row['期号']), + '红球': reds if len(reds) == 6 else [], + '蓝球': row['蓝球'], + '开机号': str(row['开机号']), + '和值': str(row['和值特征']), + '奇偶形态': str(row['奇偶形态']), + '大小比': str(row['大小比']), + '跨度': str(row['跨度']), + } + records.append(record) + + return jsonify({ + 'success': True, + 'data': { + 'records': records, + 'total': total, + 'page': page, + 'page_size': page_size, + 'columns': ['开奖日期', '期号', '红球', '蓝球', '开机号', '和值', '大小比', '跨度'] + } + }) + except Exception as e: + return jsonify({'success': False, 'error': str(e)}), 500 + + +# ============================================================ +# API:系统状态 +# ============================================================ +@app.route('/api/status') +def api_status(): + """获取系统状态""" + try: + history_exists = os.path.exists(CONFIG['history_file']) + history_size = os.path.getsize(CONFIG['history_file']) if history_exists else 0 + lottery_files = [] + if os.path.exists(CONFIG['lottery_output_dir']): + lottery_files = [f for f in os.listdir(CONFIG['lottery_output_dir']) if f.endswith('.xlsx')] + + records = load_records() + + return jsonify({ + 'success': True, + 'data': { + 'server_time': datetime.now().strftime('%Y-%m-%d %H:%M:%S'), + 'history_exists': history_exists, + 'history_size': history_size, + 'total_generations': len(records), + 'total_lottery_files': len(lottery_files), + 'config': { + 'port': CONFIG['port'], + 'auth_enabled': CONFIG['auth_enabled'], + 'max_tickets': CONFIG['max_tickets'] + } + } + }) + except Exception as e: + return jsonify({'success': False, 'error': str(e)}), 500 + + +# ============================================================ +# 前端页面 +# ============================================================ +@app.route('/') +def index(): + """首页 - 双色球 Web UI""" + return send_from_directory(BASE_DIR, 'index.html') + + +@app.route('/api/config') +def api_config(): + """获取前端配置""" + return jsonify({ + 'success': True, + 'data': { + 'max_tickets': CONFIG['max_tickets'], + 'default_tickets': CONFIG['default_tickets'], + 'auth_enabled': CONFIG['auth_enabled'] + } + }) + + +# ============================================================ +# 启动服务 +# ============================================================ +if __name__ == '__main__': + print('=' * 60) + print('🎯 双色球 Web UI 服务') + print('=' * 60) + print(f'\n📂 项目路径: {BASE_DIR}') + print(f'📁 历史数据: {CONFIG["history_file"]}') + print(f'📁 生成目录: {CONFIG["lottery_output_dir"]}') + print(f'\n🌐 服务地址: http://{CONFIG["host"]}:{CONFIG["port"]}') + print(f' 局域网访问: http://<本机IP>:{CONFIG["port"]}') + print(f'\n✅ 服务就绪!') + print('=' * 60) + + app.run(host=CONFIG['host'], port=CONFIG['port'], debug=False, threaded=True) diff --git a/deploy/DEPLOY.md b/deploy/DEPLOY.md new file mode 100644 index 0000000..3f15f4f --- /dev/null +++ b/deploy/DEPLOY.md @@ -0,0 +1,178 @@ +# 双色球系统部署文档 + +## 部署信息 + +| 项目 | 值 | +|------|-----| +| 项目名称 | 双色球自动化系统 | +| 部署时间 | 2026-06-29 | +| 部署人员 | 严维序 (opengineer) | +| 服务地址 | http://192.168.1.99:5000 | +| 宿主服务器 | Ubuntu-OpenClaw (192.168.1.99) | + +--- + +## 一、项目结构 + +``` +/home/vincent/Studio/lottoData/ +├── venv/ # Python 虚拟环境 +├── web_executor.py # Flask Web 服务 (监听 0.0.0.0:5000) +├── fetch_data.py # 数据抓取脚本 +├── lottery.py # 双色球号码生成器 +├── web_console.html # Web 控制台页面 +├── LottoSpider/ # 爬虫模块 +├── lottery/ # 彩票模块 +├── docs/ # 文档 +├── 双色球历史数据.xlsx # 历史数据文件 +└── deploy/ # 部署文件 + ├── DEPLOY.md # 本文档 + ├── lotto-web.service # systemd 服务文件 + ├── fetch_daily.sh # 每日抓取脚本 + ├── cron.log # Cron 执行日志 + └── fetch_YYYYMMDD.log # 每日抓取详细日志 +``` + +--- + +## 二、依赖清单 + +| 包 | 版本 | 用途 | +|----|------|------| +| Flask | 3.1.3 | Web 服务框架 | +| pandas | 3.0.4 | 数据处理 | +| openpyxl | 3.1.5 | Excel 读写 | +| requests | 2.34.2 | HTTP 请求 | +| beautifulsoup4 | 4.15.0 | HTML 解析 | + +安装命令: +```bash +python3 -m venv venv +./venv/bin/pip install flask pandas openpyxl requests beautifulsoup4 +``` + +--- + +## 三、systemd 服务配置 + +### 服务文件 + +`/etc/systemd/system/lotto-web.service` + +```ini +[Unit] +Description=双色球数据抓取 Web 服务 +After=network.target + +[Service] +Type=simple +User=vincent +WorkingDirectory=/home/vincent/Studio/lottoData +ExecStart=/home/vincent/Studio/lottoData/venv/bin/python3 /home/vincent/Studio/lottoData/web_executor.py +ExecStartPre=/home/vincent/Studio/lottoData/venv/bin/python3 -c "import flask; import pandas; import openpyxl; import requests; import bs4" +Restart=on-failure +RestartSec=5 +KillMode=control-group + +[Install] +WantedBy=multi-user.target +``` + +### 管理命令 + +```bash +# 安装/启用 +sudo cp deploy/lotto-web.service /etc/systemd/system/ +sudo systemctl daemon-reload +sudo systemctl enable lotto-web +sudo systemctl start lotto-web + +# 日常管理 +sudo systemctl status lotto-web # 查看状态 +sudo systemctl restart lotto-web # 重启 +sudo systemctl stop lotto-web # 停止 +sudo journalctl -u lotto-web -f # 查看实时日志 +``` + +--- + +## 四、Cron 定时任务 + +### Cron 配置 + +``` +30 2 * * * /home/vincent/Studio/lottoData/deploy/fetch_daily.sh >> /home/vincent/Studio/lottoData/deploy/cron.log 2>&1 +``` + +每天凌晨 2:30 自动抓取双色球历史数据。 + +### 手动执行 + +```bash +/home/vincent/Studio/lottoData/deploy/fetch_daily.sh +# 或 +/home/vincent/Studio/lottoData/venv/bin/python3 /home/vincent/Studio/lottoData/fetch_data.py +``` + +--- + +## 五、Web 接口 + +| 路径 | 方法 | 说明 | +|------|------|------| +| `/` | GET | Web 控制台页面 | +| `/api/status` | GET | 获取执行状态 | +| `/api/execute` | POST | 触发数据抓取 | + +### 示例 + +```bash +# 查看状态 +curl http://192.168.1.99:5000/api/status + +# 触发抓取 +curl -X POST http://192.168.1.99:5000/api/execute +``` + +--- + +## 六、验证清单 + +- [x] 依赖安装完整 (Flask, pandas, openpyxl, requests, beautifulsoup4) +- [x] systemd 服务运行正常 (active, enabled) +- [x] Web 服务可访问 (http://192.168.1.99:5000, HTTP 200) +- [x] API 接口正常 (/api/status, /api/execute) +- [x] Cron 定时任务已配置 (每日 2:30 抓取) +- [x] 手动抓取测试通过 (121 条记录保存成功) +- [x] 开机自启已配置 (systemd enable) + +--- + +## 七、回滚方案 + +```bash +# 停止服务 +sudo systemctl stop lotto-web +sudo systemctl disable lotto-web +sudo rm /etc/systemd/system/lotto-web.service +sudo systemctl daemon-reload + +# 移除 cron +crontab -l | grep -v 'lottoData' | crontab - + +# 不影响数据文件和代码 +``` + +--- + +## 八、监控要点 + +1. **服务存活**:`systemctl status lotto-web` 确认 active +2. **Web 可达**:`curl http://127.0.0.1:5000/api/status` +3. **数据更新**:检查 `/home/vincent/Studio/lottoData/双色球历史数据.xlsx` 修改时间 +4. **Cron 日志**:检查 `/home/vincent/Studio/lottoData/deploy/cron.log` +5. **磁盘空间**:Excel 文件约 250KB,可忽略 + +--- + +> 部署人:严维序 (opengineer) | 2026-06-29 \ No newline at end of file diff --git a/deploy/fetch_daily.sh b/deploy/fetch_daily.sh new file mode 100755 index 0000000..6fbe046 --- /dev/null +++ b/deploy/fetch_daily.sh @@ -0,0 +1,17 @@ +#!/bin/bash +# 双色球历史数据每日自动抓取 +# Cron: 0 2 * * * /home/vincent/Studio/lottoData/deploy/fetch_daily.sh >> /home/vincent/Studio/lottoData/deploy/cron.log 2>&1 + +SCRIPT_DIR="/home/vincent/Studio/lottoData" +VENV_PYTHON="${SCRIPT_DIR}/venv/bin/python3" +FETCH_SCRIPT="${SCRIPT_DIR}/fetch_data.py" +LOG_DIR="${SCRIPT_DIR}/deploy" +LOG_FILE="${LOG_DIR}/fetch_$(date +%Y%m%d).log" + +mkdir -p "${LOG_DIR}" + +echo "=== $(date '+%Y-%m-%d %H:%M:%S') 开始执行双色球数据抓取 ===" +"${VENV_PYTHON}" "${FETCH_SCRIPT}" >> "${LOG_FILE}" 2>&1 +RC=$? +echo "=== $(date '+%Y-%m-%d %H:%M:%S') 执行完成, exit code=${RC} ===" +exit ${RC} \ No newline at end of file diff --git a/deploy/lotto-web.service b/deploy/lotto-web.service new file mode 100644 index 0000000..bff66d0 --- /dev/null +++ b/deploy/lotto-web.service @@ -0,0 +1,16 @@ +[Unit] +Description=双色球数据抓取 Web 服务 +After=network.target + +[Service] +Type=simple +User=vincent +WorkingDirectory=/home/vincent/Studio/lottoData +ExecStart=/home/vincent/Studio/lottoData/venv/bin/python3 /home/vincent/Studio/lottoData/web_executor.py +ExecStartPre=/home/vincent/Studio/lottoData/venv/bin/python3 -c "import flask; import pandas; import openpyxl; import requests; import bs4" +Restart=on-failure +RestartSec=5 +KillMode=control-group + +[Install] +WantedBy=multi-user.target \ No newline at end of file diff --git a/docs/PRD-20260619-双色球数据抓取系统.md b/docs/PRD-20260619-双色球数据抓取系统.md new file mode 100644 index 0000000..1501e6a --- /dev/null +++ b/docs/PRD-20260619-双色球数据抓取系统.md @@ -0,0 +1,396 @@ +# 产品需求文档(PRD):双色球数据抓取系统 + +## 版本历史 +| 版本 | 日期 | 变更内容 | 作者 | +|------|------|----------|------| +| v1.0 | 2026-06-19 | 初始版本 | 沈路明 | + +--- + +## 1. 背景与目标 + +### 1.1 业务背景 +- 双色球作为中国最受欢迎的彩票类型,用户需要及时了解历史开奖数据进行分析和参考 +- 目前数据依赖人工查看,效率低且无法进行数据分析 +- 需要建立自动化数据抓取和展示系统,支持日常数据分析和研究 + +### 1.2 解决的问题 +1. **数据获取效率低**:人工访问网站查看开奖结果耗时且容易遗漏 +2. **数据难以分析**:网页数据无法直接用于 Excel 或其他分析工具 +3. **无法实时监控**:无法及时获取最新开奖数据 +4. **访问不便**:需要在局域网内便捷访问数据和管理工具 + +### 1.3 成功指标(可量化) +- **数据准确性**:抓取数据与官方网站一致率 100% +- **更新及时性**:开奖后 30 分钟内完成数据更新 +- **系统可用性**:Web 服务月可用性 ≥ 99% +- **用户体验**:页面加载时间 < 2 秒(局域网环境) + +--- + +## 2. 用户故事 + +| 角色 | 用户故事 | 价值 | +|------|----------|------| +| 数据分析员 | 作为数据分析员,我希望每天自动获取最新的双色球开奖数据,以便进行趋势分析 | 节省手动收集数据的时间,确保数据完整性 | +| 普通用户 | 作为普通用户,我希望通过网页界面手动触发数据抓取并实时查看结果,以便确认系统正常运行 | 透明化系统运行状态,增强信任感 | +| 系统管理员 | 作为系统管理员,我希望配置定时任务和时间,以便控制数据抓取的频率 | 灵活管理系统负载,避免频繁请求 | +| 局域网用户 | 作为局域网用户,我希望能在家中任何设备上访问 Web 界面,以便随时随地查看数据 | 提升访问便利性,支持多设备使用 | + +--- + +## 3. 功能需求 + +### 3.1 数据抓取模块 + +| 功能点 | 描述 | 优先级 | 验收标准 | +|--------|------|--------|----------| +| 数据源接入 | 从 https://www.55128.cn/kjh/fcssq-history-120.htm 抓取近 120 期双色球开奖数据 | P0 | 能正确解析 HTML 并提取所有开奖数据,无遗漏 | +| 增量更新 | 对比本地 Excel 文件,仅添加缺失的期数数据 | P0 | 不产生重复数据,新增数据准确率 100% | +| 数据校验 | 抓取后进行数据完整性校验(期数连续性、号码格式等) | P1 | 发现异常数据时记录错误日志并告警 | +| 错误重试 | 网络异常时自动重试(最多 3 次,间隔 5 秒) | P1 | 临时网络故障下成功抓取率 ≥ 95% | + +### 3.2 数据存储模块 + +| 功能点 | 描述 | 优先级 | 验收标准 | +|--------|------|--------|----------| +| Excel 存储 | 数据以 Excel 格式存储,文件名为「双色球历史数据.xlsx」 | P0 | 文件格式正确,可用 Excel 正常打开 | +| 字段定义 | 包含以下字段(见 4.1) | P0 | 所有字段完整,格式正确 | +| 数据导出 | 支持导出为 CSV 格式(可选) | P2 | 导出数据与 Excel 一致,编码为 UTF-8 | + +### 3.3 Web 界面模块 + +| 功能点 | 描述 | 优先级 | 验收标准 | +|--------|------|--------|----------| +| 手动触发抓取 | 提供"立即抓取"按钮,点击后执行抓取脚本 | P0 | 按钮点击后 3 秒内响应,显示执行状态 | +| 实时日志展示 | 显示抓取过程的实时日志(包括开始时间、抓取期数、完成时间等) | P0 | 日志自动滚动,支持暂停查看,颜色区分正常/警告/错误 | +| 数据概览 | 展示最新一期开奖号码(红球 6 个 + 蓝球 1 个) | P0 | 号码以球状展示,颜色正确(红球红色,蓝球蓝色) | +| 历史数据表 | 展示 Excel 中的数据,支持分页和搜索 | P1 | 支持按期数搜索,分页加载(每页 20 条) | +| 抓取状态监控 | 显示最近一次抓取时间、下次计划抓取时间、抓取状态(成功/失败) | P1 | 状态更新时间 < 5 秒延迟 | +| 定时任务配置 | 提供界面配置定时任务的执行时间 | P0 | 配置后立即生效,无需重启服务 | +| 响应式布局 | 支持桌面端和移动端访问 | P1 | 在主流手机浏览器上正常显示和操作 | + +### 3.4 定时任务模块 + +| 功能点 | 描述 | 优先级 | 验收标准 | +|--------|------|--------|----------| +| Cron 定时任务 | 使用 Linux cron 实现每天自动抓取 | P0 | 任务配置正确,日志中可查到执行记录 | +| 执行时间配置 | 默认为每天 21:30(开奖后 15 分钟) | P0 | 可通过 Web 界面修改执行时间 | +| 任务开关 | 提供启用/禁用定时任务的开关 | P1 | 开关状态立即生效,界面显示当前状态 | + +--- + +## 4. 非功能需求 + +### 4.1 数据字段定义 + +**Excel 文件字段:** + +| 字段名 | 类型 | 说明 | 示例 | +|--------|------|------|------| +| 开奖日期 | Date | 开奖日期 | 2026-06-18 | +| 期数 | String | 双色球期号 | 2026069 | +| 红球 1 | Integer | 第 1 个红球号码(1-33) | 12 | +| 红球 2 | Integer | 第 2 个红球号码(1-33) | 14 | +| 红球 3 | Integer | 第 3 个红球号码(1-33) | 16 | +| 红球 4 | Integer | 第 4 个红球号码(1-33) | 17 | +| 红球 5 | Integer | 第 5 个红球号码(1-33) | 18 | +| 红球 6 | Integer | 第 6 个红球号码(1-33) | 32 | +| 蓝球 | Integer | 蓝球号码(1-16) | 08 | +| 和值 | Integer | 6 个红球号码之和 | 109 | +| 奇偶比 | String | 红球奇偶比例 | 1:5 | +| 大小比 | String | 红球大小比例(1-16 为小,17-33 为大) | 3:3 | +| 开机号 | String | 开机号(如有) | 07,13,19,24,27,31+05 | +| 跨度 | Integer | 红球最大值 - 最小值 | 20 | + +### 4.2 性能要求 + +| 指标 | 要求 | 说明 | +|------|------|------| +| 抓取耗时 | < 30 秒 | 完成 120 期数据抓取和更新的总耗时 | +| 页面加载 | < 2 秒 | Web 界面在局域网环境下的加载时间 | +| 并发支持 | ≥ 5 个并发用户 | 支持至少 5 个用户同时访问 Web 界面 | +| 内存占用 | < 200MB | Python 进程常驻内存占用 | + +### 4.3 兼容性要求 + +| 维度 | 要求 | +|------|------| +| 操作系统 | Ubuntu 20.04+ / macOS 12+ | +| Python 版本 | Python 3.8+ | +| 浏览器 | Chrome 90+、Firefox 88+、Safari 14+、Edge 90+ | +| 移动端 | iOS Safari 14+、Android Chrome 90+ | + +### 4.4 安全要求 + +**局域网访问安全:** + +| 安全项 | 方案 | 说明 | +|--------|------|------| +| 访问控制 | 仅监听 0.0.0.0,通过防火墙限制访问来源 | 只允许内网 IP 段访问(如 192.168.0.0/16) | +| 身份验证 | 可选配置基本 HTTP 认证(用户名 + 密码) | 防止未授权访问,密码通过配置文件管理 | +| 日志记录 | 所有访问和操作记录日志 | 包含时间、IP、操作类型、结果 | +| 命令注入防护 | Web 界面不接受任何命令行输入 | 防止用户通过界面执行任意命令 | + +### 4.5 可靠性要求 + +| 指标 | 要求 | 说明 | +|------|------|------| +| 服务可用性 | ≥ 99% | 月累计不可用时间 < 7.2 小时 | +| 数据持久化 | 100% | 已抓取数据不丢失,异常情况自动备份 | +| 断电恢复 | 自动恢复服务 | 系统重启后服务自动拉起(通过 systemd) | + +--- + +## 5. 系统架构设计 + +### 5.1 技术选型 + +| 模块 | 技术栈 | 选型理由 | +|------|--------|----------| +| 数据抓取 | Python + requests + BeautifulSoup4 | 成熟的网页抓取方案,社区支持好 | +| 数据存储 | openpyxl | 原生支持 Excel 读写,无需安装 Office | +| Web 服务 | Flask | 轻量级,易部署,适合内部工具 | +| 定时任务 | Linux Cron | 系统原生支持,稳定可靠 | +| 前端 | HTML + CSS + JavaScript (jQuery) | 简单直接,无需构建流程 | +| 日志 | Python logging | 标准库支持,灵活配置 | + +### 5.2 目录结构 + +``` +/home/vincent/Studio/lottoData/ +├── lottery.py # 号码生成器(现有) +├── 双色球历史数据.xlsx # 数据存储(现有) +├── scraper.py # 数据抓取脚本(新建) +├── app.py # Flask Web 应用(新建) +├── config.py # 配置文件(新建) +├── templates/ # HTML 模板(新建) +│ └── index.html +├── static/ # 静态资源(新建) +│ ├── css/ +│ └── js/ +├── logs/ # 日志目录(新建) +│ └── lottery.log +└── requirements.txt # Python 依赖(新建) +``` + +### 5.3 定时任务配置 + +**Cron 配置示例:** +```bash +# 每天 21:30 执行数据抓取 +30 21 * * * cd /home/vincent/Studio/lottoData && /usr/bin/python3 scraper.py >> logs/cron.log 2>&1 +``` + +**Systemd 服务配置(Web 服务):** +```ini +# /etc/systemd/system/lottery-web.service +[Unit] +Description=Lottery Data Web Service +After=network.target + +[Service] +Type=simple +User=vincent +WorkingDirectory=/home/vincent/Studio/lottoData +ExecStart=/usr/bin/python3 app.py +Restart=always + +[Install] +WantedBy=multi-user.target +``` + +### 5.4 页面流程图 + +``` +用户访问 Web 界面 + ↓ +加载首页(显示最新开奖数据 + 历史数据) + ↓ +┌──────────────┬──────────────┬──────────────┐ +│ │ │ │ +▼ ▼ ▼ ▼ +手动触发抓取 查看历史数据 配置定时任务 监控抓取状态 + ↓ ↓ ↓ ↓ +显示执行日志 分页/搜索查看 修改执行时间 查看上次抓取结果 + ↓ ↓ ↓ ↓ +更新数据表 导出数据 保存配置 显示下次执行时间 +``` + +--- + +## 6. 接口设计 + +### 6.1 Web 接口 + +| 接口路径 | 方法 | 描述 | 请求参数 | 返回格式 | +|----------|------|------|----------|----------| +| `/` | GET | 首页 - 数据展示 | 无 | HTML | +| `/api/scrape` | POST | 手动触发抓取 | 无 | JSON `{"status": "success", "message": "..."}` | +| `/api/status` | GET | 获取系统状态 | 无 | JSON `{last_scrape_time, next_scheduled_time, status}` | +| `/api/history` | GET | 获取历史数据 | `page`, `limit`, `search` | JSON `{"data": [...], "total": N}` | +| `/api/config` | GET | 获取定时任务配置 | 无 | JSON | +| `/api/config` | POST | 更新定时任务配置 | `enabled`, `cron_expr` | JSON `{"status": "success"}` | + +### 6.2 日志格式 + +``` +[2026-06-19 21:30:01 INFO] 开始抓取数据... +[2026-06-19 21:30:02 INFO] 成功访问数据源页面 +[2026-06-19 21:30:05 INFO] 解析到 120 条数据 +[2026-06-19 21:30:06 INFO] 本地现有数据:118 条 +[2026-06-19 21:30:06 INFO] 新增数据:2 条 (2026069, 2026068) +[2026-06-19 21:30:07 INFO] 数据保存到 Excel 成功 +[2026-06-19 21:30:07 INFO] 抓取完成,耗时 6.2 秒 +``` + +--- + +## 7. 排期建议 + +### 7.1 开发阶段划分 + +| 阶段 | 任务 | 预计耗时 | 依赖 | +|------|------|----------|------| +| 阶段 1 | 数据抓取脚本开发(scraper.py) | 2 小时 | 无 | +| 阶段 2 | Web 服务开发(app.py + templates) | 3 小时 | 阶段 1 完成 | +| 阶段 3 | 定时任务配置和系统部署 | 1 小时 | 阶段 2 完成 | +| 阶段 4 | 测试和优化 | 2 小时 | 阶段 3 完成 | + +**总预计耗时:8 小时** + +### 7.2 关键依赖 + +1. **服务器访问权限**:需要能访问目标网站(55128.cn) +2. **Python 环境**:需要安装 Python 3.8+ 和依赖包 +3. **局域网网络**:确保局域网内设备可以访问服务端口 + +--- + +## 8. 风险与应对 + +### 8.1 需求风险 + +| 风险 | 影响 | 概率 | 应对方案 | +|------|------|------|----------| +| 数据源网站结构变化 | 抓取脚本失效 | 中 | 1. 添加结构变更检测
2. 建立告警机制
3. 定期维护更新 | +| 数据源网站反爬策略 | 被封 IP | 低 | 1. 控制请求频率
2. 添加 User-Agent
3. 必要时使用代理 | + +### 8.2 技术风险 + +| 风险 | 影响 | 概率 | 应对方案 | +|------|------|------|----------| +| Excel 文件被占用 | 写入失败 | 低 | 1. 写入前检查文件锁
2. 使用临时文件 + 原子替换
3. 失败后重试 | +| 网络不稳定 | 抓取失败 | 中 | 1. 实现重试机制
2. 记录失败原因
3. 邮件/消息告警 | +| 端口冲突 | Web 服务启动失败 | 低 | 1. 启动前检查端口占用
2. 支持配置端口
3. 日志明确提示 | + +### 8.3 安全风险 + +| 风险 | 影响 | 概率 | 应对方案 | +|------|------|------|----------| +| 未授权访问 | 数据泄露 | 中 | 1. 防火墙限制 IP 范围
2. 可选 HTTP 认证
3. 访问日志审计 | +| 恶意请求 | 服务崩溃 | 低 | 1. 请求频率限制
2. 异常输入过滤
3. 服务监控 | + +--- + +## 9. 验收标准 + +### 9.1 功能验收 + +- [ ] **数据抓取**:能从 55128.cn 成功抓取近 120 期数据 +- [ ] **增量更新**:不产生重复数据,仅添加缺失期数 +- [ ] **Web 界面**:能手动触发抓取并实时查看日志 +- [ ] **数据展示**:首页展示最新开奖号码和历史数据表 +- [ ] **定时任务**:配置 cron 后每天自动执行 +- [ ] **局域网访问**:其他设备能访问 Web 服务 + +### 9.2 质量验收 + +- [ ] **数据准确性**:与官方网站数据 100% 一致 +- [ ] **性能达标**:页面加载时间 < 2 秒(局域网) +- [ ] **日志完整**:所有关键操作都有日志记录 +- [ ] **错误处理**:异常情况有明确提示和日志 + +### 9.3 文档验收 + +- [ ] **README 文档**:包含安装、配置、使用说明 +- [ ] **依赖清单**:requirements.txt 完整列出 Python 依赖 +- [ ] **部署文档**:Systemd 服务配置说明 + +--- + +## 10. 后续优化建议 + +### 10.1 短期优化(1 个月内) + +1. **数据可视化**:增加号码分布图、冷热号统计等图表 +2. **告警通知**:抓取失败时通过邮件/微信通知 +3. **数据备份**:每天自动备份 Excel 文件到云存储 + +### 10.2 中期优化(3 个月内) + +1. **数据库升级**:使用 SQLite/MySQL 替代 Excel,支持更复杂查询 +2. **API 开放**:提供 REST API 供其他系统调用 +3. **多彩种支持**:扩展支持大乐透、福彩 3D 等其他彩票 + +### 10.3 长期优化(6 个月内) + +1. **数据分析平台**:集成数据分析工具,提供智能预测 +2. **移动端 App**:开发 iOS/Android 应用 +3. **多用户系统**:支持多个用户独立配置和使用 + +--- + +## 附录 + +### A. 依赖包清单 + +```txt +# requirements.txt +requests==2.31.0 +beautifulsoup4==4.12.2 +openpyxl==3.1.2 +flask==3.0.0 +lxml==4.9.3 +``` + +### B. 配置文件示例 + +```python +# config.py +import os + +# 系统配置 +BASE_DIR = os.path.dirname(os.path.abspath(__file__)) +DATA_FILE = os.path.join(BASE_DIR, '双色球历史数据.xlsx') +LOG_FILE = os.path.join(BASE_DIR, 'logs', 'lottery.log') + +# 数据源 +DATA_SOURCE_URL = 'https://www.55128.cn/kjh/fcssq-history-120.htm' + +# Web 服务配置 +WEB_HOST = '0.0.0.0' +WEB_PORT = 5000 +DEBUG = False + +# 定时任务配置 +CRON_ENABLED = True +CRON_EXPR = '30 21 * * *' # 每天 21:30 + +# 安全配置(可选) +AUTH_ENABLED = False +AUTH_USERNAME = 'admin' +AUTH_PASSWORD = 'your_password_here' # 建议通过环境变量设置 +``` + +### C. 数据来源说明 + +- **数据源**:彩吧助手 (www.55128.cn) +- **数据更新时间**:每周二、四、日 21:15 开奖 +- **建议抓取时间**:开奖后 15 分钟(21:30) + +--- + +**PRD 评审人:** 承哥 +**PRD 创建日期:** 2026-06-19 +**下次评审日期:** 开发完成后验收评审 \ No newline at end of file diff --git a/docs/PRD-双色球 WebUI-v1.0.md b/docs/PRD-双色球 WebUI-v1.0.md new file mode 100644 index 0000000..d832091 --- /dev/null +++ b/docs/PRD-双色球 WebUI-v1.0.md @@ -0,0 +1,361 @@ +# 产品需求文档(PRD):双色球自动化系统 Web UI + +**文档版本**: v1.0 +**创建日期**: 2026-07-03 +**产品经理**: 沈路明 +**状态**: 待评审 + +--- + +## 1. 背景与目标 + +### 1.1 业务背景 +双色球自动化项目已完成核心功能开发(数据爬取、号码生成、统计分析),但缺乏统一的 Web 界面供用户(刘总及团队成员)便捷访问和使用。现有功能分散在多个 Python 脚本中,需要在网页端整合为一体化服务。 + +### 1.2 解决的问题 +- **访问门槛高**: 用户需要运行 Python 脚本才能生成号码,操作复杂 +- **数据不可视**: 历史数据、生成记录、统计信息无法直观查看 +- **无法局域网共享**: 缺少监听 0.0.0.0 的 Web 服务,无法在 PC/手机端跨设备访问 +- **功能分散**: 数据抓取、号码生成、历史记录查看分散在不同入口 + +### 1.3 成功指标(定量) +| 指标 | 目标值 | 衡量方式 | +|------|--------|----------| +| 功能覆盖率 | 100% 核心功能 | PRD 功能清单验收 | +| 响应式支持 | PC + 移动端 | 主流设备测试通过 | +| 局域网可访问 | 0.0.0.0:8085 | 网络扫描验证 | +| API 响应时间 | <2s (P95) | 压力测试 | +| 用户满意度 | 刘总验收通过 | 评审会议确认 | + +--- + +## 2. 用户故事 + +| ID | 用户角色 | 故事 | 价值 | +|----|----------|------|------| +| US-01 | 刘总(主要用户) | 作为用户,我希望在手机上打开网页就能生成双色球号码,以便随时查看推荐号码 | 便捷性、即时访问 | +| US-02 | 刘总 | 作为用户,我希望查看历史开奖数据,以便分析号码趋势 | 数据驱动决策 | +| US-03 | 刘总 | 作为用户,我希望查看历史生成记录并下载 Excel,以便存档和分享 | 数据持久化 | +| US-04 | 团队成员 | 作为团队成员,我希望在 PC 端大屏查看统计数据,以便进行项目汇报 | 可视化展示 | +| US-05 | 团队成员 | 作为运维人员,我希望服务监听局域网,以便多人同时访问 | 资源共享 | + +--- + +## 3. 功能需求 + +### 3.1 功能清单与优先级 + +| 功能模块 | 功能点 | 描述 | 优先级 | 验收标准 | +|----------|--------|------|--------|----------| +| **号码生成** | GEN-01 | 选择生成注数(1-1000) | P0 | 滑块/输入框可调,范围校验正确 | +| | GEN-02 | 选择策略(基础/高级) | P0 | 下拉选择,高级策略调用热冷号分析 | +| | GEN-03 | 执行生成并展示结果 | P0 | 点击生成后 3s 内返回结果,展示红球 + 蓝球 | +| | GEN-04 | 结果页展示和值、奇偶比、大小比、跨度 | P0 | 每个号码下方显示统计指标 | +| | GEN-05 | 下载 Excel 文件 | P0 | 点击下载可获取完整 Excel | +| | GEN-06 | 生成记录自动保存 | P0 | 每次生成后记录存入 `.generation_records.json` | +| **历史数据** | HIS-01 | 查看历史开奖数据列表 | P0 | 分页展示,每页 20 条,支持翻页 | +| | HIS-02 | 搜索历史数据(按期号/日期) | P1 | 搜索框输入后 500ms 防抖查询 | +| | HIS-03 | 红球/蓝球高亮显示 | P0 | 红球红色背景,蓝球蓝色背景 | +| | HIS-04 | 展示和值、奇偶比、大小比、跨度 | P1 | 列表中包含这些统计字段 | +| **生成记录** | REC-01 | 查看历史生成记录列表 | P0 | 分页展示,显示策略、注数、时间、文件大小 | +| | REC-02 | 下载生成结果文件 | P0 | 点击下载可获取对应 Excel | +| | REC-03 | 删除生成记录 | P1 | 删除后同时删除对应文件,列表刷新 | +| **统计数据** | STA-01 | 展示历史开奖期数 | P0 | 数字准确 | +| | STA-02 | 红球热号 TOP15 | P0 | 按出现频次降序排列 | +| | STA-03 | 红球冷号 TOP15 | P0 | 按出现频次升序排列 | +| | STA-04 | 蓝球热号 TOP8 | P0 | 按出现频次降序排列 | +| | STA-05 | 最常见奇偶比 | P1 | 显示频次最高的奇偶比形态 | +| | STA-06 | 最常见大小比 | P1 | 显示频次最高的 大小比形态 | +| | STA-07 | 和值范围统计 | P1 | 显示最小值、最大值、平均值、标准差 | +| | STA-08 | 跨度范围统计 | P1 | 显示最小值、最大值、平均值、标准差 | +| **系统功能** | SYS-01 | 监听 0.0.0.0:8085 | P0 | `netstat -tlnp` 验证 | +| | SYS-02 | PC/移动端响应式布局 | P0 | 视口宽度 320px-1920px 自适应 | +| | SYS-03 | 页面导航(4 个 Tab) | P0 | 生成、历史数据、生成记录、统计 | +| | SYS-04 | API Token 认证(可选) | P2 | 配置项 `auth_enabled` 控制开关 | +| | SYS-05 | 系统状态接口 | P1 | `/api/status` 返回服务状态 | + +### 3.2 核心业务流程 + +``` +用户访问 → 首页(号码生成) → 选择注数/策略 → 点击生成 + ↓ +后端调用 lottery.py → 分析历史数据 → 生成号码 → 保存 Excel + ↓ +返回结果 → 前端展示(红球 + 蓝球 + 统计指标) → 可下载/查看记录 +``` + +--- + +## 4. 非功能需求 + +### 4.1 性能要求 +| 指标 | 要求 | 说明 | +|------|------|------| +| 页面加载时间 | <3s (P95) | 首次加载,含静态资源 | +| API 响应时间 | <2s (P95) | 不含号码生成(含历史数据查询、统计) | +| 号码生成时间 | <10s (P95) | 100 注以内,高级策略 | +| 并发用户数 | ≥10 | 局域网内同时访问 | + +### 4.2 兼容性要求 +| 平台 | 浏览器 | 版本要求 | +|------|--------|----------| +| PC 端 | Chrome | 90+ | +| PC 端 | Safari | 14+ | +| PC 端 | Edge | 90+ | +| 移动端 | iOS Safari | 14+ | +| 移动端 | Android Chrome | 90+ | +| 移动端 | 微信内置浏览器 | 最新版 | + +### 4.3 安全要求 +- **API 认证**: 可选 Token 认证(`auth_enabled` 配置项) +- **目录遍历防护**: 下载接口校验路径,禁止 `..` 和绝对路径 +- **HTTPS**: 内网环境暂不强制,外网部署需配置 SSL + +### 4.4 可用性要求 +- **服务可用性**: ≥99%(工作时段 9:00-22:00) +- **数据持久化**: 生成记录永久保存,除非用户主动删除 +- **错误处理**: 所有 API 失败返回友好提示,不暴露堆栈信息 + +--- + +## 5. 原型与界面 + +### 5.1 页面结构 +``` +┌─────────────────────────────────────────┐ +│ Header(标题 + 副标题) │ +├─────────────────────────────────────────┤ +│ Nav Tabs: 生成 | 历史数据 | 记录 | 统计 │ +├─────────────────────────────────────────┤ +│ │ +│ Page Content │ +│ (根据 Tab 切换内容) │ +│ │ +└─────────────────────────────────────────┘ +``` + +### 5.2 关键界面描述 + +#### 5.2.1 号码生成页(首页) +- **顶部**: 统计概览(历史期数、常见奇偶比、常见大小比、和值范围、跨度范围、热号预览) +- **中部**: 生成参数配置(滑块选择注数 1-1000,下拉选择策略) +- **操作区**: 「立即生成」大按钮 +- **结果区**: 号码卡片列表(每注显示红球 6 个 + 蓝球 1 个,下方显示和值、奇偶比、大小比、跨度) +- **底部**: 「下载 Excel」按钮 + +#### 5.2.2 历史数据页 +- **顶部**: 搜索框(按期号/日期搜索,500ms 防抖) +- **列表**: 表格展示(期号、开奖日期、红球 6 个、蓝球 1 个、和值、奇偶形态、大小比、跨度) +- **底部**: 分页控件(上一页/页码/下一页) + +#### 5.2.3 生成记录页 +- **列表**: 卡片式展示(策略、注数、生成时间、文件大小) +- **操作**: 每条记录含「下载」和「删除」按钮 +- **底部**: 分页控件 + +#### 5.2.4 统计页 +- **数据卡片**: 历史开奖期数 +- **热号区**: 红球热号 TOP15(红色球)、蓝球热号 TOP8(蓝色球) +- **冷号区**: 红球冷号 TOP15(红色球,透明度降低) +- **统计网格**: 最常见奇偶比、最常见大小比、和值范围(min-max-mean-std)、跨度范围(min-max-mean-std) + +### 5.3 设计规范 +| 元素 | 规范 | +|------|------| +| 主色调 | 红色 #e74c3c(双色球主题) | +| 辅色 | 蓝色 #3498db(蓝球)、紫色 #8e44ad(渐变) | +| 字体 | 系统默认(-apple-system, PingFang SC, Microsoft YaHei) | +| 卡片圆角 | 12px | +| 阴影 | 0 2px 12px rgba(0,0,0,0.08) | +| 移动导航 | 底部固定(高度 56px) | +| PC 导航 | 顶部 Tab(高度 68px,sticky) | + +--- + +## 6. API 接口设计 + +### 6.1 接口清单 + +| 接口 | 方法 | 描述 | 认证 | +|------|------|------|------| +| `/api/generate` | POST | 生成号码 | 可选 | +| `/api/history` | GET | 获取历史开奖数据 | 可选 | +| `/api/records` | GET | 获取生成记录列表 | 可选 | +| `/api/records/:id` | DELETE | 删除生成记录 | 可选 | +| `/api/statistics` | GET | 获取统计数据 | 可选 | +| `/api/download/:filepath` | GET | 下载文件 | 可选 | +| `/api/status` | GET | 系统状态 | 无 | +| `/api/config` | GET | 前端配置 | 无 | + +### 6.2 关键接口示例 + +#### POST /api/generate +**请求**: +```json +{ + "num_tickets": 10, + "strategy": "advanced" +} +``` + +**响应**: +```json +{ + "success": true, + "data": { + "tickets": [ + { + "index": 1, + "reds": [3, 12, 18, 23, 27, 31], + "blue": 9, + "sum_value": 114, + "odd_even": "3:3", + "size_ratio": "4:2", + "span": 28 + } + ], + "total": 10, + "filename": "lottery/双色球_20260703_142530_高级策略_10 注.xlsx", + "download_url": "/api/download/lottery/双色球_20260703_142530_高级策略_10 注.xlsx", + "record": {...}, + "statistics": {...} + } +} +``` + +--- + +## 7. 技术架构 + +### 7.1 技术栈 +| 层级 | 技术 | 版本 | +|------|------|------| +| 后端 | Python + Flask | 3.x + 2.x | +| 前端 | 原生 HTML/CSS/JS | ES6+ | +| 数据存储 | Excel + JSON | openpyxl | +| 号码生成 | NumPy + Pandas | 1.x | +| 部署 | 直接运行 | `python3 app.py` | + +### 7.2 目录结构 +``` +lottoData/ +├── app.py # Flask 主服务(17KB) +├── index.html # 前端 UI(42KB,响应式) +├── lottery.py # 号码生成核心逻辑(51KB) +├── fetch_data.py # 数据爬取脚本 +├── web_executor.py # 数据抓取 Web 服务(独立) +├── web_console.html # 数据抓取控制台 +├── 双色球历史数据.xlsx # 历史数据(由 fetch_data.py 更新) +├── lottery/ # 号码生成结果目录 +├── .generation_records.json # 生成记录索引 +└── .fetch_status.json # 抓取状态(web_executor 用) +``` + +### 7.3 部署方式 +```bash +# 进入项目目录 +cd /home/vincent/Studio/lottoData + +# 启动服务 +python3 app.py + +# 访问地址 +本地:http://localhost:8085 +局域网:http://<本机 IP>:8085 +``` + +### 7.4 端口与监听 +- **默认端口**: 8085 +- **监听地址**: 0.0.0.0(局域网可访问) +- **可配置**: `CONFIG['port']` 和 `CONFIG['host']` + +--- + +## 8. 数据埋点与监控 + +### 8.1 关键事件埋点建议 +| 事件 | 触发时机 | 数据字段 | +|------|----------|----------| +| `page_view` | 页面加载 | page_name, user_agent, timestamp | +| `generate_click` | 点击生成按钮 | num_tickets, strategy | +| `generate_success` | 生成成功 | num_tickets, strategy, duration_ms | +| `generate_failure` | 生成失败 | error_message, strategy | +| `download_click` | 点击下载 | file_name, source (生成结果/记录列表) | +| `record_delete` | 删除记录 | record_id | + +### 8.2 监控指标 +- **服务可用性**: 心跳检测(/api/status) +- **API 错误率**: 按接口统计 5xx 错误占比 +- **生成成功率**: 成功次数 / 总请求次数 +- **平均响应时间**: 各接口 P95延迟 + +--- + +## 9. 排期建议 + +| 阶段 | 工作内容 | 负责人 | 预估工时 | +|------|----------|--------|----------| +| 评审 | PRD 评审 + 架构评审 | 全员 | 2h | +| 开发 | 已有代码,无需开发 | - | 0h | +| 测试 | 功能测试 + 兼容性测试 | 测试 | 4h | +| 部署 | 服务启动 + 防火墙配置 | 运维 | 1h | +| 验收 | 刘总验收 | 刘总 | 待定 | + +**总工时**: 7 小时(主要为测试和验收) + +--- + +## 10. 风险与应对 + +| 风险 | 影响 | 概率 | 应对措施 | +|------|------|------|----------| +| 历史数据文件损坏 | 无法生成号码 | 低 | 定期备份 `.xlsx` 文件 | +| 局域网网络问题 | 无法访问 | 中 | 检查防火墙,确保 8085 端口开放 | +| 并发过高导致服务卡顿 | 体验下降 | 低 | 限制单 IP 请求频率,增加超时控制 | +| Excel 文件过大 | 下载缓慢 | 中 | 单个文件限制 1000 注,超过分批下载 | +| 移动端适配问题 | 显示错乱 | 低 | 真机测试主流设备 | + +--- + +## 11. 版本历史 + +| 版本 | 日期 | 修改内容 | 修改人 | +|------|------|----------|--------| +| v1.0 | 2026-07-03 | 初始版本,基于现有代码逆向整理 PRD | 沈路明 | + +--- + +## 12. 附件 + +### 12.1 已有代码文件清单 +1. `app.py` (17KB) - Flask 后端服务 +2. `index.html` (42KB) - 响应式前端 UI +3. `lottery.py` (51KB) - 号码生成核心逻辑 +4. `fetch_data.py` (3.8KB) - 历史数据抓取 +5. `web_executor.py` (6.4KB) - 数据抓取 Web 服务 +6. `web_console.html` (11KB) - 数据抓取控制台 +7. `双色球历史数据.xlsx` (12KB) - 历史数据文件 + +### 12.2 Git 仓库 +- **仓库地址**: http://192.168.1.99:12299/vincent/Lottery.git +- **当前状态**: 代码已完成,待提交至 Git + +### 12.3 访问地址 +- **本地访问**: http://localhost:8085 +- **局域网访问**: http://192.168.1.99:8085(示例 IP,以实际为准) + +--- + +## 13. 后续优化建议(非本期) + +| 功能 | 描述 | 优先级 | +|------|------|--------| +| 用户登录系统 | 多用户权限管理 | P2 | +| 定时任务调度 | 自动生成 + 推送 | P2 | +| 数据可视化图表 | 走势图、分布图 | P2 | +| 微信推送 | 生成结果推送至微信 | P3 | +| 多彩种支持 | 大乐透、福彩 3D 等 | P3 | + +--- + +**PRD 评审准备就绪,邀请架构师(梁思筑)和开发(徐聪)参与评审。** \ No newline at end of file diff --git a/docs/PRD-操作界面系统.md b/docs/PRD-操作界面系统.md new file mode 100644 index 0000000..8a35e0d --- /dev/null +++ b/docs/PRD-操作界面系统.md @@ -0,0 +1,512 @@ +# 产品需求文档(PRD):双色球操作界面系统 + +## 1. 背景与目标 + +### 业务背景 +基于已有的 lottery.py 号码生成逻辑,需要开发一个 Web 操作界面系统,让用户可以通过 PC 网页端和手机端方便地操控双色球号码生成、查看历史数据、管理生成记录。系统需支持远程访问,生成的数据可随时读取。 + +### 解决的问题 +1. 命令行操作门槛高,普通用户难以使用 +2. 无法随时随地访问和管理数据 +3. 缺少可视化的数据展示和管理界面 +4. 生成的 Excel 文件分散,难以统一管理 + +### 成功指标 +- [ ] PC 和手机端均可正常访问操作 +- [ ] 核心功能(生成号码、查看历史、下载数据)100% 可用 +- [ ] 内网环境下远程访问响应时间 < 2 秒 +- [ ] 数据导出成功率 100% + +--- + +## 2. 用户故事 + +| 角色 | 用户故事 | 价值 | +|------|----------|------| +| 普通用户 | 作为用户,我希望通过手机浏览器生成双色球号码,以便随时随地选号 | 移动便利性 | +| 数据管理员 | 作为管理员,我希望查看历史数据和生成记录,以便分析趋势 | 数据可追溯 | +| 分析师 | 作为分析师,我希望导出 Excel 数据进行深度分析,以便制定策略 | 数据可复用 | +| 运维人员 | 作为运维,我希望系统监听 0.0.0.0 并避免端口冲突,以便内网多设备访问 | 部署便利性 | + +--- + +## 3. 功能需求 + +### 3.1 核心功能模块 + +#### 模块一:号码生成 +| 功能点 | 描述 | 优先级 | 验收标准 | +|--------|------|--------|----------| +| 选择策略 | 用户可选择"高级策略"或"基础策略" | P0 | 默认选中高级策略,切换无延迟 | +| 输入注数 | 用户输入要生成的注数(1-1000) | P0 | 有输入验证,超出范围提示错误 | +| 立即生成 | 点击按钮后生成号码并在页面展示 | P0 | 生成时间 < 3 秒(100 注内) | +| 展示结果 | 以表格形式展示生成的号码,包含和值、奇偶比、大小比、跨度 | P0 | 红球以蓝色圆形展示,蓝球以红色圆形展示 | +| 保存 Excel | 将生成结果保存为 Excel 文件并提供下载 | P0 | 文件格式正确,包含"生成号码"和"统计信息"两个 sheet | + +#### 模块二:历史数据查看 +| 功能点 | 描述 | 优先级 | 验收标准 | +|--------|------|--------|----------| +| 热力图展示 | 展示红球热号/冷号、蓝球热号 | P0 | 用颜色深浅表示频率,支持排序切换 | +| 统计面板 | 显示最常见奇偶比、大小比、和值范围、跨度范围 | P1 | 数据与 lottery.py 计算结果一致 | +| 历史期数列表 | 展示双色球历史开奖数据列表 | P1 | 支持分页,每页 20 条,支持按期号搜索 | + +#### 模块三:生成记录管理 +| 功能点 | 描述 | 优先级 | 验收标准 | +|--------|------|--------|----------| +| 记录列表 | 展示所有历史生成记录(时间、策略、注数、文件) | P0 | 按时间倒序排列,支持分页 | +| 文件下载 | 提供历史生成文件的下载链接 | P0 | 点击即可下载,文件名包含日期和注数 | +| 记录删除 | 允许用户删除单条或多条生成记录 | P2 | 删除前有二次确认,删除后同步删除文件 | + +#### 模块四:数据导出 API +| 功能点 | 描述 | 优先级 | 验收标准 | +|--------|------|--------|----------| +| RESTful API | 提供 GET /api/latest 接口获取最新生成数据 | P1 | 返回 JSON 格式,包含所有字段 | +| API 认证 | 简单 Token 认证机制 | P1 | 请求需携带 Authorization header | +| CORS 支持 | 允许跨域访问 | P1 | 配置 Access-Control-Allow-Origin | + +### 3.2 界面设计要求 + +#### PC 网页端 +- 响应式布局,支持主流浏览器(Chrome、Firefox、Edge、Safari) +- 左侧导航栏:首页(生成)、历史数据、生成记录、系统设置 +- 主内容区自适应宽度 +- 生成号码页面:上方为策略选择和注数输入,中间为结果展示区,下方为操作按钮 + +#### 手机端 +- 采用移动优先设计,触摸操作友好 +- 底部导航栏:首页、数据、记录 +- 生成号码页面:顶部为策略选择(下拉框),中间为注数输入(数字键盘),下方为生成按钮 +- 结果展示支持横向滑动查看完整信息 +- 字体大小适配移动端,关键信息(号码)字号放大 + +### 3.3 非功能需求 + +#### 性能要求 +- 页面加载时间 < 2 秒(内网环境) +- 号码生成响应时间 < 3 秒(100 注内) +- 支持并发用户数:5 个同时操作 + +#### 兼容性要求 +- PC 端:Chrome 80+、Firefox 75+、Edge 80+、Safari 13+ +- 移动端:iOS Safari 13+、Android Chrome 80+ +- 屏幕适配:PC(1280x720 及以上)、手机(375x667 及以上) + +#### 安全要求 +- 内网访问限制:通过防火墙规则限制仅内网 IP 可访问 +- 简单认证:配置文件存储访问 Token,防止未授权访问 +- 文件访问控制:仅允许下载 lottery 目录下的文件,防止目录遍历攻击 + +#### 部署要求 +- 监听地址:0.0.0.0(支持内网任意设备访问) +- 端口:提前与运维确认未使用端口(建议 8080-8099 范围内) +- 服务器:192.168.1.99,路径 ~/Studio/lottoData/ +- 进程保活:使用 systemd 或 supervisor 确保服务异常后自动重启 + +--- + +## 4. 技术架构 + +### 4.1 技术栈选择 +| 层级 | 技术 | 理由 | +|------|------|------| +| 后端框架 | Flask | 轻量级,与现有 lottery.py 兼容性好 | +| 前端框架 | Vue.js 3 + Element Plus | 响应式支持好,组件丰富 | +| 移动端适配 | Vant UI | 移动端组件库,触摸友好 | +| 数据存储 | 本地文件系统 | 保持现有 Excel 存储方式,无需数据库 | +| API 文档 | Swagger/OpenAPI | 便于调试和集成 | + +### 4.2 系统架构图 + +``` +┌─────────────────────────────────────────────────────────┐ +│ 用户设备层 │ +│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ +│ │ PC 浏览器 │ │ 手机浏览器 │ │ API 客户端 │ │ +│ └──────┬──────┘ └──────┬──────┘ └──────┬──────┘ │ +│ │ │ │ │ +│ └──────────────────┼──────────────────┘ │ +│ │ HTTP/HTTPS │ +└───────────────────────────┼───────────────────────────────┘ + │ +┌───────────────────────────┼───────────────────────────────┐ +│ 应用服务层 (Flask) │ +│ ┌────────────────────────┴────────────────────────┐ │ +│ │ 路由控制器 │ │ +│ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │ +│ │ │ 号码生成 │ │ 历史数据 │ │ 记录管理 │ │ │ +│ │ └──────────┘ └──────────┘ └──────────┘ │ │ +│ └─────────────────────────────────────────────────┘ │ +│ │ │ +│ ┌────────────────────────┴────────────────────────┐ │ +│ │ 业务逻辑层 │ │ +│ │ (集成 lottery.py 核心逻辑) │ │ +│ └─────────────────────────────────────────────────┘ │ +│ │ │ +│ ┌────────────────────────┴────────────────────────┐ │ +│ │ 数据访问层 │ │ +│ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │ +│ │ │ Excel 读写│ │ 文件管理 │ │ 缓存管理 │ │ │ +│ │ └──────────┘ └──────────┘ └──────────┘ │ │ +│ └─────────────────────────────────────────────────┘ │ +└───────────────────────────────────────────────────────────┘ + │ +┌───────────────────────────┼───────────────────────────────┐ +│ 数据存储层 │ +│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ +│ │历史数据.xlsx │ │ lottery/ │ │ 配置文件 │ │ +│ │ │ │ 生成文件 │ │ config.yaml│ │ +│ └─────────────┘ └─────────────┘ └─────────────┘ │ +└───────────────────────────────────────────────────────────┘ +``` + +### 4.3 API 接口设计 + +#### 4.3.1 号码生成 +``` +POST /api/generate +Request: +{ + "num_tickets": 10, + "strategy": "advanced" // 或 "basic" +} +Response: +{ + "success": true, + "data": { + "tickets": [...], + "filename": "lottery/双色球模拟号码 -10 注 -20260619-001.xlsx", + "download_url": "/api/download/lottery/双色球模拟号码 -10 注 -20260619-001.xlsx" + } +} +``` + +#### 4.3.2 获取统计数据 +``` +GET /api/statistics +Response: +{ + "success": true, + "data": { + "hot_reds": [1, 7, 13, 19, 23, 27, 31, 5, 11, 17], + "cold_reds": [2, 8, 14, 20, 26, 32, 4, 10, 16, 22], + "hot_blues": [3, 7, 11, 15, 9], + "common_odd_even": "3:3", + "common_size_ratio": "3:3", + "sum_range": {"min": 73, "max": 148, "mean": 105.5}, + "span_range": {"min": 11, "max": 32, "mean": 23.8} + } +} +``` + +#### 4.3.3 获取生成记录 +``` +GET /api/records?page=1&page_size=20 +Response: +{ + "success": true, + "data": { + "records": [ + { + "id": "uuid", + "created_at": "2026-06-19T10:30:00Z", + "strategy": "advanced", + "num_tickets": 10, + "filename": "lottery/双色球模拟号码 -10 注 -20260619-001.xlsx", + "download_url": "/api/download/..." + } + ], + "total": 150, + "page": 1, + "page_size": 20 + } +} +``` + +#### 4.3.4 下载文件 +``` +GET /api/download/{filepath} +Headers: Authorization: Bearer {token} +Response: 文件流 (application/vnd.openxmlformats-officedocument.spreadsheetml.sheet) +``` + +#### 4.3.5 获取最新数据(API 客户端用) +``` +GET /api/latest +Headers: Authorization: Bearer {token} +Response: +{ + "success": true, + "data": { + "latest_record": {...}, + "statistics": {...} + } +} +``` + +--- + +## 5. 原型与界面设计 + +### 5.1 页面流程图 + +``` +首页 + ├── 选择策略(高级/基础) + ├── 输入注数 + ├── 点击"生成号码" + │ └── 加载动画(生成中...) + │ └── 展示结果表格 + │ ├── 查看前 10 注(默认) + │ ├── 展开查看全部 + │ ├── 下载 Excel + │ └── 继续生成 + │ +历史数据 + ├── 热力图(红球/蓝球) + ├── 统计面板 + └── 历史期数列表(分页) + │ +生成记录 + ├── 记录列表(时间倒序) + ├── 搜索(按期号/日期) + └── 单条操作:下载 | 删除 + │ +系统设置 + ├── 端口配置 + ├── Token 管理 + └── 文件存储路径 +``` + +### 5.2 关键界面描述 + +#### 界面 1:首页 - 号码生成(PC 端) +``` +┌────────────────────────────────────────────────────────┐ +│ Logo 双色球号码生成系统 [历史数据] [生成记录] │ +├────────────────────────────────────────────────────────┤ +│ │ +│ ┌──────────────────────────────────────────────────┐ │ +│ │ 生成策略:○ 高级策略 ○ 基础策略 │ │ +│ │ 生成注数:[____] 注 (1-1000) │ │ +│ │ │ │ +│ │ [ 立即生成 ] │ │ +│ └──────────────────────────────────────────────────┘ │ +│ │ +│ 生成结果 │ +│ ┌──────────────────────────────────────────────────┐ │ +│ │ 序号 │ 红球 1 │ 红球 2 │ ... │ 蓝球 │ 和值 │ 奇偶比│ │ +│ │ 001 │ 05 │ 12 │ ... │ 09 │ 87 │ 3:3 │ │ +│ │ 002 │ 08 │ 15 │ ... │ 14 │ 92 │ 4:2 │ │ +│ │ ... │ ... │ ... │ ... │ ... │ ... │ ... │ │ +│ └──────────────────────────────────────────────────┘ │ +│ │ +│ [下载 Excel] [继续生成] │ +│ │ +└────────────────────────────────────────────────────────┘ +``` + +#### 界面 2:首页 - 号码生成(手机端) +``` +┌─────────────────────────┐ +│ 双色球号码生成系统 │ +├─────────────────────────┤ +│ │ +│ 策略:[高级策略 ▼] │ +│ 注数:[____] │ +│ │ +│ [ 立即生成 ] │ +│ │ +│ ┌───────────────────┐ │ +│ │ 第 001 注 │ │ +│ │ 🔴 05 12 19 23 27 │ │ +│ │ 31 🔵 09 │ │ +│ │ 和值 87 奇偶 3:3 │ │ +│ └───────────────────┘ │ +│ │ +│ [下载] [继续] │ +│ │ +├─────────────────────────┤ +│ 首页 │ 数据 │ 记录 │ +└─────────────────────────┘ +``` + +#### 界面 3:历史数据 - 热力图 +``` +┌────────────────────────────────────────────────────────┐ +│ 红球热力图(出现频次) │ +│ │ +│ 01 [████████] 120 次 17 [██████████] 135 次 │ +│ 02 [██████] 95 次 18 [████████] 122 次 │ +│ 03 [████████████] 142 次 19 [██████████] 138 次 │ +│ ... │ +│ │ +│ 蓝球热力图 │ +│ 01 [██████] 88 次 09 [████████] 118 次 │ +│ 02 [████] 75 次 10 [██████] 92 次 │ +│ ... │ +└────────────────────────────────────────────────────────┘ +``` + +--- + +## 6. 排期建议 + +### 开发排期(参考历史估算) +| 阶段 | 任务 | 预估工时 | 负责人 | +|------|------|----------|--------| +| 第一阶段 | Flask 后端框架搭建 + 集成 lottery.py | 4 小时 | 徐聪 | +| 第二阶段 | API 接口开发(生成、查询、下载) | 6 小时 | 徐聪 | +| 第三阶段 | PC 端前端页面开发(Vue3 + Element Plus) | 8 小时 | 苏锦绘 | +| 第四阶段 | 移动端适配(Vant UI) | 6 小时 | 苏锦绘 | +| 第五阶段 | 部署配置 + 端口协调 + 系统测试 | 4 小时 | 严维序 | +| 第六阶段 | 产品验收 + Bug 修复 | 4 小时 | 沈路明 | + +**总预估工时**: 32 小时(约 4 个工作日) + +### 关键依赖 +- 运维需提前确认 192.168.1.99 服务器上的可用端口 +- lottery.py 业务逻辑已审核通过,无需调整 +- 历史数据文件路径:~/Studio/lottoData/双色球历史数据.xlsx + +--- + +## 7. 风险与应对 + +### 需求风险 +| 风险 | 概率 | 影响 | 应对方案 | +|------|------|------|----------| +| 移动端适配工作量大 | 中 | 中 | 优先保证核心功能,复杂交互在 PC 端使用 | +| 用户对 Excel 格式有特殊要求 | 低 | 低 | 保留配置扩展性,支持自定义列 | + +### 技术风险 +| 风险 | 概率 | 影响 | 应对方案 | +|------|------|------|----------| +| 端口冲突 | 中 | 高 | 提前与运维确认端口表,配置文件中可调整端口 | +| 大文件下载超时 | 低 | 中 | 添加进度条,支持断点续传 | +| 并发访问性能瓶颈 | 低 | 中 | 限制单 IP 请求频率,添加请求队列 | + +### 安全风险 +| 风险 | 概率 | 影响 | 应对方案 | +|------|------|------|----------| +| 内网穿透导致外网访问 | 低 | 高 | 防火墙规则限制,仅允许内网网段 | +| Token 泄露 | 中 | 中 | 定期更换 Token,配置文件权限限制 | + +--- + +## 8. 部署与运维 + +### 8.1 服务器配置 +- **服务器**: 192.168.1.99 +- **路径**: ~/Studio/lottoData/ +- **账号**: vincent +- **监听**: 0.0.0.0:{PORT}(PORT 由运维分配) +- **进程管理**: systemd 或 supervisor + +### 8.2 端口分配要求 +请运维工程师提前维护各服务器端口使用表,本项目需分配一个未使用的端口(建议范围 8080-8099)。 + +### 8.3 防火墙规则 +```bash +# 仅允许内网访问 +iptables -A INPUT -p tcp --dport {PORT} -s 192.168.0.0/16 -j ACCEPT +iptables -A INPUT -p tcp --dport {PORT} -j DROP +``` + +### 8.4 服务启动脚本 +```bash +# systemd 配置示例 +[Unit] +Description=Lottery Web Service +After=network.target + +[Service] +Type=simple +User=vincent +WorkingDirectory=/home/vincent/Studio/lottoData +ExecStart=/home/vincent/Studio/lottoData/.venv/bin/python app.py +Restart=always + +[Install] +WantedBy=multi-user.target +``` + +--- + +## 9. 验收标准 + +### 功能验收 +- [ ] PC 端可正常访问并完成号码生成、查看历史、下载文件 +- [ ] 手机端可正常访问并完成核心操作 +- [ ] 数据导出 API 可被远程调用 +- [ ] 生成的 Excel 文件与 lottery.py 直接运行结果一致 + +### 性能验收 +- [ ] 页面加载时间 < 2 秒(内网) +- [ ] 100 注号码生成时间 < 3 秒 +- [ ] 支持 5 个并发用户同时操作 + +### 安全验收 +- [ ] 外网无法访问服务(防火墙限制) +- [ ] 未携带 Token 无法调用 API +- [ ] 无法通过路径遍历访问非 lottery 目录文件 + +--- + +## 10. 版本历史 + +| 版本 | 日期 | 变更内容 | 作者 | +|------|------|----------|------| +| v1.0 | 2026-06-19 | 初始版本,基于 lottery.py 业务逻辑 | 沈路明 | + +--- + +## 11. 附录 + +### 11.1 数据字段定义 +**生成号码表字段**: +- 序号:数字,从 1 开始 +- 红球 1-6:数字 1-33 +- 蓝球:数字 1-16 +- 和值:6 个红球之和 +- 奇偶比:格式 "X:Y",如 "3:3" +- 大小比:格式 "X:Y",如 "3:3" +- 跨度:最大红球 - 最小红球 + +**统计信息表字段**: +- 生成时间:DateTime +- 生成策略:Text ("高级策略" 或 "基础策略") +- 生成注数:Integer +- 红球热号:Text (逗号分隔) +- 红球冷号:Text (逗号分隔) +- 蓝球热号:Text (逗号分隔) +- 最常见奇偶比:Text +- 最常见大小比:Text +- 和值范围:Text ("最小值 - 最大值") +- 跨度范围:Text ("最小值 - 最大值") + +### 11.2 配置文件示例 (config.yaml) +```yaml +server: + host: 0.0.0.0 + port: 8085 # 运维分配的端口 + +security: + api_token: "your-secret-token-here" + allowed_networks: + - "192.168.0.0/16" + +storage: + history_file: "双色球历史数据.xlsx" + output_dir: "lottery" + +display: + default_tickets: 10 + max_tickets: 1000 + tickets_per_page: 20 +``` + +--- + +**PRD 完成时间**: 2026-06-19 +**产品经理**: 沈路明 +**状态**: 待评审 \ No newline at end of file diff --git a/fetch_data.py b/fetch_data.py new file mode 100644 index 0000000..8867d75 --- /dev/null +++ b/fetch_data.py @@ -0,0 +1,132 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +双色球历史数据抓取脚本 +从 https://www.55128.cn/kjh/fcssq-history-120.htm 抓取数据 +更新「双色球历史数据.xlsx」文件 +""" + +import requests +from bs4 import BeautifulSoup +import pandas as pd +from datetime import datetime +import os +import re + +# 数据源 URL +URL = "https://www.55128.cn/kjh/fcssq-history-120.htm" +# 输出文件路径 +SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__)) +OUTPUT_FILE = os.path.join(SCRIPT_DIR, "双色球历史数据.xlsx") + +# 请求头,模拟浏览器 +HEADERS = { + "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36", + "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8", + "Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8", +} + + +def fetch_lottery_data(): + """抓取双色球历史数据""" + print(f"[{datetime.now()}] 开始抓取数据...") + + try: + response = requests.get(URL, headers=HEADERS, timeout=30) + response.raise_for_status() + response.encoding = "utf-8" + + soup = BeautifulSoup(response.text, "html.parser") + + # 查找表格数据 + table = soup.find("table") + if not table: + print("错误:未找到数据表格") + return None + + # 解析表格 + data_rows = [] + rows = table.find_all("tr") + + for row in rows: + cols = row.find_all(["td", "th"]) + if len(cols) >= 8: + try: + row_data = [col.get_text(strip=True) for col in cols] + data_rows.append(row_data) + except Exception as e: + continue + + if not data_rows: + print("错误:未解析到任何数据") + return None + + print(f"成功解析 {len(data_rows)} 条数据") + return data_rows + + except requests.exceptions.RequestException as e: + print(f"网络请求错误:{e}") + return None + except Exception as e: + print(f"解析错误:{e}") + return None + + +def save_to_excel(data_rows): + """保存数据到 Excel 文件""" + if not data_rows: + print("无数据可保存") + return False + + try: + # 创建 DataFrame + num_cols = min(len(row) for row in data_rows) + data_rows = [row[:num_cols] for row in data_rows] + + # 列名定义(最多 11 列) + columns = ["期号", "开奖日期", "红球 1", "红球 2", "红球 3", "红球 4", "红球 5", "红球 6", "蓝球", "特别号", "奖池"] + + # 如果列数不匹配,使用通用列名 + actual_columns = columns[:num_cols] if num_cols <= len(columns) else [f"列{i+1}" for i in range(num_cols)] + + df = pd.DataFrame(data_rows, columns=actual_columns) + + # 保存为 Excel + df.to_excel(OUTPUT_FILE, index=False, engine="openpyxl") + + print(f"[{datetime.now()}] 数据已保存到:{OUTPUT_FILE}") + print(f"共保存 {len(df)} 条记录") + return True + + except Exception as e: + print(f"保存 Excel 错误:{e}") + return False + + +def main(): + """主函数""" + print("=" * 60) + print("双色球历史数据抓取工具") + print("=" * 60) + + # 抓取数据 + data = fetch_lottery_data() + + if data: + # 保存数据 + success = save_to_excel(data) + if success: + print("=" * 60) + print("任务完成!") + print("=" * 60) + return 0 + else: + print("保存失败") + return 1 + else: + print("抓取失败") + return 1 + + +if __name__ == "__main__": + exit(main()) \ No newline at end of file diff --git a/index.html b/index.html new file mode 100644 index 0000000..7561421 --- /dev/null +++ b/index.html @@ -0,0 +1,1171 @@ + + + + + + 🎯 双色球号码生成系统 + + + + + +
+ + +
+

🎯 双色球号码生成系统

+

基于历史数据分析 · 支持 PC 端和移动端

+
+ + + + + +
+
+
+
🎲 生成双色球号码
+
+
+ + +
+
+ + +
+
+ + +
+
+
+ + +
+
+
+ 📋 生成结果 + 10 注 +
+
+ + +
+
+
+
+ + +
+
📊 数据概览
+
+
加载统计数据中...
+
+
+
+ + +
+
+
📊 双色球历史开奖数据
+ +
+
加载历史数据中...
+
+ +
+
+ + +
+
+
📋 生成记录
+
+
加载记录中...
+
+ +
+
+ + +
+
+
📈 号码统计分析
+
+
加载统计中...
+
+
+
+
+ + +
+
+
+ 🎲 生成 +
+
+ 📊 历史 +
+
+ 📋 记录 +
+
+ 📈 统计 +
+
+
+ + + + + diff --git a/lottery.py b/lottery.py new file mode 100644 index 0000000..42662e5 --- /dev/null +++ b/lottery.py @@ -0,0 +1,1189 @@ +import pandas as pd +import numpy as np +import random +from datetime import datetime, timedelta +import os +from collections import Counter +import re +import traceback + + +class DoubleColorBallGenerator: + def __init__(self, history_file="双色球历史数据.xlsx", config=None): + """ + 初始化双色球号码生成器 + + Args: + history_file: 历史数据文件路径 + config: 配置参数 + """ + self.history_file = history_file + self.history_data = None + self.red_stats = None + self.blue_stats = None + self.features_stats = None + + # 默认配置 + self.config = config or { + 'hot_red_count': 15, + 'cold_red_count': 10, + 'hot_blue_count': 8, + 'hot_blue_probability': 0.7, + 'max_adjustment_attempts': 20, + 'hot_red_display_count': 10, + 'cold_red_display_count': 10, + 'hot_blue_display_count': 5, + 'min_tickets': 1, + 'max_tickets': 1000 + } + + def load_history_data(self): + """加载历史数据""" + try: + # 检查文件是否存在 + if not os.path.exists(self.history_file): + print(f"错误: 文件 {self.history_file} 不存在") + return False + + # 读取Excel文件 + print(f"正在读取文件: {self.history_file}") + try: + self.history_data = pd.read_excel(self.history_file) + except Exception as excel_error: + print(f"读取Excel文件失败: {excel_error}") + return False + + # 检查数据是否为空 + if self.history_data.empty: + print("错误: 历史数据文件为空") + return False + + print(f"加载成功,共{len(self.history_data)}条历史记录") + print(f"数据列: {list(self.history_data.columns)}") + + # 检查是否包含必要的列 + if '号码' not in self.history_data.columns: + print("错误: 历史数据文件缺少'号码'列") + return False + + # 解析号码列 + def parse_numbers(row): + """解析单行号码数据""" + try: + # 处理号码字符串 - 直接转换为字符串然后分割 + if pd.isna(row['号码']): + return [], 0 + + numbers_str = str(row['号码']) + + # 使用正则表达式提取所有数字 + number_list = re.findall(r'\d+', numbers_str) + + if len(number_list) >= 7: + try: + red_balls = [int(x) for x in number_list[:6]] + blue_ball = int(number_list[6]) + # 验证号码范围 + if all(1 <= ball <= 33 for ball in red_balls) and 1 <= blue_ball <= 16: + return red_balls, blue_ball + else: + print(f"警告: 号码范围异常: {red_balls} + {blue_ball}") + return [], 0 + except ValueError: + # 如果转换失败,尝试其他解析方式 + # 替换各种空格字符为单个空格 + cleaned_str = re.sub(r'\s+', ' ', numbers_str.strip()) + parts = cleaned_str.split() + if len(parts) >= 7: + try: + red_balls = [int(x) for x in parts[:6]] + blue_ball = int(parts[6]) + # 验证号码范围 + if all(1 <= ball <= 33 for ball in red_balls) and 1 <= blue_ball <= 16: + return red_balls, blue_ball + else: + print(f"警告: 号码范围异常: {red_balls} + {blue_ball}") + return [], 0 + except ValueError: + return [], 0 + return [], 0 + return [], 0 + except Exception as e: + print(f"解析号码时出错: {e}") + return [], 0 + + # 应用解析函数 + parsed = self.history_data.apply(parse_numbers, axis=1) + self.history_data['红球'] = [x[0] for x in parsed] + self.history_data['蓝球'] = [x[1] for x in parsed] + + # 打印解析成功的数量 + valid_count = sum(1 for x in parsed if len(x[0]) == 6 and x[1] > 0) + print(f"成功解析 {valid_count} 条号码数据") + + # 检查是否有足够的有效数据 + if valid_count < 10: + print("警告: 有效历史数据较少,可能影响分析结果") + + # 计算统计数据 + try: + self._calculate_statistics() + except Exception as stats_error: + print(f"计算统计数据失败: {stats_error}") + print(traceback.format_exc()) + return False + + return True + + except Exception as e: + print(f"加载历史数据失败: {e}") + print(traceback.format_exc()) + return False + + def _calculate_statistics(self): + """计算统计数据""" + if self.history_data is None or len(self.history_data) == 0: + print("警告: 没有历史数据可供统计") + return + + # 1. 号码频次统计 + red_ball_counts = Counter() + blue_ball_counts = Counter() + sum_values = [] + span_values = [] + + # 一次性遍历收集所有数据,减少循环次数 + for _, row in self.history_data.iterrows(): + # 处理红球 + red_balls = row.get('红球') + if isinstance(red_balls, list) and len(red_balls) == 6: + # 统计红球频次 + red_ball_counts.update(red_balls) + # 计算和值 + sum_values.append(sum(red_balls)) + # 计算跨度 + span_values.append(max(red_balls) - min(red_balls)) + + # 处理蓝球 + blue_ball = row.get('蓝球') + if blue_ball and blue_ball > 0: + blue_ball_counts[blue_ball] += 1 + + self.red_stats = red_ball_counts + self.blue_stats = blue_ball_counts + + # 2. 特征统计 + self.features_stats = { + 'odd_even_ratio': {}, + 'size_ratio': {}, + 'sum_range': {}, + 'span_range': {} + } + + # 统计奇偶比 - 修复解析 + if '奇偶比' in self.history_data.columns: + odd_even_ratio_counts = Counter() + for ratio in self.history_data['奇偶比']: + if pd.isna(ratio): + continue + ratio_str = str(ratio) + # 提取数字部分 + parts = re.findall(r'\d+', ratio_str) + if len(parts) >= 2: + ratio_key = f"{parts[0]}:{parts[1]}" + odd_even_ratio_counts[ratio_key] += 1 + + if odd_even_ratio_counts: + total_count = sum(odd_even_ratio_counts.values()) + self.features_stats['odd_even_ratio'] = { + k: v/total_count for k, v in odd_even_ratio_counts.items() + } + + # 统计大小比 - 修复解析 + if '大小比' in self.history_data.columns: + size_ratio_counts = Counter() + for ratio in self.history_data['大小比']: + if pd.isna(ratio): + continue + ratio_str = str(ratio) + parts = re.findall(r'\d+', ratio_str) + if len(parts) >= 2: + ratio_key = f"{parts[0]}:{parts[1]}" + size_ratio_counts[ratio_key] += 1 + + if size_ratio_counts: + total_count = sum(size_ratio_counts.values()) + self.features_stats['size_ratio'] = { + k: v/total_count for k, v in size_ratio_counts.items() + } + + # 计算和值统计 + if sum_values: + sum_array = np.array(sum_values) + self.features_stats['sum_range']['min'] = int(sum_array.min()) + self.features_stats['sum_range']['max'] = int(sum_array.max()) + self.features_stats['sum_range']['mean'] = float(sum_array.mean()) + self.features_stats['sum_range']['std'] = float(sum_array.std()) + + # 计算跨度统计 + if span_values: + span_array = np.array(span_values) + self.features_stats['span_range']['min'] = int(span_array.min()) + self.features_stats['span_range']['max'] = int(span_array.max()) + self.features_stats['span_range']['mean'] = float(span_array.mean()) + self.features_stats['span_range']['std'] = float(span_array.std()) + + def get_hot_red_balls(self, n=10): + """获取热号红球""" + if not self.red_stats: + print("警告: 红球统计数据为空") + # 返回随机红球作为默认,避免固定范围 + return random.sample(range(1, 34), min(n, 33)) + + # 按出现频率排序 + sorted_reds = sorted(self.red_stats.items(), + key=lambda x: x[1], reverse=True) + result = [x[0] for x in sorted_reds[:n]] + + # 如果结果不够n个,用其他球补全 + if len(result) < n: + all_balls = list(range(1, 34)) + missing = [x for x in all_balls if x not in result] + result.extend(random.sample( + missing, min(n - len(result), len(missing)))) + + return result + + def get_cold_red_balls(self, n=10): + """获取冷号红球""" + if not self.red_stats: + print("警告: 红球统计数据为空") + # 返回随机红球作为默认,避免固定范围 + return random.sample(range(1, 34), min(n, 33)) + + # 按出现频率排序(升序) + sorted_reds = sorted(self.red_stats.items(), key=lambda x: x[1]) + result = [x[0] for x in sorted_reds[:n]] + + # 如果结果不够n个,用其他球补全 + if len(result) < n: + all_balls = list(range(1, 34)) + missing = [x for x in all_balls if x not in result] + result.extend(random.sample( + missing, min(n - len(result), len(missing)))) + + return result + + def get_hot_blue_balls(self, n=5): + """获取热号蓝球""" + if not self.blue_stats: + print("警告: 蓝球统计数据为空") + # 返回随机蓝球作为默认,避免固定范围 + return random.sample(range(1, 17), min(n, 16)) + + sorted_blues = sorted(self.blue_stats.items(), + key=lambda x: x[1], reverse=True) + result = [x[0] for x in sorted_blues[:n]] + + # 如果结果不够n个,用其他球补全 + if len(result) < n: + all_balls = list(range(1, 17)) + missing = [x for x in all_balls if x not in result] + result.extend(random.sample( + missing, min(n - len(result), len(missing)))) + + return result + + def parse_ratio(self, ratio_str): + """解析奇偶比/大小比字符串""" + if pd.isna(ratio_str): + return 3, 3 + + ratio_str = str(ratio_str) + # 提取数字 + parts = re.findall(r'\d+', ratio_str) + if len(parts) >= 2: + odd = int(parts[0]) + even = int(parts[1]) + return odd, even + return 3, 3 # 默认3:3 + + def _adjust_balls_by_criteria(self, red_balls, current_value, target_value, get_balls_to_remove, get_candidates, recalculate_current): + """通用的号码调整方法 + + Args: + red_balls: 当前红球集合 + current_value: 当前值 + target_value: 目标值 + get_balls_to_remove: 获取要移除的球的函数 + get_candidates: 获取候选球的函数 + recalculate_current: 重新计算当前值的函数 + + Returns: + 调整后的红球集合 + """ + attempts = 0 + max_attempts = self.config['max_adjustment_attempts'] + + while abs(current_value - target_value) > 1 and attempts < max_attempts: + balls_to_remove = get_balls_to_remove(red_balls) + candidates = get_candidates(red_balls) + + if balls_to_remove and candidates: + # 移除一个球并添加一个候选球 + ball_to_remove = random.choice(balls_to_remove) + ball_to_add = random.choice(candidates) + + red_balls.remove(ball_to_remove) + red_balls.append(ball_to_add) + + # 重新计算当前值 + current_value = recalculate_current(red_balls) + + attempts += 1 + + return red_balls + + def _select_hot_cold_balls(self): + """选择热号和冷号组合""" + red_balls = set() + + # 获取热号和冷号 + hot_reds = self.get_hot_red_balls(self.config['hot_red_count']) + cold_reds = self.get_cold_red_balls(self.config['cold_red_count']) + + # 增加随机性:热号数量在2-4之间随机 + hot_count = random.randint(2, 4) + cold_count = 6 - hot_count + + # 从热号中随机选择(去除已选的) + available_hot = [x for x in hot_reds if x not in red_balls] + if available_hot and hot_count > 0: + # 增加随机性:不总是选择前几个热号 + if len(available_hot) > hot_count: + # 随机打乱热号顺序后选择 + random.shuffle(available_hot) + selected = random.sample( + available_hot, min(hot_count, len(available_hot))) + red_balls.update(selected) + + # 从冷号中随机选择 + available_cold = [x for x in cold_reds if x not in red_balls] + if available_cold and cold_count > 0: + selected = random.sample(available_cold, min( + cold_count, len(available_cold))) + red_balls.update(selected) + + # 如果还不够6个,用随机数补全 + while len(red_balls) < 6: + ball = random.randint(1, 33) + red_balls.add(ball) + + return list(red_balls) + + def _adjust_odd_even_ratio(self, red_balls): + """调整奇偶比""" + if self.features_stats.get('odd_even_ratio'): + common_ratios = list(self.features_stats['odd_even_ratio'].keys()) + if common_ratios: + # 增加随机性:80%概率选择最常见的奇偶比,20%随机选择 + if random.random() < 0.8: + target_ratio = max(self.features_stats['odd_even_ratio'], + key=self.features_stats['odd_even_ratio'].get) + else: + target_ratio = random.choice(common_ratios) + target_odd, target_even = self.parse_ratio(target_ratio) + + # 调整当前组合的奇偶比 + current_odd = sum(1 for x in red_balls if x % 2 == 1) + + def get_balls_to_remove_odd_excess(balls): + return [x for x in balls if x % 2 == 1] + + def get_candidates_odd_excess(balls): + return [x for x in range(1, 34) if x % 2 == 0 and x not in balls] + + def get_balls_to_remove_even_excess(balls): + return [x for x in balls if x % 2 == 0] + + def get_candidates_even_excess(balls): + return [x for x in range(1, 34) if x % 2 == 1 and x not in balls] + + def recalculate_odd(balls): + return sum(1 for x in balls if x % 2 == 1) + + if current_odd > target_odd: + # 减少奇数,增加偶数 + red_balls = self._adjust_balls_by_criteria( + red_balls, current_odd, target_odd, + get_balls_to_remove_odd_excess, + get_candidates_odd_excess, + recalculate_odd + ) + elif current_odd < target_odd: + # 增加奇数,减少偶数 + red_balls = self._adjust_balls_by_criteria( + red_balls, current_odd, target_odd, + get_balls_to_remove_even_excess, + get_candidates_even_excess, + recalculate_odd + ) + return red_balls + + def _adjust_size_ratio(self, red_balls): + """调整大小比""" + if self.features_stats.get('size_ratio'): + common_size_ratios = list(self.features_stats['size_ratio'].keys()) + if common_size_ratios: + # 增加随机性:80%概率选择最常见的大小比,20%随机选择 + if random.random() < 0.8: + target_size_ratio = max(self.features_stats['size_ratio'], + key=self.features_stats['size_ratio'].get) + else: + target_size_ratio = random.choice(common_size_ratios) + target_small, target_large = self.parse_ratio( + target_size_ratio) + + current_small = sum(1 for x in red_balls if x <= 16) + + def get_balls_to_remove_small_excess(balls): + return [x for x in balls if x <= 16] + + def get_candidates_small_excess(balls): + return [x for x in range(17, 34) if x not in balls] + + def get_balls_to_remove_large_excess(balls): + return [x for x in balls if x > 16] + + def get_candidates_large_excess(balls): + return [x for x in range(1, 17) if x not in balls] + + def recalculate_small(balls): + return sum(1 for x in balls if x <= 16) + + if current_small > target_small: + # 减少小数,增加大数 + red_balls = self._adjust_balls_by_criteria( + red_balls, current_small, target_small, + get_balls_to_remove_small_excess, + get_candidates_small_excess, + recalculate_small + ) + elif current_small < target_small: + # 增加小数,减少大数 + red_balls = self._adjust_balls_by_criteria( + red_balls, current_small, target_small, + get_balls_to_remove_large_excess, + get_candidates_large_excess, + recalculate_small + ) + return red_balls + + def _adjust_sum_range(self, red_balls): + """调整和值范围""" + if self.features_stats.get('sum_range') and 'mean' in self.features_stats['sum_range']: + current_sum = sum(red_balls) + target_mean = self.features_stats['sum_range']['mean'] + target_std = self.features_stats['sum_range']['std'] + + # 增加随机性:90%概率调整到正常范围,10%保持原样 + if random.random() < 0.9: + # 如果和值偏离平均值太多,进行调整 + lower_bound = target_mean - target_std + upper_bound = target_mean + target_std + + attempts = 0 + while (current_sum < lower_bound or current_sum > upper_bound) and attempts < 20: + if current_sum < lower_bound: + # 和值太小,用大数替换小数 + small_balls = [x for x in red_balls if x <= 10] + large_candidates = [x for x in range( + 25, 34) if x not in red_balls] + if small_balls and large_candidates: + red_balls.remove(random.choice(small_balls)) + red_balls.append(random.choice(large_candidates)) + elif current_sum > upper_bound: + # 和值太大,用小数替换大数 + large_balls = [x for x in red_balls if x >= 25] + small_candidates = [x for x in range( + 1, 12) if x not in red_balls] + if large_balls and small_candidates: + red_balls.remove(random.choice(large_balls)) + red_balls.append(random.choice(small_candidates)) + + current_sum = sum(red_balls) + attempts += 1 + return red_balls + + def _adjust_span_range(self, red_balls): + """调整跨度范围""" + if self.features_stats.get('span_range') and 'mean' in self.features_stats['span_range']: + current_span = max(red_balls) - min(red_balls) + span_mean = self.features_stats['span_range']['mean'] + span_std = self.features_stats['span_range']['std'] + + # 增加随机性:90%概率调整到正常范围,10%保持原样 + if random.random() < 0.9: + # 跨度在平均值±标准差范围内 + span_lower = span_mean - span_std + span_upper = span_mean + span_std + + attempts = 0 + while (current_span < span_lower or current_span > span_upper) and attempts < 20: + if current_span < span_lower: + # 跨度太小,扩大范围 + # 尝试替换最小或最大的球 + if random.choice([True, False]): + # 替换最小球为更小的数 + min_ball = min(red_balls) + candidates = [x for x in range( + 1, min_ball) if x not in red_balls] + if candidates: + red_balls.remove(min_ball) + red_balls.append(random.choice(candidates)) + else: + # 替换最大球为更大的数 + max_ball = max(red_balls) + candidates = [x for x in range( + max_ball + 1, 34) if x not in red_balls] + if candidates: + red_balls.remove(max_ball) + red_balls.append(random.choice(candidates)) + elif current_span > span_upper: + # 跨度太大,缩小范围 + # 随机替换一个球,使其更靠近中心 + center = sum(red_balls) / 6 + ball_to_replace = random.choice(red_balls) + + # 选择离中心更近的候选球 + candidates = [x for x in range( + 1, 34) if x not in red_balls] + if candidates: + # 找到离中心最近的候选球 + closest = min( + candidates, key=lambda x: abs(x - center)) + red_balls.remove(ball_to_replace) + red_balls.append(closest) + + current_span = max(red_balls) - min(red_balls) + attempts += 1 + return red_balls + + def _select_blue_ball(self): + """选择蓝球""" + hot_blues = self.get_hot_blue_balls(self.config['hot_blue_count']) + if hot_blues and random.random() < self.config['hot_blue_probability']: # 基于配置的概率选择热号蓝球 + blue_ball = random.choice(hot_blues) + else: + blue_ball = random.randint(1, 16) + return blue_ball + + def generate_single_ticket_advanced(self): + """生成单注号码(高级策略)""" + # 选择热号和冷号组合 + red_balls = self._select_hot_cold_balls() + + # 调整奇偶比 + red_balls = self._adjust_odd_even_ratio(red_balls) + + # 调整大小比 + red_balls = self._adjust_size_ratio(red_balls) + + # 调整和值范围 + red_balls = self._adjust_sum_range(red_balls) + + # 调整跨度范围 + red_balls = self._adjust_span_range(red_balls) + + # 对红球排序 + red_balls.sort() + + # 选择蓝球 + blue_ball = self._select_blue_ball() + + return red_balls, blue_ball + + def generate_single_ticket_basic(self): + """生成单注号码(基础策略)""" + # 完全随机生成 + red_balls = sorted(random.sample(range(1, 34), 6)) + blue_ball = random.randint(1, 16) + return red_balls, blue_ball + + def generate_multiple_tickets(self, num_tickets, strategy="advanced"): + """生成多注号码 + + Args: + num_tickets: 注数 + strategy: 生成策略,可选 "advanced"(高级) 或 "basic"(基础) + """ + tickets = [] + generated_numbers = set() # 用于存储已生成的号码组合,避免重复 + + failed_attempts = 0 + max_attempts = num_tickets * 10 # 最多尝试次数 + max_attempts_per_ticket = 100 # 每注最多尝试次数 + + # 预计算一些值,避免重复计算 + use_advanced = strategy == "advanced" + + for i in range(num_tickets): + attempts = 0 + success = False + + while not success and attempts < max_attempts_per_ticket: + try: + if use_advanced: + reds, blue = self.generate_single_ticket_advanced() + else: + reds, blue = self.generate_single_ticket_basic() + + # 验证生成的号码 + if len(reds) == 6: + # 检查号码范围 + if all(1 <= x <= 33 for x in reds) and 1 <= blue <= 16: + # 检查是否有重复号码 + if len(set(reds)) == 6: + # 生成唯一键,用于检查重复 + ticket_key = (tuple(sorted(reds)), blue) + if ticket_key not in generated_numbers: + # 计算一次和值,避免重复计算 + sum_reds = sum(reds) + # 计算奇偶比 + odd_count = sum(1 for x in reds if x % 2 == 1) + even_count = 6 - odd_count + # 计算大小比 + large_count = sum(1 for x in reds if x > 16) + small_count = 6 - large_count + # 计算跨度 + span = max(reds) - min(reds) + + tickets.append({ + '序号': i + 1, + '红球1': reds[0], + '红球2': reds[1], + '红球3': reds[2], + '红球4': reds[3], + '红球5': reds[4], + '红球6': reds[5], + '蓝球': blue, + '和值': sum_reds, + '奇偶比': f"{odd_count}:{even_count}", + '大小比': f"{large_count}:{small_count}", + '跨度': span + }) + generated_numbers.add(ticket_key) + success = True + + attempts += 1 + failed_attempts += 1 + + if failed_attempts > max_attempts: + print(f"警告: 生成失败次数过多,可能已生成{len(tickets)}注") + if len(tickets) > 0: + return pd.DataFrame(tickets) + else: + # 返回基础随机生成的号码 + print("切换到基础随机策略") + return self.generate_multiple_tickets(num_tickets, "basic") + + except Exception as e: + attempts += 1 + failed_attempts += 1 + if attempts % 50 == 0: # 减少错误打印频率 + print(f"生成第{i+1}注时出错,尝试{attempts}次: {e}") + + # 确保返回的DataFrame结构正确 + if tickets: + return pd.DataFrame(tickets) + else: + # 如果没有生成成功,返回空的DataFrame + return pd.DataFrame(columns=['序号', '红球1', '红球2', '红球3', '红球4', '红球5', '红球6', '蓝球', '和值', '奇偶比', '大小比', '跨度']) + + def save_to_excel(self, tickets_df, num_tickets, strategy="advanced"): + """保存生成的号码到Excel文件 + + Args: + tickets_df: 号码DataFrame + num_tickets: 注数 + strategy: 生成策略 + """ + try: + # 检查DataFrame是否为空 + if tickets_df.empty: + print("错误: 没有号码数据可保存") + return None + + # 确保保存目录存在 + save_dir = "./lottery" + if not os.path.exists(save_dir): + try: + os.makedirs(save_dir) + print(f"创建保存目录: {save_dir}") + except Exception as dir_error: + print(f"创建保存目录失败: {dir_error}") + return None + + # 检查目录是否可写 + if not os.access(save_dir, os.W_OK): + print(f"错误: 目录 {save_dir} 没有写入权限") + return None + + # 生成文件名 + today = datetime.now().strftime("%Y%m%d") + base_filename = f"双色球模拟号码-{num_tickets}注-{today}" + + # 检查文件是否存在,避免覆盖 + counter = 1 + filename = f"{save_dir}/{base_filename}-{counter:03d}.xlsx" + while os.path.exists(filename): + counter += 1 + filename = f"{save_dir}/{base_filename}-{counter:03d}.xlsx" + + print(f"正在保存到文件: {filename}") + + # 保存到Excel + try: + with pd.ExcelWriter(filename, engine='openpyxl') as writer: + # 写入生成号码 + tickets_df.to_excel(writer, sheet_name='生成号码', index=False) + + # 添加统计信息sheet + stats_data = { + '统计项': ['生成时间', '生成策略', '生成注数'], + '统计值': [ + datetime.now().strftime("%Y-%m-%d %H:%M:%S"), + "高级策略" if strategy == "advanced" else "基础策略", + num_tickets + ] + } + + # 添加红球热号统计 + if self.red_stats: + try: + hot_reds = self.get_hot_red_balls(self.config['hot_red_display_count']) + stats_data['统计项'].append(f'红球热号(前{self.config["hot_red_display_count"]})') + stats_data['统计值'].append(', '.join(map(str, hot_reds))) + except Exception as e: + print(f"添加红球热号统计失败: {e}") + + # 添加红球冷号统计 + if self.red_stats: + try: + cold_reds = self.get_cold_red_balls(self.config['cold_red_display_count']) + stats_data['统计项'].append(f'红球冷号(前{self.config["cold_red_display_count"]})') + stats_data['统计值'].append(', '.join(map(str, cold_reds))) + except Exception as e: + print(f"添加红球冷号统计失败: {e}") + + # 添加蓝球热号统计 + if self.blue_stats: + try: + hot_blues = self.get_hot_blue_balls(self.config['hot_blue_display_count']) + stats_data['统计项'].append(f'蓝球热号(前{self.config["hot_blue_display_count"]})') + stats_data['统计值'].append(', '.join(map(str, hot_blues))) + except Exception as e: + print(f"添加蓝球热号统计失败: {e}") + + # 添加奇偶比统计 + if self.features_stats.get('odd_even_ratio'): + try: + common_odd_even = max(self.features_stats['odd_even_ratio'], + key=self.features_stats['odd_even_ratio'].get) + stats_data['统计项'].append('最常见奇偶比') + stats_data['统计值'].append(f"{common_odd_even}") + except Exception as e: + print(f"添加奇偶比统计失败: {e}") + + # 添加大小比统计 + if self.features_stats.get('size_ratio'): + try: + common_size = max(self.features_stats['size_ratio'], + key=self.features_stats['size_ratio'].get) + stats_data['统计项'].append('最常见大小比') + stats_data['统计值'].append(f"{common_size}") + except Exception as e: + print(f"添加大小比统计失败: {e}") + + # 添加和值范围 + if self.features_stats.get('sum_range'): + try: + sum_range = self.features_stats['sum_range'] + if 'min' in sum_range and 'max' in sum_range: + stats_data['统计项'].append('和值范围') + stats_data['统计值'].append( + f"{sum_range['min']}-{sum_range['max']}") + except Exception as e: + print(f"添加和值范围统计失败: {e}") + + # 添加跨度范围 + if self.features_stats.get('span_range'): + try: + span_range = self.features_stats['span_range'] + if 'min' in span_range and 'max' in span_range: + stats_data['统计项'].append('跨度范围') + stats_data['统计值'].append( + f"{span_range['min']}-{span_range['max']}") + except Exception as e: + print(f"添加跨度范围统计失败: {e}") + + # 写入统计信息 + try: + stats_df = pd.DataFrame(stats_data) + stats_df.to_excel(writer, sheet_name='统计信息', index=False) + except Exception as e: + print(f"写入统计信息失败: {e}") + + # 自动调整列宽 + try: + for sheet_name in writer.sheets: + worksheet = writer.sheets[sheet_name] + for column in worksheet.columns: + max_length = 0 + column_letter = column[0].column_letter + for cell in column: + try: + if cell.value and len(str(cell.value)) > max_length: + max_length = len(str(cell.value)) + except: + pass + adjusted_width = min(max_length + 2, 50) + worksheet.column_dimensions[column_letter].width = adjusted_width + except Exception as e: + print(f"调整列宽失败: {e}") + + except Exception as excel_error: + print(f"Excel写入失败: {excel_error}") + # 尝试删除可能的部分文件 + if os.path.exists(filename): + try: + os.remove(filename) + except: + pass + return None + + # 检查文件是否成功创建 + if not os.path.exists(filename): + print("错误: 文件创建失败") + return None + + # 检查文件大小 + if os.path.getsize(filename) < 100: + print("警告: 文件大小异常,可能保存不完整") + + print(f"✓ 号码已成功保存到文件: {filename}") + print(f"✓ 文件路径: {os.path.abspath(filename)}") + return filename + + except Exception as e: + print(f"保存文件失败: {e}") + print(traceback.format_exc()) + return None + + def display_statistics(self): + """显示统计信息""" + if not self.features_stats: + print("警告: 统计信息为空") + return + + print("\n" + "="*60) + print("双色球历史数据统计信息") + print("="*60) + + # 显示记录数量 + if self.history_data is not None: + print(f"历史记录总数: {len(self.history_data)}条") + + # 红球热号 + hot_reds = self.get_hot_red_balls(self.config['hot_red_display_count']) + print(f"红球热号(前{self.config['hot_red_display_count']}): {', '.join(map(str, hot_reds))}") + + # 红球冷号 + cold_reds = self.get_cold_red_balls(self.config['cold_red_display_count']) + print(f"红球冷号(前{self.config['cold_red_display_count']}): {', '.join(map(str, cold_reds))}") + + # 蓝球热号 + hot_blues = self.get_hot_blue_balls(self.config['hot_blue_display_count']) + print(f"蓝球热号(前{self.config['hot_blue_display_count']}): {', '.join(map(str, hot_blues))}") + + # 常见奇偶比 + if self.features_stats.get('odd_even_ratio'): + common_odd_even = max(self.features_stats['odd_even_ratio'], + key=self.features_stats['odd_even_ratio'].get) + prob = self.features_stats['odd_even_ratio'][common_odd_even] + print(f"最常见奇偶比: {common_odd_even} (概率: {prob:.2%})") + + # 常见大小比 + if self.features_stats.get('size_ratio'): + common_size = max(self.features_stats['size_ratio'], + key=self.features_stats['size_ratio'].get) + prob = self.features_stats['size_ratio'][common_size] + print(f"最常见大小比: {common_size} (概率: {prob:.2%})") + + # 和值统计 + if self.features_stats.get('sum_range'): + sum_range = self.features_stats['sum_range'] + if 'min' in sum_range and 'max' in sum_range: + print(f"和值范围: {sum_range['min']} - {sum_range['max']}") + if 'mean' in sum_range: + print(f"和值平均值: {sum_range['mean']:.1f}") + if 'std' in sum_range: + print(f"和值标准差: {sum_range['std']:.1f}") + + # 跨度统计 + if self.features_stats.get('span_range'): + span_range = self.features_stats['span_range'] + if 'min' in span_range and 'max' in span_range: + print(f"跨度范围: {span_range['min']} - {span_range['max']}") + if 'mean' in span_range: + print(f"跨度平均值: {span_range['mean']:.1f}") + if 'std' in span_range: + print(f"跨度标准差: {span_range['std']:.1f}") + + print("="*60) + + def run_tests(self): + """运行测试用例,验证代码正确性""" + print("\n" + "="*60) + print("开始运行测试用例") + print("="*60) + + test_results = [] + + # 测试1: 验证号码范围 + def test_number_ranges(): + print("\n测试1: 验证号码范围") + try: + # 生成多注号码并验证范围 + for _ in range(100): + # 测试高级策略 + reds, blue = self.generate_single_ticket_advanced() + assert len(reds) == 6, f"红球数量错误: {len(reds)}" + assert all(1 <= x <= 33 for x in reds), f"红球范围错误: {reds}" + assert 1 <= blue <= 16, f"蓝球范围错误: {blue}" + assert len(set(reds)) == 6, f"红球重复: {reds}" + + # 测试基础策略 + reds_basic, blue_basic = self.generate_single_ticket_basic() + assert len(reds_basic) == 6, f"基础策略红球数量错误: {len(reds_basic)}" + assert all(1 <= x <= 33 for x in reds_basic), f"基础策略红球范围错误: {reds_basic}" + assert 1 <= blue_basic <= 16, f"基础策略蓝球范围错误: {blue_basic}" + assert len(set(reds_basic)) == 6, f"基础策略红球重复: {reds_basic}" + + print("✓ 号码范围测试通过") + return True + except Exception as e: + print(f"✗ 号码范围测试失败: {e}") + return False + + # 测试2: 验证多注生成 + def test_multiple_tickets(): + print("\n测试2: 验证多注生成") + try: + # 测试生成不同数量的号码 + for num in [1, 5, 10, 50]: + df = self.generate_multiple_tickets(num, "advanced") + assert len(df) == num, f"高级策略生成数量错误: 期望{num}, 实际{len(df)}" + + df_basic = self.generate_multiple_tickets(num, "basic") + assert len(df_basic) == num, f"基础策略生成数量错误: 期望{num}, 实际{len(df_basic)}" + + print("✓ 多注生成测试通过") + return True + except Exception as e: + print(f"✗ 多注生成测试失败: {e}") + return False + + # 测试3: 验证统计信息 + def test_statistics(): + print("\n测试3: 验证统计信息") + try: + # 验证统计数据结构 + if self.features_stats: + assert 'odd_even_ratio' in self.features_stats, "缺少奇偶比统计" + assert 'size_ratio' in self.features_stats, "缺少大小比统计" + assert 'sum_range' in self.features_stats, "缺少和值范围统计" + assert 'span_range' in self.features_stats, "缺少跨度范围统计" + + # 验证热号冷号获取 + hot_reds = self.get_hot_red_balls(10) + assert len(hot_reds) == 10, f"红球热号数量错误: {len(hot_reds)}" + + cold_reds = self.get_cold_red_balls(10) + assert len(cold_reds) == 10, f"红球冷号数量错误: {len(cold_reds)}" + + hot_blues = self.get_hot_blue_balls(5) + assert len(hot_blues) == 5, f"蓝球热号数量错误: {len(hot_blues)}" + + print("✓ 统计信息测试通过") + return True + except Exception as e: + print(f"✗ 统计信息测试失败: {e}") + return False + + # 测试4: 验证配置参数 + def test_configuration(): + print("\n测试4: 验证配置参数") + try: + # 验证配置参数存在 + required_configs = [ + 'hot_red_count', 'cold_red_count', 'hot_blue_count', + 'hot_blue_probability', 'max_adjustment_attempts', + 'hot_red_display_count', 'cold_red_display_count', + 'hot_blue_display_count', 'min_tickets', 'max_tickets' + ] + + for config in required_configs: + assert config in self.config, f"缺少配置参数: {config}" + + print("✓ 配置参数测试通过") + return True + except Exception as e: + print(f"✗ 配置参数测试失败: {e}") + return False + + # 运行所有测试 + test_results.append(test_number_ranges()) + test_results.append(test_multiple_tickets()) + test_results.append(test_statistics()) + test_results.append(test_configuration()) + + # 显示测试结果 + print("\n" + "="*60) + print("测试结果汇总") + print("="*60) + + passed = sum(test_results) + total = len(test_results) + + print(f"通过测试: {passed}/{total}") + + if passed == total: + print("✓ 所有测试通过!") + else: + print("✗ 部分测试失败,请检查代码") + + print("="*60) + + return passed == total + + +def main(): + """主程序""" + print("="*60) + print("双色球模拟号码生成器") + print("="*60) + + # 初始化生成器 + generator = DoubleColorBallGenerator("双色球历史数据.xlsx") + + # 加载历史数据 + print("\n正在加载历史数据...") + if not generator.load_history_data(): + print("无法加载历史数据,将使用默认随机生成策略") + # 创建一个简单的历史数据用于后续统计 + generator.history_data = pd.DataFrame() + generator.red_stats = Counter() + generator.blue_stats = Counter() + generator.features_stats = {} + + # 显示统计信息 + generator.display_statistics() + + # 用户输入 + while True: + try: + print("\n" + "-"*60) + print("请选择操作:") + print("1. 生成号码") + print("2. 运行测试") + print("0. 退出") + choice = input("请选择 (1/2/0): ").strip() + + if choice == "0": + print("感谢使用,再见!") + break + elif choice == "2": + # 运行测试 + generator.run_tests() + continue + elif choice != "1": + print("请选择有效的操作") + continue + + # 生成号码 + num_tickets = int(input("请输入要生成的注数 (1-1000,输入0退出): ")) + + if num_tickets == 0: + print("感谢使用,再见!") + break + + if num_tickets < generator.config['min_tickets'] or num_tickets > generator.config['max_tickets']: + print(f"注数必须在{generator.config['min_tickets']}-{generator.config['max_tickets']}之间") + continue + + # 选择策略 + print("\n请选择生成策略:") + print("1. 高级策略 (基于历史数据分析)") + print("2. 基础策略 (随机生成)") + strategy_choice = input("请选择 (1或2, 默认为1): ").strip() + + if strategy_choice == "2": + strategy = "basic" + print("使用基础随机策略") + else: + strategy = "advanced" + print("使用高级分析策略") + + # 生成号码 + print(f"\n正在生成 {num_tickets} 注号码...") + tickets_df = generator.generate_multiple_tickets( + num_tickets, strategy) + + if len(tickets_df) == 0: + print("生成号码失败,请重试") + continue + + # 显示前几注 + display_count = min(10, num_tickets) + print(f"\n生成的号码 (显示前{display_count}注):") + print("-"*80) + for i, row in tickets_df.head(display_count).iterrows(): + reds = [row['红球1'], row['红球2'], row['红球3'], + row['红球4'], row['红球5'], row['红球6']] + print( + f"第{row['序号']:03d}注: 红球 {', '.join(f'{x:02d}' for x in reds)} | 蓝球 {row['蓝球']:02d}") + print( + f" 和值: {row['和值']}, 奇偶比: {row['奇偶比']}, 大小比: {row['大小比']}, 跨度: {row['跨度']}") + print("-"*80) + + if num_tickets > display_count: + print(f"... 还有 {num_tickets - display_count} 注未显示") + + # 保存到文件 + save_choice = input( + "\n是否保存到Excel文件? (y/n, 默认为y): ").strip().lower() + if save_choice != 'n': + filename = generator.save_to_excel( + tickets_df, num_tickets, strategy) + if filename: + print(f"\n✓ 文件保存完成,总共 {len(tickets_df)} 注") + + # 继续生成 + continue_choice = input("\n是否继续生成? (y/n, 默认为y): ").strip().lower() + if continue_choice == 'n': + print("感谢使用,再见!") + break + + except ValueError: + print("请输入有效的数字") + except KeyboardInterrupt: + print("\n用户中断操作,再见!") + break + except Exception as e: + print(f"发生错误: {e}") + print(traceback.format_exc()) + + +if __name__ == "__main__": + main() diff --git a/lottery/双色球模拟号码-1000注-20260122-001.xlsx b/lottery/双色球模拟号码-1000注-20260122-001.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..839557416f72f06330e6dbea1aeda5687a66353a GIT binary patch literal 64306 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 literal 0 HcmV?d00001 diff --git a/lottery/双色球模拟号码-2注-20260208-001.xlsx b/lottery/双色球模拟号码-2注-20260208-001.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..99ac7a93cc7ed5781324b3c71ba7c50ab73d1201 GIT binary patch literal 6208 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 literal 0 HcmV?d00001 diff --git a/lottery/双色球模拟号码-2注-20260521-001.xlsx b/lottery/双色球模拟号码-2注-20260521-001.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..ea2f3a6d0915d686eb5e0933120be53641dbe2b3 GIT binary patch literal 6202 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 literal 0 HcmV?d00001 diff --git a/lottery/双色球模拟号码-3注-20260208-001.xlsx b/lottery/双色球模拟号码-3注-20260208-001.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..c0a570df339ec9fc1cc546f1869c7afe4d2ac5fa GIT binary patch literal 11125 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 QBV>pHaMEB!{oA+y0UmV*S^xk5 literal 0 HcmV?d00001 diff --git a/lottery/双色球模拟号码-5注-20260130-002.xlsx b/lottery/双色球模拟号码-5注-20260130-002.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..51892fafd23c74d876cc88d668d1ef2f6f29ee5f GIT binary patch literal 6371 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 TwKM<#@sHQ5v9{6v@#+5oOByET literal 0 HcmV?d00001 diff --git a/lottery/双色球模拟号码-5注-20260205-002.xlsx b/lottery/双色球模拟号码-5注-20260205-002.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..c9e9347a279d5c91d7f0df2b213fefeacfd9f63f GIT binary patch literal 6373 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 GzWYCo-9rWd literal 0 HcmV?d00001 diff --git a/lottery/双色球模拟号码-5注-20260208-001.xlsx b/lottery/双色球模拟号码-5注-20260208-001.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..4b6efb89ea18734ec4bd492b541e5aa630fc706a GIT binary patch literal 11298 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 literal 0 HcmV?d00001 diff --git a/lottery/双色球模拟号码-5注-20260210-001.xlsx b/lottery/双色球模拟号码-5注-20260210-001.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..d0514516bbd0cfde3d8e80e80fad75874d8e5249 GIT binary patch literal 11266 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 literal 0 HcmV?d00001 diff --git a/lottery/双色球模拟号码-5注-20260503-001.xlsx b/lottery/双色球模拟号码-5注-20260503-001.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..65b720d0ddb108f77ae85bcc742a9eaebe11e3f7 GIT binary patch literal 6375 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 literal 0 HcmV?d00001 diff --git a/web_console.html b/web_console.html new file mode 100644 index 0000000..d3ec63a --- /dev/null +++ b/web_console.html @@ -0,0 +1,324 @@ + + + + + + 双色球数据抓取 - 执行控制台 + + + +

+ + + + \ No newline at end of file diff --git a/web_executor.py b/web_executor.py new file mode 100644 index 0000000..329ed60 --- /dev/null +++ b/web_executor.py @@ -0,0 +1,217 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +双色球数据抓取 Web 服务 +提供 Web 界面执行抓取任务和查看实时结果 +监听 0.0.0.0,支持局域网访问 +""" + +from flask import Flask, send_from_directory, jsonify +import subprocess +import os +import json +from datetime import datetime +import threading + +app = Flask(__name__) + +# 脚本路径和输出文件 +SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__)) +SCRIPT_PATH = os.path.join(SCRIPT_DIR, "fetch_data.py") +OUTPUT_FILE = os.path.join(SCRIPT_DIR, "双色球历史数据.xlsx") +STATUS_FILE = os.path.join(SCRIPT_DIR, ".fetch_status.json") + +# 全局状态 +execution_status = { + "is_running": False, + "last_update": None, + "last_record_count": 0, + "last_error": None +} + +# 状态锁 +status_lock = threading.Lock() + + +def load_status(): + """从文件加载状态""" + global execution_status + if os.path.exists(STATUS_FILE): + try: + with open(STATUS_FILE, 'r', encoding='utf-8') as f: + execution_status = json.load(f) + except: + pass + + +def save_status(): + """保存状态到文件""" + with status_lock: + with open(STATUS_FILE, 'w', encoding='utf-8') as f: + json.dump(execution_status, f, ensure_ascii=False, indent=2) + + +@app.route('/') +def index(): + """首页 - Web 控制台""" + return send_from_directory(SCRIPT_DIR, 'web_console.html') + + +@app.route('/api/status') +def api_status(): + """获取当前执行状态""" + with status_lock: + return jsonify({ + "isRunning": execution_status.get("is_running", False), + "lastUpdate": execution_status.get("last_update"), + "recordCount": execution_status.get("last_record_count", 0), + "lastError": execution_status.get("last_error") + }) + + +@app.route('/api/execute', methods=['POST']) +def api_execute(): + """执行抓取脚本""" + global execution_status + + with status_lock: + if execution_status.get("is_running", False): + return jsonify({ + "success": False, + "error": "任务正在执行中,请稍后再试" + }), 409 + + # 启动执行线程 + def run_script(): + global execution_status + + with status_lock: + execution_status["is_running"] = True + execution_status["last_error"] = None + save_status() + + try: + print(f"[{datetime.now()}] 开始执行抓取脚本...") + + # 执行 Python 脚本 + result = subprocess.run( + ["python3", SCRIPT_PATH], + capture_output=True, + text=True, + timeout=300 + ) + + if result.returncode == 0: + # 解析输出,获取记录数 + record_count = 0 + for line in result.stdout.split('\n'): + if '共保存' in line and '条记录' in line: + try: + record_count = int(line.split('共保存')[1].split('条记录')[0].strip()) + except: + pass + elif '成功解析' in line and '条数据' in line: + try: + record_count = int(line.split('成功解析')[1].split('条数据')[0].strip()) + except: + pass + + with status_lock: + execution_status["last_update"] = datetime.now().isoformat() + execution_status["last_record_count"] = record_count + execution_status["is_running"] = False + save_status() + + print(f"✅ 执行成功,共抓取 {record_count} 条数据") + + else: + error_msg = result.stderr or f"脚本执行失败,返回码:{result.returncode}" + with status_lock: + execution_status["last_error"] = error_msg + execution_status["is_running"] = False + save_status() + print(f"❌ {error_msg}") + + except subprocess.TimeoutExpired: + error_msg = "脚本执行超时(超过 5 分钟)" + with status_lock: + execution_status["last_error"] = error_msg + execution_status["is_running"] = False + save_status() + print(f"❌ {error_msg}") + + except Exception as e: + error_msg = f"执行异常:{str(e)}" + with status_lock: + execution_status["last_error"] = error_msg + execution_status["is_running"] = False + save_status() + print(f"❌ {error_msg}") + + # 在后台线程执行 + thread = threading.Thread(target=run_script, daemon=True) + thread.start() + + return jsonify({ + "success": True, + "message": "任务已启动,正在执行中..." + }) + + +def check_dependencies(): + """检查依赖""" + missing = [] + + try: + import flask + except ImportError: + missing.append("flask") + + try: + import requests + except ImportError: + missing.append("requests") + + try: + import bs4 + except ImportError: + missing.append("beautifulsoup4") + + try: + import pandas + except ImportError: + missing.append("pandas") + + try: + import openpyxl + except ImportError: + missing.append("openpyxl") + + if missing: + print(f"❌ 缺少依赖包:{', '.join(missing)}") + print(f" 请运行:pip3 install {' '.join(missing)}") + return False + + print("✅ 所有依赖已安装") + return True + + +if __name__ == "__main__": + print("=" * 60) + print("双色球数据抓取 Web 服务") + print("=" * 60) + + if not check_dependencies(): + exit(1) + + load_status() + + print(f"\n📂 脚本路径:{SCRIPT_PATH}") + print(f"📁 输出文件:{OUTPUT_FILE}") + print(f"\n🌐 服务启动中...") + print(f" 监听地址:http://0.0.0.0:5000") + print(f" 访问方式:局域网内任意设备访问 http://<本机 IP>:5000") + print(f"\n✅ 服务就绪!") + print("=" * 60) + + app.run(host='0.0.0.0', port=5000, debug=False, threaded=True) \ No newline at end of file diff --git a/双色球历史数据.xlsx b/双色球历史数据.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..f99ab054ccca0b2b201689fcf84e1b9f57d471d5 GIT binary patch literal 12808 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 C