From 52b875a7f96ef07958e764f33965ff6209fb2aa8 Mon Sep 17 00:00:00 2001 From: kyx236 Date: Tue, 27 Jan 2026 10:26:21 +0800 Subject: [PATCH] 8 --- browser_automation.py | 73 +++++++++++++++++++++++++++++++++---------- 1 file changed, 56 insertions(+), 17 deletions(-) diff --git a/browser_automation.py b/browser_automation.py index 5822ef9..5408a2e 100644 --- a/browser_automation.py +++ b/browser_automation.py @@ -233,7 +233,7 @@ def log_url_change(page, old_url: str, action: str = None): log.warning(f"记录URL变化失败: {e}") -def acquire_lock_with_keepalive(lock, page, timeout: float = 120, check_interval: float = 2.0) -> bool: +def acquire_lock_with_keepalive(lock, page, timeout: float = 120, check_interval: float = 1.0) -> bool: """获取锁的同时保持浏览器活跃,防止等待期间浏览器连接断开 在并发模式下,多个 Worker 可能需要等待授权回调锁。 @@ -244,46 +244,85 @@ def acquire_lock_with_keepalive(lock, page, timeout: float = 120, check_interval lock: threading.Lock 对象 page: 浏览器页面对象 timeout: 最大等待时间 (秒) - check_interval: 检查间隔 (秒) + check_interval: 检查间隔 (秒),默认 1 秒 Returns: - bool: 是否成功获取锁 + bool: 是否成功获取锁(且浏览器仍可用) """ import threading start_time = time.time() - acquired = False + keepalive_counter = 0 while time.time() - start_time < timeout: # 尝试非阻塞获取锁 acquired = lock.acquire(blocking=False) if acquired: - return True + # 获取锁成功,验证浏览器是否仍然可用 + try: + _ = page.url # 测试连接 + page.run_js("1+1") # 确保 JS 引擎可用 + return True + except Exception as e: + # 浏览器已断开,释放锁让其他人重试 + log.warning(f"获取锁后发现浏览器已断开: {e}") + lock.release() + return False # 未获取到锁,保持浏览器活跃 try: - # 访问页面属性以保持连接活跃 - _ = page.url - # 可选:执行一个轻量级操作 - try: - page.run_js("1+1") # 执行简单的 JavaScript 保持活跃 - except Exception: - pass + # 每次都访问页面属性以保持连接活跃 + current_url = page.url + + # 执行轻量级 JavaScript 保持活跃 + page.run_js("1+1") + + # 每 5 次(约 5 秒)执行一次更积极的保活操作 + keepalive_counter += 1 + if keepalive_counter % 5 == 0: + # 导航到 about:blank 再返回,强制保持连接 + try: + page.run_js("window.focus()") # 尝试激活窗口 + except Exception: + pass + except Exception as e: - # 浏览器连接可能已断开 + # 浏览器连接已断开 log.warning(f"保持浏览器活跃时出错: {e}") return False - # 等待一小段时间后重试 + # 等待一小段时间后重试(使用较短间隔) time.sleep(check_interval) # 超时,尝试最后一次阻塞获取 (短暂) acquired = lock.acquire(blocking=True, timeout=0.1) - return acquired + if acquired: + # 验证浏览器 + try: + _ = page.url + return True + except Exception: + lock.release() + return False + return False -def cleanup_chrome_processes(): - """清理残留的 Chrome 进程 (跨平台支持)""" +def cleanup_chrome_processes(force: bool = False): + """清理残留的 Chrome 进程 (跨平台支持) + + Args: + force: 是否强制清理。在并发模式下默认跳过,除非 force=True + """ + # 检查是否在并发模式下运行,如果是则跳过清理(避免杀死其他 Worker 的浏览器) + if not force: + try: + from config import CONCURRENT_ENABLED + if CONCURRENT_ENABLED: + # 并发模式下跳过全局清理,避免影响其他 Worker + return + except ImportError: + pass + try: if platform.system() == "Windows": # Windows: 使用 taskkill 清理 chromedriver 和 chrome