"""Playwright 浏览器引导:浏览器固定装在应用目录 playwright-browsers。""" from __future__ import annotations import os import subprocess import sys from pathlib import Path from app_paths import app_root, is_frozen ROOT = app_root() def browsers_dir() -> Path: return ROOT / "playwright-browsers" def scrub_playwright_env() -> Path: target = browsers_dir() target.mkdir(parents=True, exist_ok=True) for key in list(os.environ.keys()): if key.upper().startswith("PLAYWRIGHT"): os.environ.pop(key, None) os.environ["PLAYWRIGHT_BROWSERS_PATH"] = str(target.resolve()) return target def find_chrome_exe(root: Path | None = None) -> Path | None: base = root or browsers_dir() if not base.is_dir(): return None for folder in sorted(base.glob("chromium-*"), reverse=True): for sub in ("chrome-win64", "chrome-win"): exe = folder / sub / "chrome.exe" if exe.is_file(): return exe.resolve() return None def find_system_chrome() -> Path | None: candidates = [ Path(os.environ.get("PROGRAMFILES", r"C:\Program Files")) / "Google/Chrome/Application/chrome.exe", Path(os.environ.get("PROGRAMFILES(X86)", r"C:\Program Files (x86)")) / "Google/Chrome/Application/chrome.exe", Path(os.environ.get("LOCALAPPDATA", "")) / "Google/Chrome/Application/chrome.exe", ] for path in candidates: if path.is_file(): return path.resolve() return None def python_exe() -> str: if is_frozen(): return str(Path(sys.executable)) for rel in (".venv/Scripts/python.exe", "backend/.venv/Scripts/python.exe"): p = ROOT / rel.replace("/", os.sep) if p.is_file(): return str(p) return str(Path(sys.executable)) def install_chromium(target: Path) -> None: print("正在安装 Playwright Chromium(约 130MB)…") print(f" {target.resolve()}\n") env = os.environ.copy() env["PLAYWRIGHT_BROWSERS_PATH"] = str(target.resolve()) if is_frozen(): from playwright._impl._driver import compute_driver_executable, get_driver_env node, cli = compute_driver_executable() env.update(get_driver_env()) env["PLAYWRIGHT_BROWSERS_PATH"] = str(target.resolve()) proc = subprocess.run([node, cli, "install", "chromium"], env=env) else: proc = subprocess.run( [python_exe(), "-m", "playwright", "install", "chromium"], env=env, cwd=str(ROOT), ) if proc.returncode != 0: hint = "抖音IM凭证采集器.exe --install-browser" if is_frozen() else f"{python_exe()} -m playwright install chromium" raise RuntimeError(f"Chromium 安装失败,请检查网络。\n手动执行:{hint}") def resolve_chrome_exe() -> Path: target = scrub_playwright_env() exe = find_chrome_exe(target) if exe: return exe local = Path(os.environ.get("LOCALAPPDATA", "")) / "ms-playwright" exe = find_chrome_exe(local) if exe: print(f"发现已有 Chromium:{exe}") return exe install_chromium(target) exe = find_chrome_exe(target) if exe: return exe system = find_system_chrome() if system: print(f"将使用本机 Google Chrome:{system}") return system if is_frozen(): raise RuntimeError("找不到 chrome.exe,请运行「修复浏览器.bat」或 exe --install-browser") raise RuntimeError(f"找不到 chrome.exe,请运行:{ROOT / '修复Playwright浏览器.bat'}") def ensure_browser_ready() -> Path: exe = resolve_chrome_exe() print(f"浏览器就绪:{exe}") return exe def browser_launch_kwargs() -> dict: scrub_playwright_env() exe = resolve_chrome_exe() print(f"启动浏览器:{exe}") return { "executable_path": str(exe), "env": {"PLAYWRIGHT_BROWSERS_PATH": str(browsers_dir().resolve())}, } fix_playwright_env = scrub_playwright_env