首页
/ Crawl4AI 反爬进阶指南:Stealth 模式与 Undetected 浏览器的原理与实践

Crawl4AI 反爬进阶指南:Stealth 模式与 Undetected 浏览器的原理与实践

2026-09-04 09:13:07作者:卓艾滢Kingsley

本文围绕 Crawl4AI 的文档 Undetected Browser Mode,系统讲解项目中两套反机器人检测能力:基于 playwright-stealth 的 Stealth 模式和基于 Patchright 的 Undetected 浏览器模式。读完后,你将掌握两者的适用场景对比、完整可运行的配置代码,并能顺着 browser_adapter.py 等源码理解适配器模式的底层实现,为受保护的站点选择最小必要的规避方案。

两种反爬能力的定位

Crawl4AI 提供了两个层次的防检测特性,用于访问启用了机器人检测的网站:

  1. Stealth 模式:通过 playwright-stealth 修改浏览器指纹与行为,适合应对基础检测;
  2. Undetected Browser Mode:一种高级浏览器适配器,通过更深层次的浏览器补丁(Patchright)应对更复杂的检测服务。

两者的能力边界可以按下表对照(引自文档原文):

Feature 常规浏览器 Stealth 模式 Undetected 浏览器
WebDriver 检测 不通过 通过 通过
Navigator 属性检测 不通过 通过 通过
插件模拟 不通过 通过 通过
CDP 检测 不通过 部分通过 通过
深层浏览器补丁
性能影响 极小 中等
配置复杂度 极小

从源码结构看,这条"能力分层"在 async_crawler_strategy.py 中有一条清晰的调用链:AsyncPlaywrightCrawlerStrategy 根据传入的 browser_adapter 判断是否使用 Undetected 模式,并把结果透传给 BrowserManager:

# crawl4ai/async_crawler_strategy.py
self.adapter = browser_adapter or PlaywrightAdapter()
...
self.browser_manager = BrowserManager(
    browser_config=self.browser_config,
    logger=self.logger,
    use_undetected=isinstance(self.adapter, UndetectedAdapter)
)

也就是说,是否走 Patchright 浏览器,完全由你传入的适配器类型决定,这就是文档所说的"Drop-in Replacement"的实现基础。

何时选择哪种方案

文档给出的选型建议:

常规浏览器 + Stealth 模式适用于:

  • 站点只做基础检测(检查 navigator.webdriver、插件等);
  • 需要良好性能且只需应对基础保护;
  • 站点检查常见的自动化指标。

Undetected 浏览器适用于:

  • 站点使用复杂的机器人检测服务(如 Cloudflare、DataDome 等);
  • 仅靠 Stealth 模式不够;
  • 愿意用一定性能换取更好的规避效果。

最佳实践——渐进式增强(Progressive Enhancement):

  1. 从"常规浏览器 + Stealth 模式"开始;
  2. 若被拦截,切换到 Undetected 浏览器;
  3. 若仍被拦截,组合 Undetected 浏览器 + Stealth 模式。

这里有一点值得注意:Stealth 模式在配置层是独立于适配器的。BrowserConfig 中的 enable_stealth 默认为 False,其文档字符串明确说明它"不能与 use_undetected 浏览器模式共用";而 browser_manager.py 中创建 Stealth 适配器的条件正是 self.config.enable_stealth and not self.use_undetected。结合 browser_adapter.pyStealthAdapter 的实现(playwright_stealth.Stealth().apply_stealth_async(page)),可以推断官方推荐的"最强组合"实际由两层机制叠加:Patchright 底层补丁 + StealthAdapter 在页面创建时注入的 stealth 脚本。

Stealth 模式:一个开关即可启用

Stealth 模式是与常规浏览器和 Undetected 浏览器都兼容的简单防检测方案:

from crawl4ai import AsyncWebCrawler, BrowserConfig

# 用常规浏览器启用 stealth 模式
browser_config = BrowserConfig(
    enable_stealth=True,  # 简单标志位即可启用
    headless=False        # 有头模式更不容易被检测
)

async with AsyncWebCrawler(config=browser_config) as crawler:
    result = await crawler.arun("https://example.com")

Stealth 模式做了些什么:

  • 移除 navigator.webdriver 标志;
  • 修改浏览器指纹;
  • 模拟真实的插件行为;
  • 调整 navigator 属性;
  • 修复常见的自动化泄漏。

