<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>反爬虫 on Tao</title><link>https://743v45.github.io/di4urp/tags/%E5%8F%8D%E7%88%AC%E8%99%AB/</link><description>Recent content in 反爬虫 on Tao</description><generator>Hugo -- gohugo.io</generator><language>zh-cn</language><managingEditor>di4urp@gmail.com (taevas)</managingEditor><webMaster>di4urp@gmail.com (taevas)</webMaster><lastBuildDate>Thu, 12 Mar 2026 12:00:00 +0800</lastBuildDate><atom:link href="https://743v45.github.io/di4urp/tags/%E5%8F%8D%E7%88%AC%E8%99%AB/index.xml" rel="self" type="application/rss+xml"/><item><title>深入理解浏览器反机器人检测原理</title><link>https://743v45.github.io/di4urp/posts/stealth-anti-bot-detection/</link><pubDate>Thu, 12 Mar 2026 12:00:00 +0800</pubDate><author>di4urp@gmail.com (taevas)</author><guid>https://743v45.github.io/di4urp/posts/stealth-anti-bot-detection/</guid><description>&lt;h2 id="背景"&gt;背景&lt;/h2&gt;
&lt;p&gt;在 Web 自动化测试和数据采集场景中，浏览器自动化工具（如 Puppeteer、Playwright、Selenium）常被目标网站检测识别。网站通过一系列 JavaScript 指纹技术判断访问者是否为真实用户。&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/go-rod/stealth"&gt;go-rod/stealth&lt;/a&gt; 是一个 Go 语言库，为 &lt;a href="https://github.com/go-rod/rod"&gt;rod&lt;/a&gt; 浏览器自动化框架提供反检测能力。本文深入分析其工作原理。&lt;/p&gt;
&lt;h2 id="网站如何检测自动化工具"&gt;网站如何检测自动化工具&lt;/h2&gt;
&lt;h3 id="1-navigator-属性检测"&gt;1. Navigator 属性检测&lt;/h3&gt;
&lt;p&gt;浏览器暴露 &lt;code&gt;navigator&lt;/code&gt; 对象，包含大量设备信息：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 自动化工具的典型特征
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;navigator&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;webdriver&lt;/span&gt; &lt;span style="color:#f92672"&gt;===&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt; &lt;span style="color:#75715e"&gt;// Selenium/WebDriver 标记
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;navigator&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;plugins&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;length&lt;/span&gt; &lt;span style="color:#f92672"&gt;===&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#75715e"&gt;// 无插件
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;navigator&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;languages&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;length&lt;/span&gt; &lt;span style="color:#f92672"&gt;===&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#75715e"&gt;// 无语言设置
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;真实浏览器的 &lt;code&gt;navigator.webdriver&lt;/code&gt; 为 &lt;code&gt;undefined&lt;/code&gt;，而自动化工具返回 &lt;code&gt;true&lt;/code&gt;。&lt;/p&gt;
&lt;h3 id="2-chrome-devtools-protocol-检测"&gt;2. Chrome DevTools Protocol 检测&lt;/h3&gt;
&lt;p&gt;Chrome 通过 CDP (Chrome DevTools Protocol) 控制浏览器。网站可以检测：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 检测 CDP Runtime 是否被启用
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;e&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; Error();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;e&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;stack&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;includes&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;puppeteer_evaluation_script&amp;#39;&lt;/span&gt;)) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 检测到自动化
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="3-webgl-指纹"&gt;3. WebGL 指纹&lt;/h3&gt;
&lt;p&gt;WebGL 渲染器信息可用于识别：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;canvas&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; document.&lt;span style="color:#a6e22e"&gt;createElement&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;canvas&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;gl&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;canvas&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;getContext&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;webgl&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;debugInfo&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;gl&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;getExtension&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;WEBGL_debug_renderer_info&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;vendor&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;gl&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;getParameter&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;debugInfo&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;UNMASKED_VENDOR_WEBGL&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// SwiftShader = Headless Chrome 的软件渲染器
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="4-iframe-内容检测"&gt;4. iframe 内容检测&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 自动化工具注入的脚本会留下痕迹
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;iframe&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; document.&lt;span style="color:#a6e22e"&gt;createElement&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;iframe&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;iframe&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;srcdoc&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;&amp;lt;script&amp;gt;console.log(navigator.webdriver)&amp;lt;/script&amp;gt;&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 检测 iframe 中的属性
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="stealth-的反检测策略"&gt;Stealth 的反检测策略&lt;/h2&gt;
&lt;h3 id="核心架构"&gt;核心架构&lt;/h3&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;┌──────────────────────────────────────────┐
│ 用户代码 │
│ ↓ │
│ stealth.Page(browser) → *rod.Page │
│ ↓ │
│ rod.Browser.Page() + EvalOnNewDocument │
│ ↓ │
│ stealth.JS (嵌入的 JavaScript) │
│ - Chrome 对象伪装 │
│ - WebDriver 属性隐藏 │
│ - WebGL 指纹伪装 │
└──────────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="mustpage-工作流程"&gt;MustPage 工作流程&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;MustPage&lt;/code&gt; 是 &lt;code&gt;Page&lt;/code&gt; 的包装，遵循 Go 的 &lt;code&gt;Must&lt;/code&gt; 前缀约定：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-go" data-lang="go"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// MustPage 创建无法被检测为机器人的页面&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;MustPage&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;b&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;rod&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Browser&lt;/span&gt;) &lt;span style="color:#f92672"&gt;*&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;rod&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Page&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;p&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;err&lt;/span&gt; &lt;span style="color:#f92672"&gt;:=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Page&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;b&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;err&lt;/span&gt; &lt;span style="color:#f92672"&gt;!=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;nil&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; panic(&lt;span style="color:#a6e22e"&gt;err&lt;/span&gt;) &lt;span style="color:#75715e"&gt;// 失败时 panic&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;p&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// Page 创建页面并注入反检测脚本&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Page&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;b&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;rod&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Browser&lt;/span&gt;) (&lt;span style="color:#f92672"&gt;*&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;rod&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Page&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;error&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 1. 创建新的浏览器页面&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;p&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;err&lt;/span&gt; &lt;span style="color:#f92672"&gt;:=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;b&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Page&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;proto&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;TargetCreateTarget&lt;/span&gt;{})
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;err&lt;/span&gt; &lt;span style="color:#f92672"&gt;!=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;nil&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;nil&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;err&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 2. 在每个新文档加载前注入 JS&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;_&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;err&lt;/span&gt; = &lt;span style="color:#a6e22e"&gt;p&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;EvalOnNewDocument&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;JS&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;err&lt;/span&gt; &lt;span style="color:#f92672"&gt;!=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;nil&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;nil&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;err&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;p&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;完整调用链：&lt;/strong&gt;&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;MustPage(browser)
│
├── Page(browser)
│ │
│ ├── b.Page(proto.TargetCreateTarget{}) ← 创建空白页面
│ │ │
│ │ └── CDP: Target.createTarget
│ │
│ └── p.EvalOnNewDocument(JS) ← 注入反检测脚本
│ │
│ └── CDP: Page.addScriptToEvaluateOnNewDocument
│
└── 返回 *rod.Page
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;strong&gt;时序图：&lt;/strong&gt;&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;用户代码 stealth.Page rod.Browser CDP
│ │ │ │
│──── Page() ─────&amp;gt;│ │ │
│ │ │ │
│ │── b.Page() ───────&amp;gt;│ │
│ │ │── createTarget─&amp;gt;│
│ │ │&amp;lt;── pageId ─────│
│ │&amp;lt;── *Page ──────────│ │
│ │ │ │
│ │── EvalOnNewDocument ───────────────&amp;gt;│
│ │ │ │
│&amp;lt;── *Page ────────│ │ │
│ │ │ │
│── Navigate() ────────────────────────────────────────&amp;gt;│
│ │ │
│ [JS 在页面脚本前执行] │
│ │ │
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="关键技术evalonnewdocument"&gt;关键技术：EvalOnNewDocument&lt;/h3&gt;
&lt;p&gt;stealth 的核心只有 34 行 Go 代码，关键在于 &lt;code&gt;EvalOnNewDocument&lt;/code&gt;：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-go" data-lang="go"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Page&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;b&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;rod&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Browser&lt;/span&gt;) (&lt;span style="color:#f92672"&gt;*&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;rod&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Page&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;error&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;p&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;err&lt;/span&gt; &lt;span style="color:#f92672"&gt;:=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;b&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Page&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;proto&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;TargetCreateTarget&lt;/span&gt;{})
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;err&lt;/span&gt; &lt;span style="color:#f92672"&gt;!=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;nil&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;nil&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;err&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 在每个新文档加载前注入 JS&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;_&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;err&lt;/span&gt; = &lt;span style="color:#a6e22e"&gt;p&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;EvalOnNewDocument&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;JS&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;err&lt;/span&gt; &lt;span style="color:#f92672"&gt;!=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;nil&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;nil&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;err&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;p&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;EvalOnNewDocument&lt;/code&gt; 是 CDP 的 &lt;code&gt;Page.addScriptToEvaluateOnNewDocument&lt;/code&gt; 命令封装，确保注入的脚本在任何页面脚本执行前运行。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;执行时机对比：&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;方法&lt;/th&gt;
&lt;th&gt;执行时机&lt;/th&gt;
&lt;th&gt;能否修改原生 API&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;page.Eval()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;页面加载后&lt;/td&gt;
&lt;td&gt;❌ 太晚，已被检测&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;page.EvalOnNewDocument()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;页面加载前&lt;/td&gt;
&lt;td&gt;✅ 优先执行&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;工作原理：&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;注册阶段&lt;/strong&gt;：调用 &lt;code&gt;EvalOnNewDocument(JS)&lt;/code&gt; 时，CDP 将脚本注册到浏览器&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;触发时机&lt;/strong&gt;：每次导航到新页面或创建新 iframe 时自动执行&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;执行顺序&lt;/strong&gt;：注入的脚本在页面的 &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; 标签之前执行&lt;/li&gt;
&lt;/ol&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;页面加载时间线：
─────────────────────────────────────────────────────────&amp;gt;
│ │ │
▼ ▼ ▼
[EvalOnNewDocument] [页面 &amp;lt;script&amp;gt;] [检测脚本]
│ │ │
└── 修改原生 API ────┘ │
│ │
└── 检测脚本看到伪装后的 API ──&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="javascript-伪装模块"&gt;JavaScript 伪装模块&lt;/h3&gt;
&lt;p&gt;stealth 嵌入了 &lt;a href="https://github.com/nickyout/stealth-evasions"&gt;stealth-evasions&lt;/a&gt; 的编译产物（约 185KB），包含多个伪装模块：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;模块&lt;/th&gt;
&lt;th&gt;功能&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;chrome.app&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;伪装 Chrome 应用 API&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;chrome.csi&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;伪装 Chrome CSI 接口&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;chrome.loadTimes&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;伪装页面加载时间&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;chrome.runtime&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;伪装 Chrome Runtime API&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;navigator.webdriver&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;隐藏 WebDriver 标记&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;navigator.plugins&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;伪造插件列表&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;navigator.languages&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;设置语言列表&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;webgl&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;伪装 WebGL 渲染器信息&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;iframe.contentWindow&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;修复 iframe 检测&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;media.codecs&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;伪造媒体编解码器支持&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;user-agent-override&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;处理 User-Agent 一致性&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="webdriver-属性隐藏示例"&gt;WebDriver 属性隐藏示例&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 原始检测点
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Object.&lt;span style="color:#a6e22e"&gt;getOwnPropertyDescriptor&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;Navigator&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;prototype&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;webdriver&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// stealth 的伪装
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Object.&lt;span style="color:#a6e22e"&gt;defineProperty&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;Navigator&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;prototype&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;webdriver&amp;#39;&lt;/span&gt;, {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;get&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; () =&amp;gt; &lt;span style="color:#66d9ef"&gt;undefined&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;configurable&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;});
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 同时处理 iframe 场景
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;originalContentWindow&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;HTMLIFrameElement&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;prototype&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;contentWindow&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Object.&lt;span style="color:#a6e22e"&gt;defineProperty&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;HTMLIFrameElement&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;prototype&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;contentWindow&amp;#39;&lt;/span&gt;, {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;get&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; window &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;originalContentWindow&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;call&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 递归处理 iframe 内的 navigator.webdriver
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; window;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;});
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="webgl-指纹伪装示例"&gt;WebGL 指纹伪装示例&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 检测点：SwiftShader 软件渲染器
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;getParameter&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;WebGLRenderingContext&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;prototype&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;getParameter&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;WebGLRenderingContext&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;prototype&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;getParameter&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;parameter&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// UNMASKED_VENDOR_WEBGL
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;parameter&lt;/span&gt; &lt;span style="color:#f92672"&gt;===&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;37445&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;Google Inc. (NVIDIA)&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// UNMASKED_RENDERER_WEBGL
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;parameter&lt;/span&gt; &lt;span style="color:#f92672"&gt;===&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;37446&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;ANGLE (NVIDIA, NVIDIA GeForce GTX 1080 Direct3D11 vs_5_0 ps_5_0)&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;getParameter&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;call&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;parameter&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="设计亮点"&gt;设计亮点&lt;/h2&gt;
&lt;h3 id="1-gogenerate-自动化嵌入"&gt;1. go:generate 自动化嵌入&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-go" data-lang="go"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;//go:generate go run ./generate&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;generate 脚本自动下载 stealth-evasions 并嵌入到 &lt;code&gt;assets.go&lt;/code&gt;：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;JS 库更新 → go generate → assets.go 更新 → 编译
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="2-零运行时依赖"&gt;2. 零运行时依赖&lt;/h3&gt;
&lt;p&gt;编译后 JS 代码嵌入二进制，无需外部文件，部署简单。&lt;/p&gt;
&lt;h3 id="3-惯用的-go-api"&gt;3. 惯用的 Go API&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-go" data-lang="go"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 遵循 Go 的 Must 前缀约定&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;page&lt;/span&gt; &lt;span style="color:#f92672"&gt;:=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;stealth&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;MustPage&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;browser&lt;/span&gt;) &lt;span style="color:#75715e"&gt;// 失败时 panic&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;page&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;err&lt;/span&gt; &lt;span style="color:#f92672"&gt;:=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;stealth&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Page&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;browser&lt;/span&gt;) &lt;span style="color:#75715e"&gt;// 返回 error&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="局限性与注意事项"&gt;局限性与注意事项&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;非银弹&lt;/strong&gt;：高级检测（如行为分析、TLS 指纹）无法通过 JS 伪装解决&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;维护成本&lt;/strong&gt;：浏览器更新可能引入新的检测点&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;合规风险&lt;/strong&gt;：某些网站明确禁止自动化访问&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="总结"&gt;总结&lt;/h2&gt;
&lt;p&gt;stealth 通过在页面加载前注入伪装 JavaScript，解决了常见的自动化检测手段。其设计简洁，核心原理是利用 CDP 的 &lt;code&gt;addScriptToEvaluateOnNewDocument&lt;/code&gt; 确保伪装代码优先执行。&lt;/p&gt;
&lt;p&gt;理解反检测原理不仅有助于合法的自动化测试，也能帮助开发者设计更好的防御策略。&lt;/p&gt;
&lt;h2 id="参考资料"&gt;参考资料&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/nickyout/stealth-evasions"&gt;stealth-evasions 源码&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://chromedevtools.github.io/devtools-protocol/"&gt;Chrome DevTools Protocol&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/go-rod/rod"&gt;rod 文档&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="手动档"&gt;手动档&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;一个 generate/main.go 自动生成 assets.go 文件，捞的 npm extract-stealth-evasions 项目。发文时间看到项目最新版本为 2023.3.1。且 CDN 不可用&lt;/li&gt;
&lt;li&gt;extract-stealth-evasions 启动无头浏览器并加载 stealth 插件；
重写 Puppeteer 页面的 evaluateOnNewDocument/evaluate 方法（这两个方法是 Puppeteer 向浏览器注入脚本的核心方法）；
打开空白页（about:blank），触发 stealth 插件自动注入反检测脚本；
重写后的方法会把注入的脚本代码捕获并拼接成字符串（存入 scripts 变量）。&lt;/li&gt;
&lt;li&gt;消除自动化特征 &lt;a href="https://www.doubao.com/thread/wbb28ea45418e850d"&gt;https://www.doubao.com/thread/wbb28ea45418e850d&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description></item></channel></rss>