# coding: utf-8 """ Selenium 驱动工厂 提供统一的浏览器驱动创建接口 """ import logging import sys from typing import Optional from selenium import webdriver from selenium.webdriver.chrome.options import Options from selenium.webdriver.chrome.service import Service logger = logging.getLogger("damai.driver") def create_driver( driver_path: str, mobile_emulation: bool = True, headless: bool = False, disable_images: bool = True, page_load_strategy: str = "eager", ) -> webdriver.Chrome: """ 创建配置好的 Chrome 驱动 Args: driver_path: chromedriver 可执行文件路径 mobile_emulation: 是否模拟移动设备 headless: 是否无头模式 disable_images: 是否禁用图片加载 page_load_strategy: 页面加载策略 (normal/eager/none) Returns: 配置好的 Chrome WebDriver 实例 """ options = Options() # 移动端模拟 if mobile_emulation: options.add_experimental_option( "mobileEmulation", {"deviceName": "Nexus 6"} ) # 反检测 options.add_argument("--disable-blink-features=AutomationControlled") options.add_experimental_option("excludeSwitches", ["enable-automation"]) options.add_experimental_option("useAutomationExtension", False) # 性能优化 if disable_images: prefs = { "profile.managed_default_content_settings.images": 2, "profile.managed_default_content_settings.fonts": 2, } options.add_experimental_option("prefs", prefs) # 页面加载策略 options.page_load_strategy = page_load_strategy # 无头模式 if headless: options.add_argument("--headless=new") # Linux 环境 if sys.platform != "win32": options.add_argument("--no-sandbox") options.add_argument("--disable-dev-shm-usage") options.add_argument("--disable-gpu") service = Service(executable_path=driver_path) driver = webdriver.Chrome(service=service, options=options) # 隐藏 webdriver 痕迹 driver.execute_cdp_cmd( "Page.addScriptToEvaluateOnNewDocument", { "source": """ Object.defineProperty(navigator, 'webdriver', {get: () => undefined}); window.navigator.chrome = {runtime: {}}; Object.defineProperty(navigator, 'plugins', { get: () => [1, 2, 3, 4, 5], }); Object.defineProperty(navigator, 'languages', { get: () => ['zh-CN', 'en-US', 'en'], }); """ }, ) logger.info(f"Chrome 驱动已创建 | mobile={mobile_emulation} headless={headless}") return driver