在源码层面,enable_stealth=True 之后,BrowserManager 会在 初始化时创建 StealthAdapter,并在页面创建时通过 _apply_stealth_to_page 调用 Stealth().apply_stealth_async(page) 注入补丁(见 browser_manager.py#L1469-L1480)。另外 browser_adapter.py#L159-L176 显示,如果环境中没有安装 playwright_stealth 包,适配器会静默降级为普通 Playwright 行为——生产使用前建议确认该依赖已安装。

同时,enable_stealth 有一个硬性约束:BrowserConfig 构造函数 中,当 browser_mode='builtin' 时直接抛出 ValueError("Stealth 模式需要独立的浏览器实例"),使用内置托管浏览器的场景需改用 dedicated 模式。

Undetected 浏览器模式:基于 Patchright 的深度补丁

对于 Stealth 模式无法绕过的复杂检测,应使用 Undetected 浏览器适配器。

核心特性

  • Drop-in Replacement:与常规浏览器模式使用相同 API;
  • Enhanced Stealth:内置补丁,规避常见检测手段;
  • Browser Adapter 模式:可在常规与 Undetected 模式之间无缝切换;
  • 自动安装:crawl4ai-setup 会安装所有必要的浏览器依赖。

Quick Start

import asyncio
from crawl4ai import (
    AsyncWebCrawler,
    BrowserConfig,
    CrawlerRunConfig,
    UndetectedAdapter
)
from crawl4ai.async_crawler_strategy import AsyncPlaywrightCrawlerStrategy

async def main():
    # 创建 undetected 适配器
    undetected_adapter = UndetectedAdapter()

    # 创建浏览器配置
    browser_config = BrowserConfig(
        headless=False,  # headless 模式更容易被检测
        verbose=True,
    )

    # 用 undetected 适配器创建爬虫策略
    crawler_strategy = AsyncPlaywrightCrawlerStrategy(
        browser_config=browser_config,
        browser_adapter=undetected_adapter
    )

    # 用自定义策略创建爬虫
    async with AsyncWebCrawler(
        crawler_strategy=crawler_strategy,
        config=browser_config
    ) as crawler:
        # 你的爬取代码在这里
        result = await crawler.arun(
            url="https://example.com",
            config=CrawlerRunConfig()
        )
        print(result.markdown[:500])

asyncio.run(main())

这段代码在仓库中有一份可直接运行的对照示例:undetectability/undetected_basic_test.py,它先跑常规模式再跑 Undetected 模式,并对比 result.successresult.status_coderesult.markdown.raw_markdown 长度,适合用作升级前后的 A/B 验证脚本。

源码视角:UndetectedAdapter 到底做了什么

UndetectedAdapterPlaywrightAdapter 的关键差异有三处:

  1. 导入源不同get_imports() 返回的是 patchright.async_api 中的 PageErrorTimeoutError,而 PlaywrightAdapter 返回 playwright.async_api 的同名类型;
  2. 执行上下文隔离evaluate() 默认以 isolated_context=True 调用 page.evaluate,把 Crawl4AI 自身的脚本与页面环境隔离,只有涉及注入的控制变量(__console__captured__errorwindow.__)时才使用非隔离上下文;
  3. 控制台捕获改为 JS 注入。由于 Patchright 场景下不便依赖事件监听,setup_console_capture 通过 page.add_init_script 注入一段脚本,把 console.log/info/warn/error/debug 包装后写入 window.__capturedConsole,并额外监听 errorunhandledrejection 事件写入 window.__capturedErrors;retrieve_console_messages 再把这些数据取回并做毫秒到秒的时间戳换算。

相应地,browser_manager.pystart() 中,use_undetected=True 时 Playwright 实例本身就会从 patchright.async_api.async_playwright 导入,确保整个浏览器生命周期都跑在 Patchright 之上。

组合两种能力

为获得最大规避效果,可将 Stealth 模式与 Undetected 浏览器叠加:

from crawl4ai import AsyncWebCrawler, BrowserConfig, UndetectedAdapter
from crawl4ai.async_crawler_strategy import AsyncPlaywrightCrawlerStrategy

# 启用 stealth 模式的浏览器配置
browser_config = BrowserConfig(
    enable_stealth=True,  # 启用 stealth 模式
    headless=False
)

# 创建 undetected 适配器
adapter = UndetectedAdapter()

# 组合两种能力
strategy = AsyncPlaywrightCrawlerStrategy(
    browser_config=browser_config,
    browser_adapter=adapter
)

async with AsyncWebCrawler(
    crawler_strategy=strategy,
    config=browser_config
) as crawler:
    result = await crawler.arun("https://protected-site.com")

注意:如前所述,BrowserConfig 文档字符串声明 enable_stealth 不应与 undetected 模式共用,而 BrowserManager 在 undetected 场景下也会跳过 StealthAdapter 的创建。上述"组合"写法在代码层面不会报错,但 stealth 脚本是否实际生效取决于当前版本的实现细节;从源码结构看,此时真正的规避主力是 Patchright 补丁。升级版本后建议用检测测试站(下文 Example 1)验证实际效果,而不是盲目依赖组合。

完整示例

示例 1:Stealth 模式检测验证

import asyncio
from crawl4ai import AsyncWebCrawler, BrowserConfig, CrawlerRunConfig

async def test_stealth_mode():
    # 简单的 stealth 模式配置
    browser_config = BrowserConfig(
        enable_stealth=True,
        headless=False
    )

    async with AsyncWebCrawler(config=browser_config) as crawler:
        result = await crawler.arun(
            url="https://bot.sannysoft.com",
            config=CrawlerRunConfig(screenshot=True)
        )

        if result.success:
            print("✓ 成功访问机器人检测测试站")
            # 保存截图以验证检测项结果
            if result.screenshot:
                import base64
                with open("stealth_test.png", "wb") as f:
                    f.write(base64.b64decode(result.screenshot))
                print("✓ 截图已保存 - 检查绿色(通过)的检测项")

asyncio.run(test_stealth_mode())

用 SannySoft 之类的检测站截图验证,是判断"当前配置是否已被识破"最直观的手段。

示例 2:Undetected 浏览器模式

import asyncio
from crawl4ai import (
    AsyncWebCrawler,
    BrowserConfig,
    CrawlerRunConfig,
    UndetectedAdapter
)
from crawl4ai.async_crawler_strategy import AsyncPlaywrightCrawlerStrategy


async def main():
    # 创建浏览器配置
    browser_config = BrowserConfig(
        headless=False,
        verbose=True,
    )

    # 创建 undetected 适配器
    undetected_adapter = UndetectedAdapter()

    # 用 undetected 适配器创建爬虫策略
    crawler_strategy = AsyncPlaywrightCrawlerStrategy(
        browser_config=browser_config,
        browser_adapter=undetected_adapter
    )

    # 用自定义策略创建爬虫
    async with AsyncWebCrawler(
        crawler_strategy=crawler_strategy,
        config=browser_config
    ) as crawler:
        # 配置爬取
        crawler_config = CrawlerRunConfig(
            markdown_generator=DefaultMarkdownGenerator(
                content_filter=PruningContentFilter()
            ),
            capture_console_messages=True,  # 测试适配器的控制台捕获
        )

        # 在一个通常会检测机器人的站点上测试
        print("Testing undetected adapter...")
        result: CrawlResult = await crawler.arun(
            url="https://www.helloworld.org",
            config=crawler_config
        )

        print(f"Status: {result.status_code}")
        print(f"Success: {result.success}")
        print(f"Console messages captured: {len(result.console_messages or [])}")
        print(f"Markdown content (first 500 chars):\n{result.markdown.raw_markdown[:500]}")


if __name__ == "__main__":
    asyncio.run(main())

这里 capture_console_messages=True 恰好能验证前文提到的 JS 注入式控制台捕获是否正常工作:result.console_messages 的长度应当反映 UndetectedAdapter.retrieve_console_messages 取回的数据。

Browser Adapter 模式详解

Undetected 浏览器支持是用适配器模式实现的,允许在不同的浏览器实现之间无缝切换:

# 常规浏览器适配器(默认)
from crawl4ai import PlaywrightAdapter
regular_adapter = PlaywrightAdapter()

# Undetected 浏览器适配器
from crawl4ai import UndetectedAdapter
undetected_adapter = UndetectedAdapter()

三个适配器均在 crawl4ai/init.py 中导出(BrowserAdapterPlaywrightAdapterUndetectedAdapter)。抽象基类 BrowserAdapter 定义了所有浏览器特有操作的统一接口,适配器需要处理:

  • JavaScript 执行(evaluate);
  • 控制台消息捕获(setup_console_capture / retrieve_console_messages);
  • 错误处理(setup_error_capture);
  • 浏览器特定的优化(get_imports 决定类型与异常从哪个库导入)。

对比两个具体实现可以看清设计意图:PlaywrightAdapterretrieve_console_messages 直接返回空列表(消息已通过 page.on("console") 事件实时收集),而 UndetectedAdapter 则必须主动拉取页面内注入的 window.__capturedConsole——两种策略的差异被完全封装在适配器内部,上层策略代码无需感知。

最佳实践

  1. 避免 Headless 模式:headless 下更容易被检测
    browser_config = BrowserConfig(headless=False)
    
  2. 使用合理的延迟:不要过快翻页。当前源码中 CrawlerRunConfigdelay_before_return_html 默认为 0.1 秒、simulate_user 默认为 False(见 async_configs.py),可显式调大以模拟真实节奏:
    crawler_config = CrawlerRunConfig(
        delay_before_return_html=2.0,  # 额外延迟
        simulate_user=True,            # 模拟用户交互
    )
    
  3. 轮换 User Agent:BrowserConfiguser_agent 默认是一个固定的 Chrome 116 字符串,可自行定制,或使用 user_agent_mode="random" 让内置的 user_agent_generator 生成随机 UA;注意配置构造函数还会基于 UA 自动推导 sec-ch-ua 请求头(async_configs.py#L908-L909),保持两者一致能减少指纹矛盾。
  4. 优雅处理失败:部分站点仍会检测并拦截
    if not result.success:
        print(f"Crawl failed: {result.error_message}")
    

进阶:渐进式检测处理

async def crawl_with_progressive_evasion(url):
    # 第 1 步:先试常规浏览器 + stealth
    browser_config = BrowserConfig(
        enable_stealth=True,
        headless=False
    )

    async with AsyncWebCrawler(config=browser_config) as crawler:
        result = await crawler.arun(url)
        if result.success and "Access Denied" not in result.html:
            return result

    # 第 2 步:若被拦截,尝试 undetected 浏览器
    print("Regular + stealth blocked, trying undetected browser...")

    adapter = UndetectedAdapter()
    strategy = AsyncPlaywrightCrawlerStrategy(
        browser_config=browser_config,
        browser_adapter=adapter
    )

    async with AsyncWebCrawler(
        crawler_strategy=strategy,
        config=browser_config
    ) as crawler:
        result = await crawler.arun(url)
        return result

安装

Undetected 浏览器的依赖会在运行安装命令时自动装好:

crawl4ai-setup

该命令同时安装常规与 Undetected 两种模式所需的浏览器。从 install.py 的实现看,它在 Playwright 安装之后,会额外执行 patchright install --with-deps --force chromium;若任一步骤失败,会提示你手动运行 python -m patchright install --with-deps。因此在手动部署(如容器)场景中,确认 Patchright 浏览器二进制已安装是排查"Browser Not Found"的第一步。

局限性与注意事项

  • 性能:由于额外的补丁,比常规模式略慢;
  • Headless 检测:部分站点仍可能识别 headless 模式;
  • 资源占用:可能比常规模式消耗更多资源;
  • 不是 100% 保证:高级反机器人服务在持续演化,没有一劳永逸的方案。

故障排查

浏览器未找到

运行安装命令:

crawl4ai-setup

仍被检测

尝试叠加其他功能:

crawler_config = CrawlerRunConfig(
    simulate_user=True,  # 增加用户行为模拟
    wait_time=5.0,       # 更长等待(如当前版本无此参数,改用 delay_before_return_html / mean_delay)
)

参数核对说明:在当前仓库的 CrawlerRunConfig 源码中,已确认存在的延迟/模拟相关参数为 delay_before_return_htmlmean_delaymax_rangesimulate_userwait_for_images(见 async_configs.py);文档示例中的 magicwait_time 请以你所用版本实际签名为准。

性能问题

若性能不佳,可只对受保护站点启用 Undetected 模式:

# 仅对受保护站点使用选择性 undetected 模式
if is_protected_site(url):
    adapter = UndetectedAdapter()
else:
    adapter = PlaywrightAdapter()  # 默认适配器

未来计划

说明:Crawl4AI 未来版本可能会默认启用 Stealth 模式与 Undetected 浏览器,以提供更好的开箱成功率。目前用户应在需要时显式启用这些功能。

总结

Crawl4AI 提供了灵活的反机器人方案:

  1. 从简单开始:多数站点用常规浏览器 + Stealth 模式即可;
  2. 必要时升级:面对复杂防护时切换到 Undetected 浏览器;
  3. 组合拳应对最强防护:两者叠加使用。

同时请记住:

  • 始终尊重 robots.txt 与网站服务条款;
  • 使用合理的延迟,避免压垮服务器;
  • 权衡每种方案的性能代价;
  • 渐进式测试,找到满足需求的最低规避级别。

延伸阅读

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.12 K
2.72 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
528
588
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
906
1.82 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
854
1.34 K
docsdocs
暂无描述
Markdown
891
5.78 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.53 K
1.01 K
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.34 K
1.45 K
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
987
504
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
540
384