This commit is contained in:
2026-01-18 05:38:14 +08:00
parent e510c568b4
commit 7e92e12c79
5 changed files with 438 additions and 132 deletions

View File

@@ -35,6 +35,27 @@ from s2a_service import (
from logger import log
# ==================== 停止检查 ====================
class ShutdownRequested(Exception):
"""停止请求异常 - 用于中断浏览器操作"""
pass
def check_shutdown():
"""检查是否收到停止请求,如果是则抛出异常"""
try:
import run
if run._shutdown_requested:
log.warning("检测到停止请求,中断当前操作...")
raise ShutdownRequested("用户请求停止")
except ImportError:
pass
except ShutdownRequested:
raise
except Exception:
pass
# ==================== 浏览器配置常量 ====================
BROWSER_MAX_RETRIES = 3 # 浏览器启动最大重试次数
BROWSER_RETRY_DELAY = 2 # 重试间隔 (秒)
@@ -198,24 +219,49 @@ def cleanup_chrome_processes():
"""清理残留的 Chrome 进程 (跨平台支持)"""
try:
if platform.system() == "Windows":
# Windows: 使用 tasklist 和 taskkill
result = subprocess.run(
['tasklist', '/FI', 'IMAGENAME eq chrome.exe', '/FO', 'CSV'],
capture_output=True, text=True, timeout=5
)
if 'chrome.exe' in result.stdout:
# Windows: 使用 taskkill 清理 chromedriver 和 chrome
try:
subprocess.run(
['taskkill', '/F', '/IM', 'chromedriver.exe'],
capture_output=True, timeout=5
)
log.step("已清理 chromedriver 残留进程")
except Exception:
pass
# 清理无头模式的 chrome 进程 (带 --headless 参数的)
try:
result = subprocess.run(
['wmic', 'process', 'where', "name='chrome.exe' and commandline like '%--headless%'", 'get', 'processid'],
capture_output=True, text=True, timeout=5
)
for line in result.stdout.strip().split('\n'):
pid = line.strip()
if pid.isdigit():
subprocess.run(['taskkill', '/F', '/PID', pid], capture_output=True, timeout=5)
except Exception:
pass
log.step("已清理 Chrome 残留进程")
else:
# Linux/Mac: 使用 pkill
subprocess.run(
['pkill', '-f', 'chromedriver'],
capture_output=True, timeout=5
)
try:
subprocess.run(
['pkill', '-f', 'chromedriver'],
capture_output=True, timeout=5
)
except Exception:
pass
# 清理无头模式的 chrome 进程
try:
subprocess.run(
['pkill', '-f', 'chrome.*--headless'],
capture_output=True, timeout=5
)
except Exception:
pass
log.step("已清理 Chrome 残留进程")
except Exception:
pass # 静默处理,不影响主流程
@@ -484,6 +530,9 @@ class BrowserRetryContext:
if not self._should_continue:
break
# 检查停止请求
check_shutdown()
self.current_attempt = attempt
# 非首次尝试时的清理和等待
@@ -495,8 +544,12 @@ class BrowserRetryContext:
# 初始化浏览器
try:
check_shutdown() # 再次检查
self.page = init_browser()
yield attempt
except ShutdownRequested:
self._should_continue = False
raise
except Exception as e:
log.error(f"浏览器初始化失败: {e}")
if attempt >= self.max_retries - 1:
@@ -504,6 +557,11 @@ class BrowserRetryContext:
def handle_error(self, error: Exception):
"""处理错误,决定是否继续重试"""
# 如果是停止请求,直接停止
if isinstance(error, ShutdownRequested):
self._should_continue = False
return
log.error(f"流程异常: {error}")
if self.current_attempt >= self.max_retries - 1:
self._should_continue = False
@@ -550,6 +608,9 @@ def wait_for_page_stable(page, timeout: int = 10, check_interval: float = 0.5) -
stable_count = 0
while time.time() - start_time < timeout:
# 检查停止请求
check_shutdown()
try:
# 检查浏览器标签页是否还在加载favicon 旋转动画)
ready_state = page.run_js('return document.readyState', timeout=2)
@@ -567,6 +628,8 @@ def wait_for_page_stable(page, timeout: int = 10, check_interval: float = 0.5) -
stable_count = 0
last_html_len = current_len
time.sleep(check_interval)
except ShutdownRequested:
raise
except Exception:
time.sleep(check_interval)
@@ -626,11 +689,16 @@ def wait_for_element(page, selector: str, timeout: int = 10, visible: bool = Tru
start_time = time.time()
while time.time() - start_time < timeout:
# 检查停止请求
check_shutdown()
try:
element = page.ele(selector, timeout=1)
if element:
if not visible or (element.states.is_displayed if hasattr(element, 'states') else True):
return element
except ShutdownRequested:
raise
except Exception:
pass
time.sleep(0.3)
@@ -653,11 +721,16 @@ def wait_for_url_change(page, old_url: str, timeout: int = 15, contains: str = N
start_time = time.time()
while time.time() - start_time < timeout:
# 检查停止请求
check_shutdown()
try:
current_url = page.url
if current_url != old_url:
if contains is None or contains in current_url:
return True
except ShutdownRequested:
raise
except Exception:
pass
time.sleep(0.5)