DeepSeek 网页端中转方案可行性与深度实现报告:基于 Quicker 与 WebView2 的架构解析

洛洛罗 2025/12/2 发布 · 2025/12/2 更新 · 18 次阅读

根据报告制作的动作已经上线:https://getquicker.net/Sharedaction?code=1ee89389-2e3e-4a77-c23f-08de3147f78a

1. 执行摘要与项目背景

在当前大语言模型(LLM)应用爆发的背景下,用户对于高效、低成本地接入先进模型能力的需求日益增长。DeepSeek 作为近期表现卓越的模型提供商,其网页端(chat.deepseek.com)提供了免费且功能完整的交互体验,特别是针对 R1 推理模型的“思维链”(Chain of Thought)可视化展示,这在标准 API 中往往需要特定的参数配置或仅返回最终结果。本报告旨在深入探讨利用 Windows 自动化工具 Quicker 结合 Microsoft Edge WebView2 控件,构建一个能够“后台运行”、“即时响应”的 DeepSeek 网页端中转(Relay)子程序的技术可行性与实施细节。

经过详尽的技术验证与架构分析,本报告确认该方案在技术上是完全可行的,但其实现难度远高于简单的 HTTP 请求封装。该方案的核心在于构建一个“无头(Headless)”或“伪后台”的浏览器代理,通过 WebView2 引擎在本地渲染 DeepSeek 网页,并通过双向进程间通信(IPC)机制实现 Quicker 主程序与网页 DOM(文档对象模型)之间的数据交换。

相比于官方 API,此方案的优势在于零边际成本(利用网页端免费额度)和对网页独有功能(如完整思维链展示、文件上传交互)的保留;劣势则在于系统架构的复杂性、对网页 DOM 结构的依赖性(即“脆性”),以及在 Windows 环境下维持后台浏览器进程活跃度的技术挑战。本报告将分章节详细阐述从架构设计、DOM 逆向工程、WebView2 深度集成到后台资源调度优化的全过程,为开发者提供一份字数详实、逻辑严密的实施指南。

2. 技术架构深度解析与可行性论证

2.1 核心组件的技术特性分析

本方案涉及三个核心技术层级:宿主环境(Quicker)、渲染引擎(WebView2)以及目标应用(DeepSeek Web)。理解这三者的交互机制是论证可行性的基础。

2.1.1 Quicker 的.NET 互操作性

Quicker 不仅仅是一个简单的宏录制工具,其底层基于.NET Framework/Core 构建,支持强大的 C# 脚本执行能力。这使得 Quicker 能够动态加载外部 DLL(动态链接库),实例化复杂的 Windows Form 或 WPF 窗口对象。对于本方案而言,这意味着我们不必受限于 Quicker 内置的简易浏览器动作,而是可以直接编写 C# 代码来创建一个拥有完全控制权的 System.Windows.Forms.Form,并在其中宿主 WebView2 控件。Quicker 的“子程序”机制允许将这段复杂的逻辑封装,对外暴露简单的输入(用户 Prompt)和输出(AI 响应),完全符合用户“封装成一个子程序”的需求 。   

2.1.2 WebView2 的现代化渲染与 IPC 能力

Microsoft Edge WebView2 控件基于 Chromium 内核,这与旧时代的 WebBrowser 控件(基于 IE)有着本质区别。

  • 现代 Web 标准支持: DeepSeek 网页端采用 React 等现代前端框架构建,依赖大量的 ES6+ 语法、CSS Grid 布局以及复杂的异步 JavaScript 执行。WebView2 能够完美渲染此类单页应用(SPA)。   

  • 隔离的 User Data Folder(用户数据文件夹): WebView2 允许开发者指定独立的 UserDataFolder。这是实现“免登录”的关键——通过持久化存储 Cookies 和 LocalStorage,用户只需登录一次,后续子程序启动时即可自动恢复会话,无需重复扫码或输入密码 。   

  • 双向通信桥梁: WebView2 提供了 ExecuteScriptAsync 方法供宿主调用网页 JS,以及 WebMessageReceived 事件供网页 JS 回传数据给宿主。这种机制构建了 Quicker 与 DeepSeek 之间的高速数据通道,其延迟远低于传统的文件轮询或剪贴板监控方式 。   

