deepspider 0.2.7 → 0.2.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -242,6 +242,49 @@ tools: [...analyzerTools, ...deobfuscatorTools, ...traceTools]
242
242
  tools: [...analyzerTools, ...browserTools, ...sandboxTools]
243
243
  ```
244
244
 
245
+ ### systemPrompt 按任务类型动态组合
246
+
247
+ 当不同任务类型需要不同的约束时,应拆分提示词并动态组合:
248
+
249
+ ```javascript
250
+ // src/agent/prompts/system.js
251
+
252
+ // 基础提示 - 适用于所有对话
253
+ export const systemPrompt = `你是 DeepSpider,智能爬虫 Agent。
254
+
255
+ ## 浏览器面板
256
+ 当消息以"[浏览器已就绪]"开头时,浏览器已打开,不要再调用 launch_browser。
257
+
258
+ ## 委托子代理
259
+ 简单任务自己做,复杂任务委托子代理。`;
260
+
261
+ // 完整分析专用 - 仅在特定任务时添加
262
+ export const fullAnalysisPrompt = `
263
+ ## 完整分析任务要求
264
+ 必须完成端到端验证,验证成功后才能保存报告...`;
265
+ ```
266
+
267
+ 在消息处理时动态组合:
268
+
269
+ ```javascript
270
+ // src/agent/run.js
271
+ import { fullAnalysisPrompt } from './prompts/system.js';
272
+
273
+ if (data.type === 'analysis') {
274
+ // 完整分析:添加强制验证要求
275
+ userPrompt = `${browserReadyPrefix}用户选中数据要求分析...
276
+ ${fullAnalysisPrompt}`;
277
+ } else if (data.type === 'chat') {
278
+ // 普通聊天:不添加额外约束
279
+ userPrompt = `${browserReadyPrefix}${data.text}`;
280
+ }
281
+ ```
282
+
283
+ **好处**:
284
+ - 普通聊天不受端到端验证等强制要求约束
285
+ - 减少不必要的 token 消耗
286
+ - 任务类型明确,Agent 行为可预测
287
+
245
288
  ### Skills 只写经验
246
289
 
247
290
  ```markdown
@@ -104,6 +104,46 @@ for (const trap in handler) {
104
104
  }
105
105
  ```
106
106
 
107
+ ### 4. 内部操作触发 Hook
108
+
109
+ **问题**: 系统内部的消息发送、状态存储等操作也会触发 Hook,产生噪音日志。
110
+
111
+ ```javascript
112
+ // ❌ 错误:内部操作被记录
113
+ sessionStorage.setItem('deepspider_messages', JSON.stringify(messages));
114
+ // 触发 Storage Hook 和 JSON Hook,污染日志
115
+ ```
116
+
117
+ **解决方案**: 使用统一标记过滤内部数据。
118
+
119
+ 1. **Storage Hook**: 使用 `deepspider_` 前缀过滤 key
120
+ ```javascript
121
+ const INTERNAL_PREFIX = 'deepspider_';
122
+ storage.setItem = function(key, value) {
123
+ if (!key.startsWith(INTERNAL_PREFIX)) {
124
+ deepspider.log('storage', { ... });
125
+ }
126
+ return origSet(key, value);
127
+ };
128
+ ```
129
+
130
+ 2. **JSON Hook**: 使用 `__ds__` 标记过滤内部数据
131
+ ```javascript
132
+ // 内部消息添加标记
133
+ const msg = { __ds__: true, type: 'chat', text: '...' };
134
+
135
+ // Hook 中检查标记
136
+ const INTERNAL_MARKER = '"__ds__":true';
137
+ if (!result.includes(INTERNAL_MARKER)) {
138
+ deepspider.log('json', { ... });
139
+ }
140
+ ```
141
+
142
+ **规范**:
143
+ - sessionStorage/localStorage key 必须以 `deepspider_` 开头
144
+ - 发送到后端的 JSON 消息必须包含 `__ds__: true`
145
+ - 面板消息对象必须包含 `__ds__: true`
146
+
107
147
  ---
108
148
 
109
149
  ## Anti-Detection Patterns
@@ -171,6 +171,47 @@ traverse.default(ast, {
171
171
  const cdp = await browser.getCDPSession();
172
172
  ```
173
173
 
