This commit is contained in:
2026-03-26 15:04:59 +08:00
commit e0af97ac7f
65 changed files with 7366 additions and 0 deletions

View File

@@ -0,0 +1,121 @@
import threading
import time
import os
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from webdriver_manager.chrome import ChromeDriverManager
from app.utils.logger import log
class BrowserManager:
"""浏览器管理器提供共享的Chrome浏览器实例"""
_instance = None
_lock = threading.Lock()
_driver = None
_driver_path = None
_last_activity = 0
_max_idle_time = 1800 # 最大空闲时间默认30分钟
def __new__(cls, *args, **kwargs):
"""单例模式实现"""
if cls._instance is None:
with cls._lock:
if cls._instance is None:
cls._instance = super(BrowserManager, cls).__new__(cls)
cls._instance._init_driver_path()
cls._instance._start_idle_monitor()
return cls._instance
def _init_driver_path(self):
"""初始化ChromeDriver路径"""
try:
self._driver_path = ChromeDriverManager().install()
log.info(f"ChromeDriver已安装: {self._driver_path}")
except Exception as e:
log.error(f"ChromeDriver安装失败: {str(e)}")
raise
def _start_idle_monitor(self):
"""启动空闲监控线程"""
def monitor():
while True:
time.sleep(60) # 每分钟检查一次
try:
with self._lock:
if self._driver is not None:
current_time = time.time()
if current_time - self._last_activity > self._max_idle_time:
log.info(f"浏览器空闲超过{self._max_idle_time}秒,释放资源")
self._quit_driver()
except Exception as e:
log.error(f"浏览器监控线程异常: {str(e)}")
monitor_thread = threading.Thread(target=monitor, daemon=True)
monitor_thread.start()
log.info("浏览器空闲监控线程已启动")
def get_driver(self):
"""获取Chrome浏览器实例"""
with self._lock:
self._last_activity = time.time()
if self._driver is None:
self._create_driver()
return self._driver
def _create_driver(self):
"""创建新的Chrome浏览器实例"""
log.info("创建新的Chrome浏览器实例")
options = webdriver.ChromeOptions()
# 基本配置(无头模式)
options.add_argument("--headless")
options.add_argument("--disable-gpu")
options.add_argument("--no-sandbox")
# 内存优化配置
options.add_argument("--disable-dev-shm-usage")
options.add_argument("--disable-extensions")
options.add_argument("--disable-application-cache")
options.add_argument("--js-flags=--expose-gc")
options.add_argument("--memory-pressure-off")
options.add_argument("--disable-default-apps")
# 日志级别
options.add_argument("--log-level=3")
self._driver = webdriver.Chrome(
service=Service(self._driver_path),
options=options
)
self._driver.set_page_load_timeout(30)
def _quit_driver(self):
"""关闭浏览器实例"""
if self._driver:
try:
self._driver.quit()
log.info("浏览器实例已关闭")
except Exception as e:
log.error(f"关闭浏览器实例出错: {str(e)}")
finally:
self._driver = None
def release_driver(self):
"""使用完毕后标记为活动状态"""
with self._lock:
self._last_activity = time.time()
def get_page_content(self, url, wait_time=5):
"""获取指定URL的页面内容并自动处理浏览器"""
driver = self.get_driver()
try:
driver.get(url)
time.sleep(wait_time) # 等待页面加载
page_source = driver.page_source
self.release_driver()
return page_source, driver
except Exception as e:
log.error(f"获取页面内容失败: {str(e)}")
self.release_driver()
raise
def shutdown(self):
"""关闭浏览器管理器"""
with self._lock:
self._quit_driver()