2.1.3 DeepSeek 网页端的动态特性

DeepSeek 的网页端是一个典型的动态 SPA,其响应采用了 Server-Sent Events (SSE) 流式传输。这意味着 DOM 元素不是一次性加载完成的,而是随着文本生成的节奏不断更新。自动化脚本必须具备“观察”能力,即利用 MutationObserver 实时捕捉 DOM 变化,而非简单地等待页面加载完成。此外,DeepSeek R1 模型引入的“深度思考”模式在 DOM 结构上会有特殊的表现形式(如独立的思考容器),这也为自动化提取提供了丰富的数据源,但同时也增加了选择器适配的复杂度 。   

2.2 “后台运行”的技术挑战与对策

用户明确提出需要“后台传递消息”。在 Windows 桌面应用开发中,“后台”是一个模糊的概念,可能指最小化、隐藏窗口或系统托盘运行。然而,对于基于 Chromium 的 WebView2 而言,真正的“隐藏”或“最小化”会触发浏览器的资源优化机制。

2.2.1 遮挡剔除与定时器节流

现代浏览器为了省电,会对不可见(Occluded)或后台标签页(Background Tabs)进行极其激进的资源限制。

  • 渲染停止: 当 WebView2 窗口的 Visible 属性设为 false,或窗口被最小化时,Chromium 的合成器(Compositor)可能会停止绘制帧。虽然逻辑代码(JS)通常继续运行,但依赖 requestAnimationFrame 的 UI 更新可能会暂停 。   

  • 定时器节流: 后台页面的 setTimeout 和 setInterval 可能会被强制降低至 1Hz(每秒一次)甚至更低。这会导致 DeepSeek 的流式响应接收变慢,或者心跳包丢失导致连接断开。

2.2.2 解决方案:透明窗口与屏幕外渲染

为了规避上述机制,我们不能简单地调用 Form.Hide()。必须采用“伪后台”策略:

  • 透明度欺骗(Opacity Hack): 将窗口的 Opacity 属性设置为 1%(0.01)。对于 Windows 桌面窗口管理器(DWM)而言,该窗口仍然是“可见”的,因此必须进行渲染;但对于用户肉眼而言,它是不可见的。

  • 屏幕外坐标(Off-Screen): 将窗口位置设置在显示器区域之外,例如坐标 (-32000, -32000)。这样窗口保持“还原(Restored)”状态而非“最小化(Minimized)”状态,从而骗过浏览器的资源调度器,使其全速运行 。   

2.3 架构决策:持久化进程 vs 瞬态调用

Quicker 的动作通常是瞬态的(Transient),即按下快捷键运行,执行完毕后进程释放。然而,WebView2 的初始化成本较高(冷启动可能需要 1-2 秒),且 DeepSeek 网页加载也需要时间。如果每次发送消息都重新加载网页,体验将极其糟糕。

结论: 必须采用单例模式(Singleton Pattern)。 Quicker 子程序应当设计为“启动器 + 客户端”。首次运行时,它启动一个独立的、隐藏的 Windows Form 进程(我们可以称之为“DeepSeek Bridge”),该进程常驻后台并维持 DeepSeek 会话。后续运行 Quicker 动作时,通过本地套接字(Socket)、命名管道(Named Pipe)或简单的 HTTP 本地服务与该后台进程通信。这种分离架构不仅保证了毫秒级的响应速度,还避免了 Quicker 主进程因浏览器内存泄漏或崩溃而受到影响。


3. DeepSeek 网页端逆向工程与 DOM 解析

要实现消息的中转,我们必须像外科手术一样精准地操作 DeepSeek 的网页 DOM。由于 DeepSeek 官方并未公开网页版的内部 API,我们需要基于现有的用户脚本(UserScripts)和浏览器开发者工具进行逆向分析。

3.1 核心交互元素的定位(Selectors)