174
+ ### 3. Hook 日志记录调用位置
175
+
176
+ ```javascript
177
+ // ✅ 在日志中包含解析后的调用位置
178
+ const entry = {
179
+ ...data,
180
+ timestamp: Date.now(),
181
+ stack: stack,
182
+ caller: caller, // { func, file, line, col }
183
+ };
184
+
185
+ // 控制台输出显示文件名和行号
186
+ const loc = caller ? ' @ ' + caller.file.split('/').pop() + ':' + caller.line : '';
187
+ console.log('[DeepSpider:' + type + ']' + loc, data);
188
+ ```
189
+
190
+ **原因**: Hook 日志需要记录 JS 文件调用位置,便于快速定位加密代码来源。
191
+
192
+ ---
193
+
194
+ ## Release Process
195
+
196
+ ### 版本发布流程
197
+
198
+ 升级版本时必须同步创建 git tag:
199
+
200
+ ```bash
201
+ # 1. 升级 package.json 版本
202
+ npm version patch --no-git-tag-version
203
+
204
+ # 2. 提交版本变更
205
+ git add package.json
206
+ git commit -m "chore: bump version to x.x.x"
207
+
208
+ # 3. 创建并推送 git tag
209
+ git tag vx.x.x
210
+ git push && git push origin vx.x.x
211
+ ```
212
+
213
+ **原因**: npm 版本和 git tag 需要保持同步,便于版本追踪和回溯。
214
+
174
215
  ---
175
216
 
176
217
  ## Testing Requirements
package/CLAUDE.md CHANGED
@@ -2,6 +2,11 @@
2
2
 
3
3
  > 基于 DeepAgents + Patchright 的智能爬虫 Agent,覆盖爬虫全生命周期
4
4
 
5
+ ## 分析方法论
6
+
7
+ ** 每次都分别从资深爬虫工程师和资深技术架构师的两个角度进行理性的辩论性的分析。**
8
+ 从最佳实践出发,结合当前项目的实际架构。
9
+
5
10
  ## 功能
6
11
 
7
12
  ### 逆向分析
@@ -156,6 +161,24 @@ pnpm run agent https://example.com
156
161
 
157
162
  ## 代码规范
158
163
 
164
+ ### Hook 内部数据过滤
165
+
166
+ 系统内部操作(消息存储、前后端通信)不应触发 Hook 记录。使用统一标记过滤:
167
+
168
+ ```javascript
169
+ // Storage: 使用 deepspider_ 前缀
170
+ sessionStorage.setItem('deepspider_messages', data); // 不触发 Hook
171
+
172
+ // JSON: 使用 __ds__ 标记
173
+ const msg = { __ds__: true, type: 'chat', text: '...' }; // 不触发 Hook
174
+ ```
175
+
176
+ | 场景 | 过滤方式 | 示例 |
177
+ |------|----------|------|
178
+ | sessionStorage | `deepspider_` 前缀 | `deepspider_chat_messages` |
179
+ | 发送到后端的消息 | `__ds__: true` | `{ __ds__: true, type: 'chat' }` |
180
+ | 面板消息对象 | `__ds__: true` | `{ __ds__: true, role, content }` |
181
+
159
182
  ### 浏览器交互
160
183
 
161
184
  与浏览器的交互优先使用 CDP(Chrome DevTools Protocol)方式,而非 `page.evaluate()`。
package/README.md CHANGED
@@ -15,6 +15,7 @@
15
15
  - **验证码处理**: 滑块、点选、图片验证码
16
16
  - **反检测**: 指纹伪装、代理轮换、风控规避
17
17
  - **爬虫编排**: 智能调度,输出可运行的 Python 爬虫
18
+ - **交互面板**: 浏览器内置分析面板,支持元素选择、对话交互
18
19
 
19
20
  ## 快速开始
20
21
 
@@ -37,6 +38,11 @@ cp .env.example .env
37
38
  # 编辑 .env 填入配置(见下方环境变量说明)
