132 lines
3.9 KiB
Python
132 lines
3.9 KiB
Python
"""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
|