网页自动化的基石是 CSS 选择器。根据对 DeepSeek 网页结构的分析以及社区开源脚本(如 PromptHelper、FoldingDeepSeek 等)的代码审计,我们可以确定以下关键元素 。   

3.1.1 输入框(Textarea)

DeepSeek 的输入框不仅仅是一个 HTML textarea,它被 React 框架严密接管。

  • 选择器特征: 通常具有 ID chat-input 或特定的 placeholder 属性。

    • 主要选择器:textarea#chat-input 。   

    • 备用选择器:textarea[placeholder*='Ask'] 或 textarea[placeholder*='Message'] 。   

  • 交互陷阱: 直接修改 textarea.value = "Hello" 通常无效。React 的虚拟 DOM(Virtual DOM)会忽略这种非用户触发的变更,导致提交按钮保持禁用状态,或者提交后内容为空。

  • 破解之道: 必须调用 Web 原型的属性设置器(Native Property Setter),并手动触发 input 事件,以模拟真实的用户输入行为,强制 React 状态同步 。   

3.1.2 发送按钮(Send Button)

发送按钮的状态通常与输入框内容绑定。

  • 选择器特征: 通常是位于输入框右侧的图标按钮。

    • 主要选择器:div[role='button'] 或 .send-button(类名可能混淆,需结合上下文)。   

    • 替代方案:模拟键盘事件。在聚焦输入框后,发送 Enter 键(需注意区分 Shift+Enter 换行与 Enter 发送的配置差异,部分脚本显示 DeepSeek 默认支持 Enter 发送)。   

3.1.3 响应容器与流式内容

DeepSeek 的回复是动态生成的 Markdown 内容。

  • 容器特征: 消息流通常包裹在具有 .ds-markdown 或 .markdown-body 类的 div 中 。   

  • 提取逻辑: 聊天记录是追加式的。自动化脚本需要定位到最后一个具备“助手(Assistant)”角色的消息块。利用 MutationObserver 监听该节点的 childList 变化,可以捕获每一个新生成的字符(Token),实现打字机效果的实时转发。

3.1.4 深度思考(Thinking Process)

DeepSeek R1 模型的独特之处在于其“思维链”。网页端通常会将这部分内容渲染在一个独立的区域,有时是折叠的。

  • 结构推测: 思维链可能位于 .thinking-process 类或特定的 <details> 标签内。与最终答案(Answer)区分开来是自动化脚本的一大优势,允许用户选择是否在 Quicker 界面显示思考过程 。   

3.2 动态验证与反爬虫机制(Cloudflare)

DeepSeek 网页端前端部署了 Cloudflare Turnstile 或类似的验证机制 。   

  • WebView2 的优势: 作为一个完整的浏览器,WebView2 自带指纹(User Agent、Canvas 指纹等)与标准 Chrome 几乎一致,通常能通过无感验证。

  • 人工介入机制(Human-in-the-Loop): 如果遇到强验证(如点击图片),后台隐藏窗口将无能为力。因此,子程序设计中必须包含一个“显示窗口”的开关。当检测到页面跳转至验证 URL 或长时间无响应时,Quicker 应能一键唤出 WebView2 窗口,让用户手动完成验证,随后再自动隐藏。


4. WebView2 深度集成方案

在确认了可行性并分析了目标网页后,本节将详细阐述如何在 Quicker 的 C# 环境中集成 WebView2。

4.1 环境准备与依赖管理

Quicker 自身不一定预装 WebView2 的.NET 封装库。我们需要手动处理依赖。

  • DLL 引用: 脚本需要引用 Microsoft.Web.WebView2.Core.dll 和 Microsoft.Web.WebView2.WinForms.dll。这些文件可以随子程序分发,或者在脚本运行时从 NuGet 下载到临时目录加载。

  • Runtime 检查: 必须检查用户系统是否安装了 WebView2 Runtime(Windows 10/11 通常预装)。如果未安装,脚本应提示用户下载“常青版(Evergreen)引导程序” 。   

4.2 核心代码逻辑:C# 宿主端

以下是 C# 代码的核心骨架,展示了如何创建一个隐藏的、持久化的 WebView2 窗口,并建立通信接口。

C#
 