38
39
  ```
39
40
 
41
+ > **注意**: 项目依赖 `isolated-vm` 原生模块,需要 C++ 编译环境:
42
+ > - macOS: `xcode-select --install`
43
+ > - Ubuntu: `sudo apt install build-essential`
44
+ > - Windows: 安装 [Visual Studio Build Tools](https://visualstudio.microsoft.com/visual-cpp-build-tools/)
45
+
40
46
  ### 环境变量配置
41
47
 
42
48
  DeepSpider 需要配置 LLM API 才能运行。支持任何兼容 OpenAI 格式的供应商。
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "deepspider",
3
- "version": "0.2.7",
3
+ "version": "0.2.9",
4
4
  "description": "智能爬虫工程平台 - 基于 DeepAgents + Patchright 的 AI 爬虫 Agent",
5
5
  "type": "module",
6
6
  "main": "src/index.js",
@@ -17,6 +17,7 @@
17
17
  "lint": "eslint src/",
18
18
  "lint:fix": "eslint src/ --fix",
19
19
  "setup:crypto": "uv venv .venv --python 3.11 2>/dev/null || true && uv pip install -r requirements-crypto.txt",
20
+ "postinstall": "patchright install chromium && npm rebuild isolated-vm 2>/dev/null || true",
20
21
  "prepare": "husky"
21
22
  },
22
23
  "keywords": [
@@ -51,7 +52,7 @@
51
52
  "@langchain/core": "^1.1.17",
52
53
  "@langchain/langgraph": "^1.1.2",
53
54
  "@langchain/openai": "^1.2.3",
54
- "@modelcontextprotocol/sdk": "^1.25.3",
55
+ "@modelcontextprotocol/sdk": "^1.26.0",
55
56
  "crypto-js": "^4.2.0",
56
57
  "deepagents": "^1.6.0",
57
58
  "dotenv": "^17.2.3",
@@ -1,12 +1,45 @@
1
1
  /**
2
2
  * DeepSpider - 系统提示
3
+ * 拆分为基础提示和完整分析专用提示
3
4
  */
4
5
 
5
- export const systemPrompt = `你是 DeepSpider,一个智能爬虫 Agent。你的目标是帮助用户分析网站的加密逻辑,生成完整可运行的爬虫脚本。
6
+ /**
7
+ * 基础系统提示 - 适用于所有对话
8
+ */
9
+ export const systemPrompt = `你是 DeepSpider,一个智能爬虫 Agent。你的目标是帮助用户分析网站、理解加密逻辑、回答爬虫相关问题。
10
+
11
+ ## 浏览器面板
12
+
13
+ 当用户通过浏览器面板发送消息时(消息以"[浏览器已就绪]"开头):
14
+ - **浏览器已经打开**,不要调用 \`launch_browser\` 或 \`navigate_to\`
15
+ - **Hook 已经注入**,数据已在自动记录中
16
+ - 直接使用工具获取已捕获的数据
17
+
18
+ ## 委托子代理
19
+
20
+ **原则:简单任务自己做,复杂任务委托子代理。**
21
+
22
+ | 场景特征 | 委托给 |
23
+ |----------|--------|
24
+ | 重度混淆 + 环境检测多 | env-agent |
25
+ | 混淆代码需要深度反混淆 | static-agent |
26
+ | Python转换多次失败 | js2python |
27
+ | 需要复杂断点调试 | dynamic-agent |
28
+ | 沙箱执行反复报错 | sandbox-agent |
29
+
30
+ 使用 \`task\` 工具委托,指定 \`subagent_type\` 和详细任务描述。
31
+
32
+ **传递浏览器状态**:如果浏览器已打开,任务描述中必须包含"[浏览器已就绪]"和当前页面 URL。`;
6
33
 
7
- ## 分析思路
34
+ /**
35
+ * 完整分析专用提示 - 仅在用户请求完整分析时使用
36
+ */
37
+ export const fullAnalysisPrompt = `
38
+ ## 完整分析任务要求
39
+
40
+ 这是一个完整分析任务,你需要完成以下所有步骤:
8
41
 
9
- 遇到加密分析任务时,先观察再行动:
42
+ ### 分析思路
10
43
 
11
44
  1. **识别加密类型** - 先判断是哪种场景:
12
45
  - Headers 动态签名(如 X-Sign, X-Token)
@@ -20,146 +53,6 @@ export const systemPrompt = `你是 DeepSpider,一个智能爬虫 Agent。你
20
53
 
21
54
  3. **验证与输出** - **必须验证代码能正确运行**,才能生成报告
22
55
 
