#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ 浏览器自动下载安装模块 检测本地是否有Playwright浏览器,如果没有则自动下载安装 """ import os import sys import shutil import subprocess from pathlib import Path # 设置浏览器安装路径(支持Docker和本地环境) # Docker环境: PLAYWRIGHT_BROWSERS_PATH环境变量已设置为 /ms-playwright # 本地环境: 使用Playwright默认路径 if 'PLAYWRIGHT_BROWSERS_PATH' in os.environ: BROWSERS_PATH = os.environ['PLAYWRIGHT_BROWSERS_PATH'] else: # Windows: %USERPROFILE%\AppData\Local\ms-playwright # Linux: ~/.cache/ms-playwright if sys.platform == 'win32': BROWSERS_PATH = str(Path.home() / "AppData" / "Local" / "ms-playwright") else: BROWSERS_PATH = str(Path.home() / ".cache" / "ms-playwright") os.environ["PLAYWRIGHT_BROWSERS_PATH"] = BROWSERS_PATH class BrowserInstaller: """浏览器安装器""" def __init__(self, log_callback=None): """ 初始化安装器 Args: log_callback: 日志回调函数 """ self.log_callback = log_callback def log(self, message): """输出日志""" if self.log_callback: self.log_callback(message) else: try: print(message) except UnicodeEncodeError: # 如果打印Unicode字符失败,替换特殊字符 safe_message = message.replace('✓', '[OK]').replace('✗', '[X]') print(safe_message) def check_playwright_installed(self): """检查Playwright是否已安装""" try: import playwright self.log("✓ Playwright已安装") return True except ImportError: self.log("✗ Playwright未安装") return False def check_chromium_installed(self): """检查Chromium浏览器是否已安装""" try: from playwright.sync_api import sync_playwright # 尝试启动浏览器检查是否可用 with sync_playwright() as p: try: # 使用超时快速检查 browser = p.chromium.launch(headless=True, timeout=5000) browser.close() self.log("✓ Chromium浏览器已安装且可用") return True except Exception as e: error_msg = str(e) self.log(f"✗ Chromium浏览器不可用: {error_msg}") # 检查是否是路径不存在的错误 if "Executable doesn't exist" in error_msg: self.log("检测到浏览器文件缺失,需要重新安装") return False except Exception as e: self.log(f"✗ 检查浏览器时出错: {str(e)}") return False def install_chromium(self): """安装Chromium浏览器""" try: self.log("正在安装 Chromium 浏览器...") # 查找 playwright 可执行文件 playwright_cli = None possible_paths = [ os.path.join(os.path.dirname(sys.executable), "Scripts", "playwright.exe"), os.path.join(os.path.dirname(sys.executable), "playwright.exe"), os.path.join(os.path.dirname(sys.executable), "Scripts", "playwright"), os.path.join(os.path.dirname(sys.executable), "playwright"), "playwright", # 系统PATH中 ] for path in possible_paths: if os.path.exists(path) or shutil.which(path): playwright_cli = path break # 如果找到了 playwright CLI,直接调用 if playwright_cli: self.log(f"使用 Playwright CLI: {playwright_cli}") result = subprocess.run( [playwright_cli, "install", "chromium"], capture_output=True, text=True, timeout=300 ) else: # 检测是否是 Nuitka 编译的程序 is_nuitka = hasattr(sys, 'frozen') or '__compiled__' in globals() if is_nuitka: self.log("检测到 Nuitka 编译环境") self.log("✗ 无法找到 playwright CLI 工具") self.log("请手动运行: playwright install chromium") return False else: # 使用 python -m result = subprocess.run( [sys.executable, "-m", "playwright", "install", "chromium"], capture_output=True, text=True, timeout=300 ) if result.returncode == 0: self.log("✓ Chromium浏览器安装成功") return True else: self.log(f"✗ 浏览器安装失败: {result.stderr}") return False except subprocess.TimeoutExpired: self.log("✗ 浏览器安装超时") return False except Exception as e: self.log(f"✗ 浏览器安装出错: {str(e)}") return False def auto_install(self): """ 自动检测并安装所需环境 Returns: 是否成功安装或已安装 """ self.log("=" * 60) self.log("检查浏览器环境...") self.log("=" * 60) # 1. 检查Playwright是否安装 if not self.check_playwright_installed(): self.log("✗ Playwright未安装,无法继续") self.log("请确保程序包含 Playwright 库") return False # 2. 检查Chromium浏览器是否安装 if not self.check_chromium_installed(): self.log("\n未检测到Chromium浏览器,开始自动安装...") # 安装浏览器 if not self.install_chromium(): self.log("✗ 浏览器安装失败") self.log("\n您可以尝试以下方法:") self.log("1. 手动执行: playwright install chromium") self.log("2. 检查网络连接后重试") self.log("3. 检查防火墙设置") return False self.log("\n" + "=" * 60) self.log("✓ 浏览器环境检查完成,一切就绪!") self.log("=" * 60 + "\n") return True def check_and_install_browser(log_callback=None): """ 便捷函数:检查并安装浏览器 Args: log_callback: 日志回调函数 Returns: 是否成功 """ installer = BrowserInstaller(log_callback) return installer.auto_install() # 测试代码 if __name__ == "__main__": print("浏览器自动安装工具") print("=" * 60) installer = BrowserInstaller() success = installer.auto_install() if success: print("\n✓ 安装成功!您现在可以运行主程序了。") else: print("\n✗ 安装失败,请查看上方错误信息。") print("=" * 60)