using System;
using System.Windows.Forms;
using Microsoft.Web.WebView2.Core;
using Microsoft.Web.WebView2.WinForms;
using System.Drawing;
using System.Threading.Tasks;

public class DeepSeekBridge : Form
{
    private WebView2 webView;
    private const string TARGET_URL = "https://chat.deepseek.com/";
    // 指定用户数据文件夹,实现免登录
    private const string USER_DATA_FOLDER = @"C:\Users\Public\DeepSeek_Quicker_Data";

    public DeepSeekBridge()
    {
        // 1. 窗口初始化设置:伪后台模式
        this.ShowInTaskbar = false;
        this.FormBorderStyle = FormBorderStyle.None;
        this.Size = new Size(1024, 768); // 保持足够尺寸以触发桌面版布局
        this.StartPosition = FormStartPosition.Manual;
        this.Location = new Point(-32000, -32000); // 移出屏幕外
        this.Opacity = 0.01; // 防止完全不可见导致的渲染停止

        InitializeAsync();
    }

    private async void InitializeAsync()
    {
        webView = new WebView2();
        webView.Dock = DockStyle.Fill;
        this.Controls.Add(webView);

        // 2. 环境初始化
        var env = await CoreWebView2Environment.CreateAsync(userDataFolder: USER_DATA_FOLDER);
        await webView.EnsureCoreWebView2Async(env);

        // 3. 注册事件
        webView.CoreWebView2.WebMessageReceived += OnWebMessageReceived;
        webView.CoreWebView2.NavigationCompleted += OnNavigationCompleted;
        
        // 4. 加载页面
        webView.Source = new Uri(TARGET_URL);
    }

    // 接收来自网页 JS 的消息
    private void OnWebMessageReceived(object sender, CoreWebView2WebMessageReceivedEventArgs e)
    {
        string message = e.TryGetWebMessageAsString();
        // 处理消息:例如将其写入本地文件、剪贴板或通过 NamedPipe 发送给 Quicker
        HandleMessage(message);
    }

    // 注入核心 JS 桥接脚本
    private async void OnNavigationCompleted(object sender, CoreWebView2NavigationCompletedEventArgs e)
    {
        if (e.IsSuccess)
        {
            string bridgeJs = GetBridgeScript(); // 获取下文定义的 JS 脚本
            await webView.CoreWebView2.ExecuteScriptAsync(bridgeJs);
        }
    }

    // 公共方法:供外部(Quicker)调用以发送 Prompt
    public async Task SendPromptToAi(string prompt)
    {
        // 将 prompt 转义为 JSON 字符串以安全注入 JS
        string jsonPrompt = System.Text.Json.JsonSerializer.Serialize(prompt);
        await webView.CoreWebView2.ExecuteScriptAsync($"window.DeepSeekAgent.sendUserMessage({jsonPrompt})");
    }
}

4.3 核心代码逻辑:JavaScript 注入端

这段 JS 代码将作为“代理人”驻留在 DeepSeek 网页中,负责操作 DOM 和监听变化。

JavaScript
 
// Bridge Script
window.DeepSeekAgent = {
    // 模拟用户输入
    sendUserMessage: function(text) {
        const input = document.querySelector('textarea#chat-input');
        if (!input) return "ERROR: Input not found";

        // React 兼容性输入 Hack
        const nativeSetter = Object.getOwnPropertyDescriptor(window.HTMLTextAreaElement.prototype, "value").set;
        nativeSetter.call(input, text);
        input.dispatchEvent(new Event('input', { bubbles: true }));

        // 延迟点击发送,给予 React 状态同步时间
        setTimeout(() => {
            const btn = document.querySelector('.send-button'); // 需根据实际情况调整选择器
            if (btn) btn.click();
            else {
                // 尝试回车发送
                input.dispatchEvent(new KeyboardEvent('keydown', {
                    key: 'Enter', code: 'Enter', keyCode: 13, bubbles: true
                }));
            }
        }, 100);
    },

    // 启动观察者监听回复
    initObserver: function() {
        const observer = new MutationObserver((mutations) => {
            // 简单策略:获取最后一个 Markdown 块的文本
            const msgs = document.querySelectorAll('.ds-markdown');
            if (msgs.length > 0) {
                const lastMsg = msgs[msgs.length - 1];
                // 发送增量或全量文本回 C#
                window.chrome.webview.postMessage({
                    type: 'stream',
                    content: lastMsg.innerText,
                    isThinking: false // 后续可扩展 R1 思考检测
                });
            }
            
            // 检测生成是否结束(例如检查“停止生成”按钮是否消失)
            const stopBtn = document.querySelector('button');
            if (!stopBtn && msgs.length > 0) {
                 window.chrome.webview.postMessage({ type: 'done' });
            }
        });

        const chatContainer = document.querySelector('body'); // 范围可缩小以提升性能
        observer.observe(chatContainer, { childList: true, subtree: true });
    }
};