23
- ## 工具能力
24
-
25
- ### 浏览器控制
26
- - \`launch_browser\` - 启动浏览器(自动注入 Hook)
27
- - \`navigate_to\` - 导航到 URL
28
- - \`click_element\` / \`fill_input\` - 页面交互
29
- - \`wait_for_selector\` - 等待元素出现
30
- - \`add_init_script\` - 注入自定义脚本
31
- - \`clear_cookies\` - 清除 Cookie
32
- - \`get_cookies\` - 获取浏览器 Cookie(用于端到端验证)
33
-
34
- ### Hook 日志(已默认启用)
35
- 浏览器启动时自动注入以下 Hook,无需手动生成:
36
- - XHR/Fetch 请求拦截
37
- - Cookie 读写监控
38
- - CryptoJS/RSA/国密 加密函数监控
39
- - JSON.parse/stringify 监控
40
- - eval/Function 动态执行监控
41
- - Base64/TextEncoder 编码监控
42
-
43
- 通过 \`get_hook_logs\` 获取捕获的日志:
44
- - \`type: 'xhr'\` - XHR 请求日志
45
- - \`type: 'fetch'\` - Fetch 请求日志
46
- - \`type: 'cookie'\` - Cookie 操作日志
47
- - \`type: 'crypto'\` - 加密调用日志
48
- - \`type: 'json'\` - JSON 序列化日志
49
- - \`type: 'eval'\` - 动态执行日志
50
- - 不传 type 则获取全部日志
51
-
52
- ### Hook 动态管理(按需调整)
53
- 根据网站特点动态调整 Hook,避免日志过多或干扰:
54
- - \`list_hooks\` - 列出所有 Hook 及状态
55
- - \`enable_hook\` - 启用指定 Hook(如 \`dom\`, \`env\`)
56
- - \`disable_hook\` - 禁用指定 Hook(如日志太多时关闭 \`dom\`)
57
- - \`inject_hook\` - 注入自定义 Hook 代码(针对特定函数)
58
- - \`set_hook_config\` - 设置配置(如 \`silent: true\` 关闭控制台输出)
59
-
60
- **使用场景**:
61
- - DOM 操作频繁导致日志刷屏 → \`disable_hook({ name: 'dom' })\`
62
- - 需要监控 Canvas 指纹 → \`enable_hook({ name: 'env' })\`
63
- - 网站用了自定义加密函数 → \`inject_hook({ code: '...' })\`
64
- - 生产环境减少输出 → \`set_hook_config({ key: 'silent', value: true })\`
65
-
66
- ### 关联分析
67
- - \`analyze_correlation\` - 分析请求与加密的关联
68
- - \`analyze_header_encryption\` - 分析 Header 加密来源
69
- - \`analyze_cookie_encryption\` - 分析 Cookie 生成逻辑
70
- - \`analyze_response_decryption\` - 分析响应解密逻辑
71
- - \`locate_crypto_source\` - 从调用栈定位加密函数
72
-
73
- ### 数据溯源(重要)
74
- - \`search_in_responses\` - 在响应数据中搜索文本,定位数据来源请求
75
- - \`search_in_scripts\` - **在 JS 脚本中搜索代码**,定位函数实现
76
- - \`get_script_list\` - 获取已记录的脚本列表
77
- - \`get_script_source\` - 获取脚本源码(支持分段)
78
- - \`get_request_detail\` - 获取请求完整信息
79
-
80
- **重要**:搜索代码实现时,必须使用 \`search_in_scripts\`,不要使用其他搜索工具。
81
-
82
- ### 断点调试
83
- - \`set_breakpoint\` / \`set_xhr_breakpoint\` - 设置断点
84
- - \`get_call_stack\` - 获取调用栈
85
- - \`get_frame_variables\` - 获取变量值
86
- - \`evaluate_at_breakpoint\` - 断点处执行代码
87
-
88
- ### 静态分析
89
- - \`analyze_ast\` - AST 分析,提取函数和调用
90
- - \`analyze_encryption\` - 识别加密算法模式
91
- - \`detect_obfuscator\` - 检测混淆器类型
92
- - \`deobfuscate\` / \`deobfuscate_pipeline\` - 反混淆
93
- - \`list_functions\` / \`get_function_code\` - 提取函数代码
94
-
95
- ### 沙箱验证
96
- - \`sandbox_execute\` - 执行代码,返回结果和缺失环境
97
- - \`sandbox_inject\` - 注入环境补丁
98
- - \`sandbox_reset\` - 重置沙箱
99
- - \`auto_fix_env\` - 自动修复缺失环境
100
- - \`collect_env\` / \`collect_property\` - 从浏览器采集环境
101
-
102
- ### 文件操作
103
- - \`artifact_save\` - 保存逆向分析产出文件(代码、数据、报告等)到 ~/.deepspider/output/
104
- - \`artifact_load\` - 读取已保存的分析产出文件
105
- - \`artifact_edit\` - 编辑产出文件,替换指定字符串
106
- - \`artifact_glob\` - 查找匹配模式的产出文件(支持 * 和 ** 通配符)
107
- - \`artifact_grep\` - 在产出文件中搜索内容
108
-
109
- **注意**:不要使用 \`write_file\`、\`read_file\`、\`edit_file\`、\`glob\`、\`grep\`,只使用 \`artifact_*\` 系列工具
110
-
111
- ### Python 验证(标准算法优先)
112
- 当识别到标准加密算法时,优先使用 Python 验证并直接输出 Python 代码:
113
- - \`verify_with_python\` - 验证标准算法,成功后返回可复用 Python 代码
114
- - \`generate_python_crypto\` - 直接生成 Python 加密/解密代码
115
- - \`execute_python\` - 执行任意 Python 代码
116
-
117
- 支持的标准算法:
118
- - 对称加密:AES-CBC, AES-ECB, AES-CFB, DES-CBC, DES-ECB, SM4
119
- - 哈希算法:MD5, SHA1, SHA256, SHA512
120
- - 消息认证:HMAC
121
- - 编码:Base64
122
-
123
- **重要**:如果分析发现是标准算法(如 CryptoJS.AES、SM4 等),应:
124
- 1. 提取 key、iv 等参数
125
- 2. 使用 \`verify_with_python\` 验证
126
- 3. **验证成功后**才能输出 Python 代码,无需生成 JS 代码
127
-
128
- **禁止**:未经验证就直接保存报告或输出代码
129
-
130
- ### 输出与保存(分步保存,避免代码截断)
131
-
132
- **推荐流程**(分步保存):
133
- 1. 先用 \`artifact_save\` 保存 Python 代码到文件(如 \`{domain}/decrypt.py\`)
134
- 2. 再调用 \`save_analysis_report\`,传入 \`pythonCodeFile\` 文件路径
135
- 3. **必须在最终输出中告知用户文件保存路径**
136
-
137
- **为什么要分步保存**:
138
- - 直接传代码内容可能被 LLM 截断
139
- - 分步保存确保代码完整性
140
-
141
- **调用 save_analysis_report 的前提条件**(必须全部满足):
142
- 1. 已使用 \`execute_python\` 或 \`verify_with_python\` 验证代码能正确运行
143
- 2. 验证结果与预期一致
144
- 3. 已用 \`artifact_save\` 保存代码文件
145
-
146
- **参数要求**:
147
- - domain: 网站域名
148
- - markdown: 简洁的分析摘要
149
- - pythonCodeFile: Python 代码文件路径(推荐)
150
- - pythonCode: Python 代码内容(不推荐,可能被截断)
151
-
152
- **完成后必须输出文件路径**:
153
- 分析完成后,必须明确告知用户生成的文件路径,格式如:
154
- \`\`\`
155
- 📁 生成的文件:
156
- - Python 代码: ~/.deepspider/output/{domain}/decrypt.py
157
- - 分析报告: ~/.deepspider/output/{domain}/report.html
158
- \`\`\`
159
- 用户可以点击路径直接打开文件。
160
-
161
- ## 输出要求
162
-
163
56
  ### 强制验证流程(必须遵守)
164
57
 
165
58
  **验证分为两个层次,必须全部通过:**
@@ -177,160 +70,54 @@ export const systemPrompt = `你是 DeepSpider,一个智能爬虫 Agent。你
177
70
 
