# -*- coding: utf-8 -*- """常驻:确保本机有一个可用的独立 Chrome 实例(9223,固定 profile ⇒ 登录态保留)。 为什么必须常驻:本机沙箱在父进程退出时连带杀子进程 ⇒ 会话/工具调用里起的浏览器一返回就死。 为什么放工作区根而不是 tmp/:tmp/ 会被清理,脚本一没计划任务就静默失效。 形态:幂等 —— 端口已在听 ⇒ 立刻退出(⛔ 不叠加第二个实例、不抢同一个 profile)。 由计划任务 `bh-chrome-keepalive` 每 5 分钟触发一次(MultipleInstances=IgnoreNew), 所以"活着的那份"负责守端口,任务只是兜它挂掉时重新拉起。 ⛔ 不附着用户日常 Chrome(那是 9222,会弹「允许远程调试?」动到用户浏览器)。 """ import os, subprocess, sys, time, socket, io for k in ["HTTP_PROXY", "HTTPS_PROXY", "http_proxy", "https_proxy"]: os.environ.pop(k, None) os.environ["NO_PROXY"] = "127.0.0.1,localhost" WS = r"E:/ProgramData/AIProject/contentm_agent" CHROME = r"C:\Program Files\Google\Chrome\Application\chrome.exe" PROFILE = r"E:/ProgramData/.workbuddy/tmp/bu-chatgpt-profile" PORT = 9223 LOG = os.path.join(WS, "tmp", "_bh_chrome.log") def log(msg): try: os.makedirs(os.path.dirname(LOG), exist_ok=True) with io.open(LOG, "a", encoding="utf-8") as f: f.write("[%s] %s\n" % (time.strftime("%m-%d %H:%M:%S"), msg)) except Exception: pass def up(): try: s = socket.create_connection(("127.0.0.1", PORT), 1) s.close() return True except Exception: return False def launch(): return subprocess.Popen( [CHROME, "--remote-debugging-port=%d" % PORT, "--user-data-dir=%s" % PROFILE, "--no-first-run", "--no-default-browser-check", "about:blank"], creationflags=0x00000008 | 0x08000000 | 0x00000200, # DETACHED | NO_WINDOW | NEW_PROCESS_GROUP ) # ---- 幂等前置:端口已在听 ⇒ 什么都不做 ---- if up(): log("port %d already listening ⇒ exit (idempotent)" % PORT) sys.exit(0) p = launch() log("launched pid=%s" % p.pid) while True: time.sleep(5) if p.poll() is not None: log("chrome exited rc=%s ⇒ relaunch" % p.returncode) p = launch() log("relaunched pid=%s" % p.pid) if not up(): # ⚠️ 这里只记日志:僵死态(端口不应答、进程不死)按规则由人/会话判定后重启实例, # ⛔ 脚本不做自动重启,免得把"正在被人排查的现场"清掉。 log("port %d not answering (pid alive=%s)" % (PORT, p.poll() is None))