// 启动监听
window.DeepSeekAgent.initObserver();

5. Quicker 子程序的设计与通信流程

在 Quicker 端,我们需要设计一套机制来管理这个后台进程。

5.1 通信协议设计

由于 Quicker 和 WebView2 窗口可能运行在不同线程甚至不同进程(如果采用独立 EXE 方案),推荐使用 HTTP 本地回环 或 命名管道 进行通信。

  • 方案推荐:简单 HTTP 服务器 在 C# DeepSeekBridge 类中,启动一个轻量级的 HttpListener,监听 http://127.0.0.1:54321

    • POST /chat: 接收用户 Prompt。

    • GET /stream: SSE 长连接,实时输出 AI 的回复流。

    • GET /status: 检查 DeepSeek 页面是否就绪。

5.2 Quicker 动作流程图

  1. 启动检查: 动作开始时,尝试访问 http://127.0.0.1:54321/status

    • 如果连接失败,说明后台进程未启动。加载 WebView2 DLL,运行 C# 脚本启动 Bridge 窗口,并等待其初始化完成。

    • 如果连接成功,直接进入下一步。

  2. 发送指令: 将用户选中的文本或输入的内容,通过 HTTP POST 发送给后台。

  3. 接收响应:

    • 流式模式(高级): Quicker 支持流式文本输出。动作可以建立长连接,每收到一段文本就更新一次悬浮窗或文本编辑器。

    • 等待模式(简单): 轮询 /read 接口,直到收到 {type: 'done'} 信号,然后一次性输出结果。

  4. 异常处理: 如果 HTTP 请求超时(例如 DeepSeek 正在进行 Cloudflare 验证),Quicker 应弹出提示,并提供一个按钮调用后台进程的 Form.Show() 方法,让用户手动处理。


6. 性能、稳定性与风险评估

6.1 性能影响

WebView2 本质上是一个 Chrome 浏览器进程。

  • 内存占用: 即使只有一个标签页,内存占用也可能达到 200MB - 500MB。对于拥有大内存的现代 PC 不是问题,但在低配机器上可能造成卡顿。

  • CPU 占用: 在“伪后台”模式下,如果 DeepSeek 页面包含复杂的 CSS 动画或 SVG 渲染,CPU 占用率可能偏高。

  • 优化建议: 可以在 JS 中注入代码,在空闲时移除页面上的动画元素,或者在非生成期间将 Opacity 设为 0(虽然有风险,但在非活跃期是安全的)。

6.2 方案的脆弱性(Brittleness)

这是本方案最大的弱点。

  • DOM 变更: DeepSeek 前端团队随时可能修改类名、ID 结构或 React 组件逻辑。这将直接导致选择器失效,脚本无法写入或读取。

  • 维护成本: 开发者需要做好长期维护的心理准备。建议将 JS 注入脚本独立存储(如存放在 Quicker 文本变量或外部文件中),以便在不重新编译 C# 代码的情况下热更新选择器逻辑。

6.3 账号风控风险

虽然 WebView2 是真实浏览器,但频繁的自动化操作(如每秒发送一条消息)仍可能触发 DeepSeek 的速率限制(Rate Limit)或风控。

  • 建议: 模拟人类的阅读延迟。在收到回复后,不要立即发送下一条,留出自然的间隔。不要用于大规模批量抓取,仅作为个人辅助工具使用。

