#!/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)