Selenium反检测实战:从指纹原理到高匿框架构建
1. 项目概述当Selenium不再“隐形”如果你用过Selenium做自动化测试或者数据采集大概率遇到过这种情况脚本运行得好好的突然就被目标网站拦截了弹出一个验证码或者干脆告诉你“检测到自动化工具访问”。那一刻的感觉就像穿着夜行衣潜行却突然被聚光灯照了个正着。这背后的“聚光灯”就是现代网站广泛采用的浏览器指纹检测技术。它们不再仅仅依赖简单的navigator.webdriver属性而是构建了一套复杂的“体检”系统对你的浏览器环境进行全方位扫描。我们今天要聊的“Selenium反检测实战”核心目标就是让我们的自动化脚本从“穿着制服的士兵”变回“融入人群的便衣”实现真正的“隐身”访问。这不仅仅是改几个参数那么简单它涉及对浏览器底层运行原理的理解、对检测逻辑的逆向以及驱动层面的深度定制。无论是为了更稳定地进行UI自动化测试还是为了在合规前提下高效获取公开数据掌握这套“隐身术”都至关重要。2. 浏览器指纹检测原理深度拆解要反检测首先得知道别人是怎么检测你的。现代网站的检测系统就像一个精明的海关官员它不会只看你的护照User-Agent还会检查你的行李浏览器特性、询问你的行程行为模式。我们把它们统称为“浏览器指纹”。2.1 核心指纹维度与检测点网站检测自动化工具主要从以下几个层面入手我将其归纳为“三层检测模型”第一层显式属性最容易暴露这是最基础的检测点Selenium默认会留下明显的“自动化标记”。navigator.webdriver: 这是最著名的标志。在普通浏览器中这个属性是undefined或false而在Selenium驱动的浏览器中它通常是true。早期反检测几乎都从这里入手。window.chrome对象下的运行时属性对于ChromeSelenium会注入一些特有的对象和方法例如cdc_开头的变量。检测脚本会遍历window对象寻找这些“异物”。document.documentElement的属性某些情况下Selenium会修改DOM根元素的一些内部属性。第二层隐性特征与不一致性更隐蔽即使你抹掉了显式标记浏览器运行时的一些特征和行为也可能“出卖”你。插件列表 (navigator.plugins): 自动化浏览器通常插件列表为空或与真实用户差异巨大。真实用户的Chrome很可能装有AdBlock、Grammarly等。语言与屏幕分辨率 (navigator.language,screen.width/height): 脚本可能使用默认值而真实用户环境多样。WebGL渲染器与Canvas指纹: 网站通过让浏览器绘制一个隐藏的Canvas图像然后计算其哈希值。由于硬件、驱动、浏览器版本的不同这个哈希值几乎是唯一的。自动化环境下的图形渲染库可能与真实环境有细微差别。字体列表 (document.fonts): 通过检测已安装的字体来生成指纹。服务器端字体列表通常与客户端不同。音频上下文指纹: 类似于Canvas利用音频信号处理的微小差异生成指纹。第三层行为模式终极判断这是最高级的检测模拟难度最大。鼠标移动轨迹: 真人鼠标移动带有随机加速度曲线和微小的不规则抖动而自动化工具的移动往往是完美的直线或简单的贝塞尔曲线。点击位置与精度: 程序化点击总是在元素的精确中心而真人点击会有偏移。打字速度与节奏: 自动输入的速度要么是恒定的极快要么带有非人类的节奏。页面停留与交互节奏: 脚本执行任务的速度和顺序过于规律缺乏真人浏览时的随机思考和停顿。注意许多检测系统采用“打分制”。单一特征匹配不会立即封禁但多个特征同时指向自动化工具时分数累积超过阈值就会触发验证或拦截。因此我们的反检测策略必须是系统性的。2.2 网站如何实施检测了解了指纹维度我们再看网站端如何利用它们。检测代码通常以一段混淆的JavaScript形式在页面加载早期或关键交互节点执行。它收集上述指纹信息可能在本地进行计算打分也可能将指纹数据发送到后端进行更复杂的分析和比对。常见的开源检测库如puppeteer-extra-plugin-stealth的对抗目标就反映了这些检测点的普遍性。3. 反检测策略全景与工具选型面对多层次检测我们的反检测策略也必须是立体的。我将其分为四个层级从易到难从通用到定制。层级一驱动选项与参数伪装基础必备这是通过SeleniumChromeOptions或FirefoxOptions就能实现的初级隐身。主要目标是消除第一层的“显式属性”。核心参数from selenium import webdriver from selenium.webdriver.chrome.options import Options options Options() # 1. 禁用自动化控制标志关键 options.add_experimental_option(excludeSwitches, [enable-automation]) options.add_experimental_option(useAutomationExtension, False) # 2. 修改navigator.webdriver属性旧版Chrome驱动方式新版需结合CDP # 通过执行CDP命令来覆盖属性 driver.execute_cdp_cmd(Page.addScriptToEvaluateOnNewDocument, { source: Object.defineProperty(navigator, webdriver, { get: () undefined }); }) # 3. 使用非默认用户数据目录避免“空白”环境 options.add_argument(r--user-data-dirC:\Users\YourName\ChromeProfile) # 或者添加一个常见的用户代理字符串 options.add_argument(--user-agentMozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 ...) driver webdriver.Chrome(optionsoptions)为什么有效excludeSwitches和useAutomationExtension直接移除了浏览器顶部“正受到自动测试软件控制”的提示并清除了一些内部标志。CDP命令则在页面任何脚本执行前就重写了关键的navigator.webdriver属性使其返回undefined。层级二使用反检测浏览器驱动省心之选手动配置所有参数繁琐且可能遗漏。社区出现了封装好的解决方案。undetected-chromedriver (uc): 这是目前Python生态中最流行、效果最好的反检测驱动库之一。它自动处理驱动匹配、参数注入、CDP命令执行等繁琐步骤。import undetected_chromedriver as uc driver uc.Chrome() driver.get(https://nowsecure.nl) # 一个著名的反自动化检测测试网站优势开箱即用持续更新对抗最新检测手段社区活跃。劣势作为黑盒对其内部实现了解有限遇到极端定制化需求时调整不便。Selenium Stealth 插件 (Python版): 另一个选择需要配合pyppeteer或selenium使用通过注入一系列脚本修改浏览器环境。选型建议对于大多数常规反检测场景undetected-chromedriver是首选。它能解决80%以上的检测问题且节省大量调试时间。层级三指纹环境深度模拟进阶挑战当目标网站采用第二层隐性特征检测时我们需要模拟更真实的浏览器环境。模拟插件通过CDP命令在navigator.plugins和navigator.mimeTypes中注入常见的插件信息如Chrome PDF Viewer, Widevine Content Decryption Module等。模拟屏幕、语言、时区通过options.add_argument设置--window-size,--lang等参数。Canvas指纹欺骗这非常困难。一种思路是使用chrome.debugger协议或修改浏览器启动参数加载一个能够Hook WebGL和Canvas API的扩展但稳定性差。更实际的做法是使用真实的、经过人为使用过的浏览器用户数据目录--user-data-dir。因为这个目录下的浏览器已经拥有了真实的Canvas、WebGL、字体等指纹。这是绕过高级指纹检测最有效的方法之一。实操心得准备多个“真人”浏览器Profile轮换使用可以进一步降低风险。你可以手动创建几个Chrome用户用它们正常上网一段时间产生真实的浏览历史、缓存和指纹然后将这些Profile目录作为脚本的启动参数。层级四行为模式拟人化终极目标对抗行为检测没有银弹核心是“随机化”和“人性化”。鼠标移动库使用如PyAutoGUI、pynput或selenium-action链进行更复杂的鼠标移动模拟加入随机偏移和曲线。from selenium.webdriver.common.action_chains import ActionChains import random, time element driver.find_element(...) actions ActionChains(driver) # 先移动到元素附近的一个随机点 actions.move_by_offset(random.randint(-50, 50), random.randint(-50, 50)) actions.pause(random.uniform(0.1, 0.5)) # 再缓慢移动到元素中心 actions.move_to_element(element) actions.pause(random.uniform(0.2, 0.8)) # 模拟犹豫 actions.click() actions.perform()输入模拟不要用element.send_keys(“text”)一气呵成。拆分成单个字符并加入随机延迟。def human_type(element, text): for char in text: element.send_keys(char) time.sleep(random.uniform(0.05, 0.2)) # 随机延迟模拟打字节奏浏览节奏在页面间跳转或执行操作序列时加入随机等待时间模拟阅读和思考。使用time.sleep(random.uniform(1, 5))而非固定延迟。4. 定制化驱动与CDP协议深度应用当现成工具无法满足需求或者你需要对反检测有绝对控制力时定制化驱动和深入使用Chrome DevTools Protocol (CDP) 是必经之路。4.1 理解CDP直接与浏览器内核对话Selenium WebDriver协议是一个W3C标准它为了兼容多种浏览器抽象层级较高。而CDP是Chrome/Chromium内核提供的原生调试协议功能更底层、更强大。Selenium 4之后提供了直接执行CDP命令的接口driver.execute_cdp_cmd这为我们深度修改浏览器环境打开了大门。4.2 关键CDP命令实战以下是一些在反检测中至关重要的CDP命令应用1. 在文档加载前执行脚本核心中的核心这是覆盖JavaScript环境属性的最佳时机确保在网站检测代码运行前我们的伪装已经就位。# 覆盖 webdriver 属性 driver.execute_cdp_cmd(Page.addScriptToEvaluateOnNewDocument, { source: Object.defineProperty(navigator, webdriver, { get: () undefined }); // 覆盖 chrome 运行时属性 window.chrome { runtime: {}, // ... 其他需要模拟的属性 }; // 覆盖 permissions API const originalQuery window.navigator.permissions.query; window.navigator.permissions.query (parameters) ( parameters.name notifications ? Promise.resolve({ state: Notification.permission }) : originalQuery(parameters) ); }) # 更全面的脚本可以模拟 plugins, languages 等 plugin_script Object.defineProperty(navigator, plugins, { get: () [ {0: {type: application/pdf, suffixes: pdf, description: Portable Document Format}, ...}, // 模拟多个插件 ] }); Object.defineProperty(navigator, languages, { get: () [zh-CN, zh, en-US, en] }); driver.execute_cdp_cmd(Page.addScriptToEvaluateOnNewDocument, {source: plugin_script})2. 修改网络请求头一些检测会分析请求头中的Sec-CH-UA用户代理客户端提示等字段。CDP可以修改这些。driver.execute_cdp_cmd(Network.setUserAgentOverride, { userAgent: driver.execute_script(return navigator.userAgent), platform: Win32, userAgentMetadata: { brands: [ {brand: Not A;Brand, version: 99}, {brand: Chromium, version: 96}, {brand: Google Chrome, version: 96} ], fullVersion: 96.0.4664.110, platform: Windows, platformVersion: 10.0.0, architecture: x86, model: } })3. 启用网络域监听用于高级分析如果你想分析浏览器发送了哪些指纹数据可以启用网络监听。driver.execute_cdp_cmd(Network.enable, {}) # 可以添加事件监听器来捕获请求/响应 # driver.add_listener(...) 具体实现较复杂需配合异步4.3 编译定制Chromium驱动这是终极手段适用于需要彻底移除Selenium所有痕迹或集成特定补丁的场景。为什么需要定制即使通过CDP覆盖了属性一些极端的检测可能通过更低层级的API或内存特征来识别。修改Chromium源码可以从根源上移除与自动化测试相关的代码标识。大致流程获取源码从Chromium官方仓库checkout特定版本的代码。定位关键文件搜索与cdc_、automation、webdriver等关键词相关的字符串和变量定义。通常位于//chrome/test/、//third_party/blink/等目录。修改并编译注释或修改相关代码然后按照Chromium庞大的编译指南进行编译。这个过程对机器性能需要数十GB内存和数百GB硬盘和网络要求极高可能需要数小时甚至更长时间。替换驱动使用编译出的chromedriver替换官方版本。实操心得除非面对国家级别的反爬或进行安全研究否则不建议个人开发者走这条路。维护成本极高且随着Chromium版本快速迭代每次升级都需要重新编译。社区已有一些开源项目维护了修改版的chromedriver例如某些“stealth”版本可以优先尝试这些现成方案。5. 实战构建一个高匿Selenium爬虫框架理论说再多不如动手搭一个。下面我将构建一个集成了上述多种策略的、模块化的Selenium爬虫框架。这个框架的目标是可配置、可扩展、易维护。5.1 框架结构设计selenium_stealth_framework/ ├── core/ │ ├── driver_factory.py # 驱动创建工厂集成uc、CDP脚本等 │ └── behavior_simulator.py # 行为模拟类鼠标、输入、等待 ├── fingerprints/ │ ├── plugins.json # 模拟的插件列表数据 │ └── scripts.js # 要注入的CDP脚本合集 ├── profiles/ # 存放多个真人浏览器Profile目录 │ ├── profile_1/ │ └── profile_2/ ├── utils/ │ ├── config_loader.py # 配置文件读取 │ └── logger.py # 日志记录 └── main.py # 主程序入口5.2 核心模块实现驱动工厂driver_factory.py是核心它根据配置决定创建哪种类型的“隐身”驱动。import random import json from pathlib import Path from selenium import webdriver from selenium.webdriver.chrome.options import Options from selenium.webdriver.chrome.service import Service import undetected_chromedriver as uc class StealthDriverFactory: def __init__(self, config): self.config config self.fingerprint_scripts self._load_fingerprint_scripts() def _load_fingerprint_scripts(self): 加载预定义的指纹伪装JS脚本 script_path Path(__file__).parent.parent / fingerprints / scripts.js with open(script_path, r, encodingutf-8) as f: return f.read() def create_driver(self, modebalanced, profile_dirNone): 创建驱动 :param mode: aggressive (最大隐身可能慢), balanced (平衡), simple (基础) :param profile_dir: 指定使用的浏览器用户数据目录路径 :return: WebDriver 实例 if self.config.get(use_undetected_chromedriver, True) and mode ! aggressive: # 使用 undetected-chromedriver 作为基础 return self._create_uc_driver(mode, profile_dir) else: # 使用原生Selenium 深度定制 return self._create_custom_selenium_driver(mode, profile_dir) def _create_uc_driver(self, mode, profile_dir): 使用 undetected-chromedriver 创建驱动 options uc.ChromeOptions() # 基础隐身参数 options.add_argument(--disable-blink-featuresAutomationControlled) options.add_argument(--disable-dev-shm-usage) options.add_argument(--no-sandbox) # 仅在容器或无头环境中建议使用 # 用户数据目录使用真实指纹的关键 if profile_dir: options.add_argument(f--user-data-dir{profile_dir}) elif self.config.get(rotate_profiles): # 随机选择一个Profile目录 profiles list((Path(__file__).parent.parent / profiles).glob(profile_*)) if profiles: selected_profile random.choice(profiles) options.add_argument(f--user-data-dir{selected_profile}) print(f[Info] 使用Profile: {selected_profile.name}) # 根据模式调整参数 if mode aggressive: # 更激进的设置可能影响稳定性 options.add_argument(--disable-webgl) # 禁用WebGL避免Canvas指纹但可能影响功能 options.add_argument(--disable-featuresWebRtcHideLocalIpsWithMdns) # 创建驱动 driver uc.Chrome(optionsoptions, version_mainself.config.get(chrome_version, None)) # 即使使用uc也额外注入一些自定义脚本以增强伪装 if mode in [aggressive, balanced]: self._inject_custom_scripts(driver) return driver def _create_custom_selenium_driver(self, mode, profile_dir): 使用原生Selenium创建深度定制驱动 chrome_options Options() # 基础反检测参数 chrome_options.add_experimental_option(excludeSwitches, [enable-automation]) chrome_options.add_experimental_option(useAutomationExtension, False) # 用户数据目录 if profile_dir: chrome_options.add_argument(f--user-data-dir{profile_dir}) # 其他通用参数 chrome_options.add_argument(--disable-blink-featuresAutomationControlled) chrome_options.add_argument(--window-size1920,1080) chrome_options.add_argument(--disable-gpu) if mode aggressive else None # 无头模式设置如果需要 if self.config.get(headless, False): chrome_options.add_argument(--headlessnew) # Chrome较新版本的无头模式 chrome_options.add_argument(--disable-dev-shm-usage) chrome_options.add_argument(--no-sandbox) service Service(executable_pathself.config.get(chromedriver_path)) driver webdriver.Chrome(serviceservice, optionschrome_options) # 注入核心伪装脚本必须在get URL之前 driver.execute_cdp_cmd(Page.addScriptToEvaluateOnNewDocument, { source: self.fingerprint_scripts }) # 执行额外的CDP命令 self._apply_advanced_cdp_settings(driver, mode) return driver def _inject_custom_scripts(self, driver): 向已创建的驱动注入额外脚本适用于uc或普通驱动 try: # 尝试注入模拟插件等更复杂指纹的脚本 extra_script // 示例更细致地覆盖 permissions if (window.Notification) { Object.defineProperty(window.Notification, permission, { get: () default }); } driver.execute_cdp_cmd(Page.addScriptToEvaluateOnNewDocument, {source: extra_script}) except Exception as e: print(f[Warning] 注入自定义脚本失败: {e}) def _apply_advanced_cdp_settings(self, driver, mode): 应用高级CDP设置如覆盖User-Agent客户端提示 if mode aggressive: driver.execute_cdp_cmd(Network.setUserAgentOverride, { userAgent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 ..., platform: Win32, userAgentMetadata: { brands: [ {brand: Not A;Brand, version: 99}, {brand: Chromium, version: 96}, {brand: Google Chrome, version: 96} ], fullVersion: 96.0.4664.110, platform: Windows, platformVersion: 10.0.0, architecture: x86, model: } })5.3 行为模拟模块behavior_simulator.py负责让脚本动作更像人。import time import random import math from selenium.webdriver.common.action_chains import ActionChains from selenium.webdriver.common.keys import Keys class HumanBehaviorSimulator: def __init__(self, driver, config): self.driver driver self.config config self.actions ActionChains(driver) def human_click(self, element, spread5): 模拟人类点击先移动到一个随机点附近再点击元素 # 获取元素位置和大小 rect element.rect center_x rect[x] rect[width] / 2 center_y rect[y] rect[height] / 2 # 生成一个目标点在元素区域内但非绝对中心 target_x center_x random.uniform(-spread, spread) target_y center_y random.uniform(-spread, spread) # 使用ActionChains执行移动和点击 actions ActionChains(self.driver) # 先移动到目标点 actions.move_to_location(int(target_x), int(target_y)) actions.pause(random.uniform(0.05, 0.2)) # 点击 actions.click() actions.pause(random.uniform(0.1, 0.3)) # 点击后短暂停顿 actions.perform() def human_type(self, element, text, avg_delay0.15, delay_range0.1): 模拟人类打字随机延迟和可能的错字回退 element.click() # 先聚焦 time.sleep(random.uniform(0.2, 0.5)) for char in text: element.send_keys(char) # 每个字符输入后随机延迟模拟思考或打字速度变化 delay avg_delay random.uniform(-delay_range, delay_range) delay max(0.05, delay) # 确保延迟不为负 time.sleep(delay) # 小概率模拟打错字并回退增加随机性 if random.random() 0.02: # 2%的概率 element.send_keys(Keys.BACK_SPACE) time.sleep(random.uniform(0.1, 0.3)) element.send_keys(char) time.sleep(random.uniform(0.1, 0.2)) def random_scroll(self, scroll_pixelsNone): 随机滚动页面模拟浏览行为 if scroll_pixels is None: scroll_pixels random.randint(200, 800) # 使用JavaScript平滑滚动 script f window.scrollBy({{ top: {scroll_pixels}, left: 0, behavior: smooth }}); self.driver.execute_script(script) # 滚动后随机停留一段时间 time.sleep(random.uniform(0.5, 2.5)) def random_mouse_movement(self, duration2.0): 在页面随机移动鼠标生成轨迹 # 这是一个简化版实际更复杂的实现可以生成贝塞尔曲线路径 width self.driver.execute_script(return document.documentElement.scrollWidth) height self.driver.execute_script(return document.documentElement.scrollHeight) start_x random.randint(0, width // 2) start_y random.randint(0, height // 2) actions ActionChains(self.driver) actions.move_by_offset(start_x, start_y).perform() time.sleep(0.1) # 模拟几次小的随机移动 for _ in range(random.randint(3, 8)): dx random.randint(-50, 50) dy random.randint(-30, 30) actions.move_by_offset(dx, dy) actions.pause(random.uniform(0.05, 0.2)) actions.perform()5.4 配置文件与主程序示例config.yaml:driver: use_undetected_chromedriver: true default_mode: balanced # simple, balanced, aggressive chrome_version: 124 # 指定Chrome大版本uc会自动匹配驱动 rotate_profiles: true # 是否在多个Profile间轮换 behavior: min_action_delay: 0.5 max_action_delay: 3.0 enable_random_scroll: true stealth: inject_fingerprint_scripts: truemain.py:import yaml from core.driver_factory import StealthDriverFactory from core.behavior_simulator import HumanBehaviorSimulator import time def load_config(): with open(config.yaml, r, encodingutf-8) as f: return yaml.safe_load(f) def main(): config load_config() # 1. 创建隐身浏览器驱动 print([*] 正在初始化隐身浏览器...) factory StealthDriverFactory(config[driver]) driver factory.create_driver(modeconfig[driver][default_mode]) # 2. 初始化行为模拟器 behavior_sim HumanBehaviorSimulator(driver, config[behavior]) try: # 3. 访问目标网站 target_url https://bot.sannysoft.com/ # 一个著名的自动化检测测试页 driver.get(target_url) time.sleep(3) # 等待页面加载和检测脚本运行 # 4. 执行一些拟人化操作 behavior_sim.random_scroll() time.sleep(random.uniform(1, 2)) # 5. 进行测试检查是否被检测到 # 这里可以添加逻辑检查页面元素来判断检测结果 test_result driver.find_element(By.TAG_NAME, body).text if passed in test_result.lower() or 未检测到 in test_result: print([] 反检测测试通过) else: print([-] 可能被检测到需要调整策略。) # 6. 模拟真实任务例如搜索 # search_box driver.find_element(By.NAME, q) # behavior_sim.human_type(search_box, Selenium反检测) # behavior_sim.human_click(search_button) except Exception as e: print(f[!] 发生错误: {e}) finally: # 7. 清理 input(按回车键关闭浏览器...) driver.quit() if __name__ __main__: main()6. 常见问题排查与实战避坑指南即使按照最佳实践配置在实际运行中仍会遇到各种问题。下面是我在长期实践中总结的常见“坑”及其解决方案。6.1 驱动版本不匹配问题这是最常见的问题尤其是使用undetected-chromedriver时。症状SessionNotCreatedException提示“This version of ChromeDriver only supports Chrome version XX”。原因本地安装的Chrome浏览器版本与chromedriver或undetected-chromedriver尝试使用的驱动版本不匹配。解决方案明确版本在浏览器地址栏输入chrome://version/查看“Google Chrome”后的具体版本号如124.0.6367.91。指定版本在使用uc.Chrome()时传入version_main参数指定主版本号如124。uc会尝试自动下载匹配的驱动。手动管理驱动如果自动下载失败可以手动从https://chromedriver.chromium.org/下载对应版本的chromedriver并在代码中指定路径对于原生Selenium或放入uc的缓存目录。更新浏览器将Chrome更新到稳定版的最新版本通常能获得最好的兼容性。6.2 反检测脚本注入失败或无效症状已经注入了脚本但网站仍然检测到自动化工具。排查步骤检查注入时机确保Page.addScriptToEvaluateOnNewDocument是在driver.get()之前执行的。在页面加载后注入就太晚了。检查脚本内容在浏览器开发者工具中F12Console选项卡下输入navigator.webdriver查看返回值。如果是undefined说明基础覆盖成功。如果仍然为true说明注入未生效。网站可能检测其他属性使用Object.getOwnPropertyDescriptor(navigator, webdriver)检查属性描述符是否被成功修改。有些网站会检查属性是否可配置。使用测试网站验证访问https://bot.sannysoft.com/或https://nowsecure.nl这些网站会直观显示被检测到的自动化特征。根据报告针对性调整脚本。6.3 无头模式(Headless)更容易被检测现象在无头模式下运行时被检测的概率大大增加。原因无头模式会暴露一些特有的属性如navigator.plugins.length为0window.chrome对象可能缺失User-Agent字符串可能包含HeadlessChrome等。解决方案使用新版无头模式Chrome 112 提供了新的无头模式--headlessnew它更接近真实浏览器的行为。伪装无头特征即使使用新版也需额外注入脚本覆盖无头特征。options.add_argument(--headlessnew) # 注入脚本覆盖无头特征 driver.execute_cdp_cmd(Page.addScriptToEvaluateOnNewDocument, { source: // 覆盖 headless 相关的属性 Object.defineProperty(navigator, plugins, { get: () [1, 2, 3, 4, 5], // 返回非空数组 }); Object.defineProperty(navigator, languages, { get: () [zh-CN, zh, en-US, en], }); // 修改 userAgent 字符串移除 Headless 字样如果存在 const originalUserAgent navigator.userAgent; if (originalUserAgent.includes(Headless)) { Object.defineProperty(navigator, userAgent, { get: () originalUserAgent.replace(HeadlessChrome, Chrome), }); } })权衡考虑如果任务允许尽量不使用无头模式。带界面的浏览器虽然消耗更多资源但被检测的风险最低。可以使用虚拟帧缓冲区如Xvfb在服务器上运行带界面的浏览器。6.4 行为模拟的“过拟和”与性能损耗问题过度追求拟人化导致脚本运行速度极慢失去了自动化的意义。平衡策略关键操作拟人化只在最可能触发检测的环节如登录、提交表单、翻页使用复杂的鼠标移动和随机延迟。对于简单的数据遍历可以使用较快的速度。设置合理的延迟范围time.sleep(random.uniform(0.5, 2.0))比固定的time.sleep(2)更自然也比time.sleep(random.uniform(0, 5))更高效可控。使用异步与非阻塞等待对于网络请求优先使用Selenium的显式等待WebDriverWait而不是固定的sleep。这能在元素就绪后立即继续减少不必要的等待。性能监控记录脚本执行时间如果拟人化导致效率下降超过50%就需要评估是否值得。6.5 网站动态更新检测策略挑战今天有效的反检测方法可能因为目标网站更新了检测脚本而明天就失效。应对方法建立监控机制定期如每天用你的脚本访问一次测试页面或目标网站的某个安全页面检查是否出现验证码或被拦截。代码与配置分离将反检测脚本JS代码、CDP命令、参数配置等放在外部文件如JSON、YAML中。当需要更新时只需修改配置文件无需改动核心代码。维护指纹库收集和更新模拟真实环境的指纹数据插件列表、User-Agent字符串、屏幕分辨率组合等。关注社区关注undetected-chromedriver、puppeteer-extra等项目的Issue和更新日志了解最新的检测与反检测动态。6.6 资源管理与防崩溃内存泄漏长时间运行Selenium脚本尤其是打开大量标签页而不关闭会导致浏览器内存占用持续增长。解决方案显式关闭标签页和窗口使用driver.close()关闭不需要的标签页而不是仅仅切换到新标签。定期重启浏览器对于长时间运行的任务设计一个机制在运行一定次数或时间后完全退出并重启浏览器实例。使用driver.quit()而非driver.close()任务结束时确保调用quit()来彻底关闭浏览器进程和驱动。close()只关闭当前窗口。监控进程在服务器上使用ps aux | grep chrome监控Chrome进程数量防止僵尸进程堆积。反检测是一场持续的“军备竞赛”没有一劳永逸的解决方案。最有效的策略是分层防御和持续迭代。从基础的驱动参数配置开始逐步叠加使用反检测库、模拟真人指纹、拟人化行为并根据目标网站的反应灵活调整策略。记住我们的目标不是成为“看不见的幽灵”而是成为一个“看起来足够正常的普通访客”。保持对浏览器技术和检测手段的好奇心你的“隐身”爬虫才能行稳致远。