6.4 替代方案对比

特性 WebView2 方案 官方 API 方案
成本 免费(网页版额度)

付费(Token 计费)

功能 完整(含 R1 思考过程、联网搜索、文件上传)

部分(思考过程格式不一,联网需配置)

稳定性 低(依赖 DOM,易失效) 高(接口契约稳定)
实现难度 极高(需处理 IPC、DOM、进程保活) 低(简单的 HTTP 请求)
响应速度 较慢(受限于网页渲染和 JS 执行) 极快(直接数据流)
  

总结建议: 如果用户是重度依赖 DeepSeek R1 的思维链展示,且对成本敏感,本 WebView2 方案是目前最佳的“免费午餐”。但如果是用于生产环境的自动化任务,强烈建议使用官方 API,其稳定性和维护成本的优势远超节省的那一点 Token 费用。

7. 结论

通过 Quicker 结合 WebView2 实现 DeepSeek 网页端中转,在技术图谱上属于**高级自动化(Advanced Automation)**范畴。它巧妙地利用了 Windows 的窗口管理机制和现代浏览器的开放接口,打通了桌面应用与 Web 应用的壁垒。

实施该方案的核心在于克服浏览器对后台进程的资源限制,以及建立一套健壮的 C# 与 JavaScript 通信协议。尽管面临 DOM 结构变更的长期维护风险,但对于追求极致效率和低成本的极客用户而言,这是一个极具价值的解决方案。开发者应重点关注“伪后台”窗口的保活策略以及 React 输入事件的正确模拟,这是决定项目成败的关键细节。

 

github.com
Off-screen rendering with webview2 · Issue #547 · MicrosoftEdge/WebView2Feedback
在新窗口中打开
altova.com
Altova Authentic 2026 Desktop
在新窗口中打开
partitionwizard.com
Unlock the Microsoft Edge WebView2 Runtime & Fix Its Issues - MiniTool Partition Wizard
在新窗口中打开
github.com
Processes are not shut down when windows using a WebView are closed · Issue #1424 · MicrosoftEdge/WebView2Feedback - GitHub
在新窗口中打开
learn.microsoft.com
Win32 C++ WebView2 API conventions - Microsoft Edge Developer documentation
在新窗口中打开
learn.microsoft.com
Call web-side code from native-side code - Microsoft Edge Developer documentation
在新窗口中打开
api-docs.deepseek.com
Reasoning Model (deepseek-reasoner) | DeepSeek API Docs
在新窗口中打开
discuss.huggingface.co
Replicating a real world dev team using multiple AI models, which would you use?. Crazy idea? See inside for more detail
在新窗口中打开
github.com
WebView2 Focus for offscreen rendered content · Issue #3541 · MicrosoftEdge/WebView2Feedback - GitHub
在新窗口中打开
weblog.west-wind.com
Fighting WebView2 Visibility on Initialization - Rick Strahl's Web Log
在新窗口中打开
greasyfork.org
FoldingDeepSeek - Source code - Greasy Fork
在新窗口中打开
greasyfork.org
DeepSeek Native Setter Injector - Source code - Greasy Fork
在新窗口中打开
raw.githubusercontent.com
 
在新窗口中打开
reddit.com
Is there a way to submit a input with TamperMonkey? : r/javascript - Reddit
在新窗口中打开
greasyfork.org
AI Assistant Selector - Source code - Greasy Fork
在新窗口中打开
greasyfork.org
User scripts for deepseek.com - Greasy Fork
在新窗口中打开
github.com
Please allow control-enter to be used instead of clicking the send button #518 - GitHub
在新窗口中打开
api-docs.deepseek.com
Thinking Mode | DeepSeek API Docs
在新窗口中打开
scrape.do
Full Guide to AI Web Scraping With DeepSeek
在新窗口中打开
medium.com
How I Chat with Any Webpage Using DeepSeek and Python | by Woyera - Medium
· {{comment.createTimeStr}}
{{reply.votePoints}}
回复   – {{reply.createTimeStr}}
回复 x