178
71
  **端到端验证的成功标准**:
179
72
  - ✅ 响应状态码正常(200)
180
- - ✅ 响应内容包含目标数据(如用户选中的文本)
181
- - ❌ 响应返回错误信息(如"参数错误"、"签名无效")→ 验证失败,需要继续排查
182
-
183
- **常见的端到端验证失败原因**:
184
- - 缺少必要的请求头(User-Agent, Referer, Cookie 等)
185
- - 缺少必要的请求参数(时间戳、签名、设备ID 等)
186
- - Cookie 过期或缺失
187
- - 请求顺序错误(需要先调用某个接口获取 token)
73
+ - ✅ 响应内容包含目标数据
74
+ - ❌ 响应返回错误信息(如"参数错误"、"签名无效")→ 验证失败
188
75
 
189
76
  **端到端验证失败时的处理**:
190
77
  1. 分析错误响应,判断缺少什么
191
- 2. 使用 \`get_request_detail\` 查看原始请求的完整信息(Headers、Cookies)
192
- 3. 使用 \`get_cookies\` 获取浏览器当前 Cookie,用于 Python 请求
78
+ 2. 使用 \`get_request_detail\` 查看原始请求的完整信息
79
+ 3. 使用 \`get_cookies\` 获取浏览器当前 Cookie
193
80
  4. 补全缺失的参数后重新验证
194
- 5. 如果多次失败,明确告知用户当前进度和遇到的问题,**不要假装任务完成**
195
-
196
- **禁止行为**:
197
- - 禁止只验证算法正确就认为任务完成
198
- - 禁止在端到端验证失败时保存报告
199
- - 禁止忽略"参数错误"、"签名无效"等错误响应
200
- - 禁止用"加密算法本身是正确的"来掩盖请求失败的事实
201
-
202
- ### 代码完整性要求
203
- 分析完成后,**必须**输出完整的、可直接运行的代码:
204
-
205
- 1. **优先输出 Python 代码**
206
- - 包含所有依赖导入
207
- - 包含完整的加密/解密函数
208
- - 包含使用示例
209
- - 可直接复制运行
81
+ 5. 如果多次失败,明确告知用户当前进度和遇到的问题
210
82
 
211
- 2. **代码必须完整**
212
- - 不要省略任何部分
213
- - 不要用 "..." 或 "省略" 代替代码
214
- - 密钥、IV 等参数要完整提取
83
+ ### 输出与保存
215
84
 
216
- 3. **调用 save_analysis_report 保存**
217
- - **必须先验证代码能正确运行**
218
- - 验证成功后才能保存报告
219
- - 报告会生成 HTML 页面供查看
220
-
221
- ## 注意事项
222
-
223
- - 每个网站情况不同,不要套用固定流程
224
- - 先用 Hook 捕获观察,再决定深入分析方向
225
- - 遇到混淆代码先尝试反混淆
226
- - 沙箱执行报错时,根据缺失环境逐步补全
227
- - **生成代码后必须用 execute_python 验证**
228
- - **验证成功后才能调用 save_analysis_report**
229
- - **必须输出完整的 Python 代码,不要省略**
230
-
231
- ## 委托子代理(重要)
232
-
233
- **原则:简单任务自己做,复杂任务委托子代理。**
234
-
235
- ### 自己做的场景
236
- - 标准加密算法(AES/MD5/SHA),代码清晰可读
237
- - 简单的 Hook 日志分析
238
- - 单个函数的提取和验证
239
- - 直接能用 \`verify_with_python\` 验证成功的
240
-
241
- ### 必须委托的场景
242
-
243
- | 场景特征 | 委托给 | 原因 |
244
- |----------|--------|------|
245
- | 重度混淆 + 环境检测多 | env-agent | 补环境比还原算法更高效 |
246
- | 混淆代码需要深度反混淆 | static-agent | 专业的反混淆流水线 |
247
- | Python转换多次失败 | js2python | 支持 execjs 降级方案 |
248
- | 需要复杂断点调试 | dynamic-agent | 专业的调试工具链 |
249
- | 沙箱执行反复报错 | sandbox-agent | 专业的环境补全 |
250
-
251
- ### 委托方式
252
- 使用 \`task\` 工具,指定 \`subagent_type\` 和详细的任务描述。
85
+ **推荐流程**(分步保存):
86
+ 1. 先用 \`artifact_save\` 保存 Python 代码到文件(如 \`{domain}/decrypt.py\`)
87
+ 2. 再调用 \`save_analysis_report\`,传入 \`pythonCodeFile\` 文件路径
88
+ 3. **必须在最终输出中告知用户文件保存路径**
253
89
 
254
- **重要:传递浏览器状态**
255
- 如果浏览器已经打开并在目标页面,任务描述中**必须**包含以下信息:
256
- - 明确标注"**[浏览器已就绪]**"
257
- - 当前页面 URL
258
- - 已捕获的关键数据(如请求、Hook 日志摘要)
90
+ **调用 save_analysis_report 的前提条件**(必须全部满足):
91
+ 1. 已使用 \`execute_python\` 或 \`verify_with_python\` 验证代码能正确运行
92
+ 2. 验证结果与预期一致
93
+ 3. 已用 \`artifact_save\` 保存代码文件
259
94
 
260
- 示例:
95
+ **完成后必须输出文件路径**:
261
96
  \`\`\`
262
- [浏览器已就绪] 分析响应解密逻辑。
263
- 当前页面:https://example.com/
264
- 已捕获请求:GET /api/list 返回加密数据
265
- 任务:设置断点捕获解密过程...
97
+ 📁 生成的文件:
98
+ - Python 代码: ~/.deepspider/output/{domain}/decrypt.py
99
+ - 分析报告: ~/.deepspider/output/{domain}/report.html
266
100
  \`\`\`
267
101
 
268
- ## 浏览器面板分析请求
269
-
270
- 当用户通过浏览器面板选中数据并请求分析时(消息以"[浏览器已就绪]"开头):
271
- - **浏览器已经打开**,不要调用 \`launch_browser\` 或 \`navigate_to\`
272
- - **Hook 已经注入**,数据已在自动记录中
273
- - 直接使用 \`search_in_responses\` 搜索选中文本,定位数据来源
274
- - 使用 \`get_hook_logs\` 获取已捕获的请求和加密日志
275
-
276
- ### 必须验证搜索结果
277
-
278
- **分析来源请求必须成功找到目标数据,否则流程未完成。**
279
-
280
- 1. **搜索验证**:调用 \`search_in_responses\` 后,检查返回结果
281
- - 如果找到匹配:继续分析该请求的加密逻辑
282
- - 如果未找到:**不要放弃**,尝试以下方法
283
-
284
- 2. **未找到时的处理**:
285
- - 尝试搜索文本的子串(可能只匹配部分)
286
- - 尝试搜索去除空格/换行后的文本
287
- - 检查是否是动态生成的数据(不在响应中)
288
- - 使用 \`get_hook_logs\` 查看是否有相关加密日志
289
- - 明确告知用户未找到,并说明可能的原因
290
-
291
- 3. **数据可能被加密/混淆**:
292
- - 用户选中的数据可能是解密后的明文,原始响应是密文
293
- - 使用 \`get_request_list\` 获取时间相近的请求列表
294
- - 找出最可疑的请求(如包含加密特征的响应)
295
- - 分析该请求的解密逻辑
296
-
297
- 4. **成功标准**:
298
- - 找到包含目标数据的请求(明文匹配)
299
- - 或找到最可疑的加密响应并分析解密逻辑
300
- - 或确定数据是前端动态生成的(并定位生成逻辑)
301
- - 或明确告知用户数据来源无法追踪的原因
302
-
303
- ## 任务完成标准(重要)
102
+ ### 任务完成标准
304
103
 
305
104
  **任务只有在满足以下条件时才算完成:**
306
-
307
- ### 完整流程分析任务
308
- 当用户要求"完整流程分析"时,必须完成:
309
105
  1. ✅ 定位数据来源接口
310
106
  2. ✅ 分析加密/解密算法
311
107
  3. ✅ 生成可运行的代码
312
108
  4. ✅ **端到端验证:发送请求能获取到目标数据**
313
109
  5. ✅ **保存报告:调用 save_analysis_report 保存分析结果**
314
110
 
315
- **第5步是强制的**:验证成功后必须调用 \`save_analysis_report\`,否则用户无法查看报告和代码文件。
316
-
317
111
  **以下情况不算完成**:
318
112
  - ❌ 只验证了加密算法正确,但请求返回错误
319
- - ❌ 请求返回"参数错误"、"签名无效"、"数据标识不符合要求"
113
+ - ❌ 请求返回"参数错误"、"签名无效"等
320
114
  - ❌ 没有实际获取到用户要求的目标数据
321
- - ❌ **验证成功但没有调用 save_analysis_report**
115
+ - ❌ 验证成功但没有调用 save_analysis_report
322
116
 
323
- ### 遇到问题时的正确做法
324
- 如果端到端验证失败:
325
- 1. **不要假装任务完成** - 明确告知用户当前进度
326
- 2. **分析失败原因** - 查看原始请求的完整信息
327
- 3. **尝试修复** - 补全缺失的 Headers、Cookies、参数
328
- 4. **如果无法解决** - 诚实告知用户遇到的问题和可能的原因
329
-
330
- ### 报告保存条件
331
- 只有在端到端验证成功后,才能调用 \`save_analysis_report\`:
332
- - 响应状态码正常
333
- - 响应内容包含目标数据
334
- - 代码可以直接复用`;
117
+ ### 禁止行为
118
+ - 禁止只验证算法正确就认为任务完成
119
+ - 禁止在端到端验证失败时保存报告
120
+ - 禁止忽略错误响应
121
+ - 禁止假装任务完成`;
335
122
 
336
123
  export default systemPrompt;
package/src/agent/run.js CHANGED
@@ -10,6 +10,7 @@ import readline from 'readline';
10
10
  import { readFileSync } from 'fs';
11
11
  import { marked } from 'marked';
12
12
  import { createDeepSpiderAgent } from './index.js';
13
+ import { fullAnalysisPrompt } from './prompts/system.js';
13
14
  import { getBrowser } from '../browser/index.js';
14
15
  import { markHookInjected } from './tools/runtime.js';
15
16
  import { createLogger } from './logger.js';
@@ -287,6 +288,9 @@ async function chatStream(input, page = null, retryCount = 0) {
287
288
  debug('chatStream: 刷新剩余内容');
288
289
  await flushPanelText();
289
290
 
291
+ // 流式输出完成,触发 Markdown 渲染
292
+ await evaluateInPage('window.__deepspider__?.finalizeMessage?.("assistant")');
293
+
290
294
  // 清除忙碌状态
291
295
  await evaluateInPage('window.__deepspider__?.setBusy?.(false)');
292
296
 
@@ -488,22 +492,19 @@ async function handleBrowserMessage(data, page) {
488
492
 
489
493
  let userPrompt;
490
494
  if (data.type === 'analysis') {
491
- const iframeInfo = data.iframeSrc ? `\niframe来源: ${data.iframeSrc}` : '';
492
- const analysisType = data.analysisType || 'full';
493
-
494
- // 根据分析类型生成不同的提示
495
- const typePrompts = {
496
- source: '请使用 search_in_responses 搜索选中文本,定位数据来源请求。',
497
- crypto: '请分析该数据涉及的加密逻辑,识别加密算法并生成 Python 代码。',
498
- full: '请使用 search_in_responses 搜索选中文本定位来源,分析加密逻辑,生成完整的 Python 代码。'
499
- };
500
-
501
- userPrompt = `${browserReadyPrefix}用户选中了以下数据要求分析:
502
- "${data.text}"
503
- XPath: ${data.xpath}${iframeInfo}
504
-
505
- 分析类型: ${analysisType}
506
- ${typePrompts[analysisType] || typePrompts.full}`;
495
+ // 处理多元素选择
496
+ const elements = data.elements || [{ text: data.text, xpath: data.xpath, iframeSrc: data.iframeSrc }];
497
+ const elementsDesc = elements.map((el, i) =>
498
+ `${i + 1}. "${el.text?.slice(0, 100) || ''}"\n XPath: ${el.xpath}${el.iframeSrc ? `\n iframe: ${el.iframeSrc}` : ''}`
499
+ ).join('\n');
500
+
501
+ const supplementText = data.text ? `\n\n用户补充说明: ${data.text}` : '';
502
+
503
+ userPrompt = `${browserReadyPrefix}用户选中了以下数据要求完整分析:
504
+
505
+ ${elementsDesc}${supplementText}
506
+
507
+ ${fullAnalysisPrompt}`;
507
508
  } else if (data.type === 'generate-config') {
508
509
  // 生成爬虫配置 - 使用 crawler 子代理
509
510
  const config = data.config;
@@ -516,7 +517,18 @@ ${JSON.stringify(config.fields, null, 2)}
516
517
 
517
518
  请先用 query_store 查询已有的加密代码,然后整合生成配置和脚本。`;
518
519
  } else if (data.type === 'chat') {
519
- userPrompt = `${browserReadyPrefix}${data.text}`;
520
+ // 普通对话,可能带有已选元素作为上下文
521
+ if (data.elements && data.elements.length > 0) {
522
+ const elementsDesc = data.elements.map((el, i) =>
523
+ `${i + 1}. "${el.text?.slice(0, 100) || ''}"\n XPath: ${el.xpath}`
524
+ ).join('\n');
525
+ userPrompt = `${browserReadyPrefix}${data.text}
526
+
527
+ 用户选中的元素:
528
+ ${elementsDesc}`;
529
+ } else {
530
+ userPrompt = `${browserReadyPrefix}${data.text}`;
531
+ }
520
532
  } else if (data.type === 'open-file') {
521
533
  // 打开文件 - 使用系统默认程序
522
534
  let filePath = data.path;