feat(web-access): 迁移到内置受管浏览器工具(v2.1.0) (#72)

## 变更说明 / Description

### 中文

客户端 v10.0.98(desirecore/desirecore#1596)停用了旧的 `BrowserListTabs` /
`BrowserNavigate` / `BrowserEval` / `BrowserClick` / `BrowserScreenshot`
/ `BrowserScroll` / `BrowserSetFiles` / `BrowserCloseTab` 及其 cdp-proxy
后端,调用会直接返回「该旧 BrowserXxx/cdp-proxy 入口已停用」。而 web-access v2.0.2 的
`provides.tools` 仍声明这批工具——技能激活后注入的是一组必然失败的工具。

本次把 `provides.tools` 换成统一浏览器工具,并同步正文与参考文档:

- `provides.tools`:`BrowserManage` / `BrowserSnapshot` / `BrowserAct` /
`BrowserImport` / `BrowserShare` + 保留 `SitePatternRead` /
`SitePatternWrite` / `LocalBookmarks`
- 中英文 SKILL 正文同步改写(L0 / 能力描述 / 决策树 / 四层策略表 / L3-fast 速查 / 反模式)
- `references/browser-tools.md` 整篇重写为新 API + 实测边界
- 5 份站点经验(小红书 / B站 / 微博 / 知乎 / 飞书)的流程改用新工具
- 版本 2.0.2 → 2.1.0,`updated_at` 更新,i18n `source_hash` 重算

**L3-fast 的定位相应收窄**:内置浏览器负责「到达 + 交互 + 截图 + 隔离」,抽取长正文仍回落 Jina
Reader(公开页)或 Playwright(登录态)——理由见下方实测。

### English

Client v10.0.98 retired the legacy `BrowserXxx` tools and the cdp-proxy
behind them, so web-access v2.0.2 was injecting a set of tools that
always fail. This PR migrates `provides.tools` to the unified browser
tools and rewrites the body, the browser-tools reference, and the five
site-pattern playbooks accordingly. L3-fast is re-scoped to
navigation/interaction/screenshots; bulk text extraction still falls
back to Jina Reader or Playwright.

## 测试方式 / Test Plan

在客户端 v10.0.98 + `electron-embedded` Provider 上实测:

- [x] `provides.tools` 里 8 个工具 ID 全部在 builtin registry 中存在
- [x] 把本 PR 的技能装进 dev 实例,带 `skillIds:['web-access']` 驱动智能体:真实调用
`BrowserManage(create_space)` → `BrowserManage(start_session)` →
`BrowserAct(tab.navigate)` → `BrowserManage(close_session)`,全部 success
- [x] `scripts/i18n/validate-i18n.py` 全仓库通过(中英文标题数一致、source_hash 一致)

文档中记录的边界均来自实测,而非推测:

| 边界 | 实测现象 |
|------|---------|
| 截图前必须 `tab.activate` | 标签页默认停在 `(-10000,-10000,1x1)`,直接截图卡满 30s
deadline 并触发 `browser.host.gone`,之后全部 `BROWSER_TAB_HOST_NOT_FOUND` |
| `page.evaluate` 不是取文通道 | 每次调用需人工审批;字符串/对象返回值被替换为
`[REDACTED:browser-runtime-value]`,仅 number/boolean/null 穿透 |
| `accessibility` 快照真实页面不可用 | example.com 正常返回 StaticText;维基百科条目一律
`BROWSER_RESULT_TOO_LARGE`(2 MB 上限,且 `depth` 参数被宿主忽略) |
| `semantic` 快照不含正文 | 只列 button / input / a 等可交互元素 |

## 风险与回滚 / Risk and rollback

- 纯技能内容变更,无脚本或清单结构改动
- 需要客户端 v10.0.98+;旧客户端装到本版会拿到一组不存在的工具名(旧客户端上原本那批工具也已失效,不构成回退)
- 回滚即 revert 本 PR
This commit is contained in:
2026-08-06 00:49:35 +08:00
committed by yi-ge
parent 413f2cc00b
commit af4176bbd7
8 changed files with 281 additions and 186 deletions

View File

@@ -5,16 +5,18 @@ description: >-
— searching for current information, fetching public web pages, browsing
login-gated sites (微博/小红书/B站/飞书/Twitter), comparing products,
researching topics, gathering documentation, or summarizing news.
This skill orchestrates three complementary layers: (1) WebSearch + WebFetch
This skill orchestrates four complementary layers: (1) WebSearch + WebFetch
for public pages, (2) Jina Reader as the default token-optimization layer for
heavy/JS-rendered pages, and (3) Chrome DevTools Protocol (CDP) via Python
Playwright for login-gated sites that require the user's existing browser
session. Always cite source URLs. Use when 用户提到 联网搜索、上网查、
heavy/JS-rendered pages, (3) the governed built-in browser (isolated
BrowserSpace + Cookie import) to reach and interact with login-gated sites,
and (4) Chrome DevTools Protocol via Python Playwright as the fallback for
bulk text extraction and complex automation. Always cite source URLs.
Use when 用户提到 联网搜索、上网查、
查资料、抓取网页、研究、调研、最新资讯、文档查询、对比、竞品、技术文档、
新闻、网址、URL、找一下、搜一下、查一下、小红书、B站、微博、飞书、Twitter、
推特、X、知乎、公众号、已登录、登录状态。
license: Complete terms in LICENSE.txt
version: 2.0.2
version: 2.1.0
type: procedural
risk_level: low
status: enabled
@@ -29,20 +31,17 @@ tags:
- playwright
provides:
tools:
- BrowserListTabs
- BrowserNavigate
- BrowserEval
- BrowserClick
- BrowserScreenshot
- BrowserScroll
- BrowserSetFiles
- BrowserCloseTab
- BrowserManage
- BrowserSnapshot
- BrowserAct
- BrowserImport
- BrowserShare
- SitePatternRead
- SitePatternWrite
- LocalBookmarks
metadata:
author: desirecore
updated_at: '2026-05-05'
updated_at: '2026-08-06'
i18n:
default_locale: en-US
source_locale: zh-CN
@@ -51,17 +50,17 @@ metadata:
- en-US
zh-CN:
name: 联网访问
short_desc: 联网搜索、网页抓取、登录态浏览器访问CDP、研究调研工作流
description: 层联网访问工具包——搜索公开页面、Jina 优化抓取、CDP 登录态浏览器访问
short_desc: 联网搜索、网页抓取、内置受管浏览器登录态访问、研究调研工作流
description: 层联网访问工具包——搜索公开页面、Jina 优化抓取、内置受管浏览器登录态访问、Python Playwright CDP 兜底
body: ./SKILL.zh-CN.md
source_hash: sha256:0ba170b3126a0823
source_hash: sha256:2e6753fc05142e9a
translated_by: human
en-US:
name: Web Access
short_desc: Web search, page fetching, logged-in browser access via CDP, research workflows
description: A three-layer web-access toolkit — search public pages, fetch heavy pages via Jina Reader, and reach logged-in sites via Chrome CDP.
short_desc: Web search, page fetching, logged-in access via the governed built-in browser, research workflows
description: A four-layer web-access toolkit — search public pages, fetch heavy pages via Jina Reader, reach logged-in sites through the governed built-in browser, and fall back to Chrome CDP.
body: ./SKILL.md
source_hash: sha256:4cda9ca594fbd974
source_hash: sha256:2e6753fc05142e9a
translated_by: human
market:
icon: >-
@@ -90,7 +89,7 @@ market:
## L0: One-line Summary
A three-layer web-access toolkit — search public pages, optimize fetches via Jina Reader, and reach login-gated sites via Chrome CDP.
A four-layer web-access toolkit — search public pages, optimize fetches via Jina Reader, reach login-gated sites through the governed built-in browser, and fall back to Chrome CDP.
## L1: Overview & Use Cases
@@ -100,24 +99,26 @@ web-access is a **procedural skill** that provides four complementary layers of
- **L1** (WebSearch + WebFetch): public, static pages
- **L2** (Jina Reader): JS-rendered heavy pages, saving tokens by default
- **L3-fast** (BrowserXxx builtin tool family**new in v2.0**): preferred for logged-in sites — zero Python dependency, in-process cdp-proxy, supports CDP real-mouse events
- **L3-fast** (governed built-in browser**rewritten in v2.1**): reach and *interact with* logged-in / interactive sites — isolated BrowserSpace per task, zero Python dependency, every action carries a signed receipt. **Reading long article text is still L2/L3-fallback's job** — see the extraction note below
- **L3-fallback** (Chrome CDP + Python Playwright): backup for complex automation (long waits, race conditions, custom in-browser scripts)
### v2.0BrowserXxx tool family (default-hidden, exposed only after Skill activation)
### v2.1governed built-in browser (default-hidden, exposed only after Skill activation)
When you call `Skill('web-access')`, the following 11 tools are injected into the current session so the LLM can drive Chrome directly:
When you call `Skill('web-access')`, the following 8 tools are injected into the current session so the LLM can drive the built-in browser directly:
| Tool | Purpose |
|------|---------|
| BrowserListTabs / BrowserNavigate / BrowserCloseTab | Tab management |
| BrowserEval | Run JS to extract data |
| BrowserClick (`mode: js \| real-mouse`) | Click elements; real-mouse defeats anti-bot |
| BrowserScreenshot / BrowserScroll | Screenshots, scroll to trigger lazy loading |
| BrowserSetFiles | Upload local files (requires user confirmation) |
| BrowserManage | Create/destroy isolated BrowserSpace, start sessions, manage tabs |
| BrowserSnapshot | `semantic` / `accessibility` / `visual` page snapshots — the primary way to read a page |
| BrowserAct | One governed action per call: navigate, click, type, scroll, screenshot, … |
| BrowserImport | Import Cookies from the user's Chrome/Edge/Firefox/Safari profile (human-approved) |
| BrowserShare | Delegate a Space/Session to another Agent (isolated / snapshot / copy-on-write / live) |
| SitePatternRead / SitePatternWrite | Per-domain "site experience" (AgentFS three-layer) |
| LocalBookmarks | Search local Chrome bookmarks / history |
> **Important**: before `Skill('web-access')` is called, none of these tools appear in the LLM tools list — default conversations don't pay their token cost. See [references/browser-tools.md](references/browser-tools.md).
>
> **Removed in v2.1**: `BrowserListTabs` / `BrowserNavigate` / `BrowserEval` / `BrowserClick` / `BrowserScreenshot` / `BrowserScroll` / `BrowserSetFiles` / `BrowserCloseTab` and the cdp-proxy behind them are retired. Calling them now returns "该旧 BrowserXxx/cdp-proxy 入口已停用". Requires client v10.0.98+.
### Use Cases
@@ -130,7 +131,7 @@ When you call `Skill('web-access')`, the following 11 tools are injected into th
- **Four-layer progression**: from lightweight search to heavy JS rendering to logged-in access — pick on demand
- **Token optimization**: Jina Reader cuts token usage by 5080% by default
- **Logged-in session reuse**: connect to the user's already-logged-in Chrome via CDP — no re-login required
- **Logged-in session reuse**: import the user's existing Cookies into an isolated Space via BrowserImport (or attach to their Chrome via CDP in the fallback layer) — no re-login required
## L2: Detailed Specification
@@ -146,7 +147,7 @@ If any fetch fails, explicitly tell the user which URL failed and which fallback
## Prerequisites: Chrome CDP Setup (for login-gated sites)
**Only required when accessing sites that need the user's login session** (Xiaohongshu / Bilibili / Weibo / Feishu / Twitter / Zhihu / WeChat Official Accounts).
**Only required for the L3-fallback layer** (Python Playwright). The L3-fast built-in browser does not need this — use `BrowserImport` to reuse the user's login instead.
### One-time setup
@@ -205,10 +206,11 @@ User intent
│ (Jina Reader = default for JS-rendered content, saves tokens)
├─ "Read this login-gated page" (Xiaohongshu/Bilibili/Weibo/Feishu/Twitter/Zhihu/WeChat)
─→ 1. Verify CDP ready (curl http://localhost:9222/json/version)
2. Bash: python3 script with playwright.connect_over_cdp()
3. Extract content → feed to Jina Reader for clean Markdown
(or use BeautifulSoup directly on the raw HTML)
─→ Reach it: BrowserManage(create_space/start_session) → BrowserImport(cookies for
that domain) → BrowserAct(tab.navigate) → tab.activate + page.screenshot
to confirm you landed on the content (semantic snapshot has no body text)
└─→ Extract the text: verify CDP ready, then python3 playwright.connect_over_cdp()
│ → page.content() → Jina Reader / BeautifulSoup
├─ "API documentation / GitHub / npm package info"
│ └─→ Prefer official API endpoints over scraping HTML:
@@ -217,9 +219,9 @@ User intent
│ - PyPI: curl https://pypi.org/pypi/<pkg>/json
└─ "Real-time interactive task" (click, fill form, scroll, screenshot)
├─→ **Default: BrowserXxx tools** (BrowserNavigate / BrowserEval / BrowserClick / BrowserScreenshot —
├─→ **Default: built-in browser** (BrowserManage → BrowserAct → BrowserSnapshot —
│ see references/browser-tools.md, no Python needed)
└─→ Fallback: CDP + Python Playwright (references/cdp-browser.md) when BrowserXxx is insufficient
└─→ Fallback: CDP + Python Playwright (references/cdp-browser.md) when the built-in browser is insufficient
(e.g., complex race conditions, multi-event waits, long-running in-browser scripts)
```
@@ -229,10 +231,10 @@ User intent
|-------|----------|--------------|------------|
| L1 | Public, static | `WebFetch` | Low |
| L2 | JS-heavy, long articles, token savings | `Bash curl r.jina.ai` | **Lowest** (Markdown pre-cleaned) |
| **L3-fast** | **Login-gated, interactive (PRIMARY)** | **BrowserXxx tool family** | Medium |
| **L3-fast** | **Login-gated navigation & interaction (PRIMARY)** | **built-in browser (BrowserManage / BrowserAct / BrowserSnapshot)** | Medium |
| L3-fallback | Complex automation (race / long-wait / custom scripts) | `Bash + Python Playwright CDP` | Medium |
**Default priority**: L1 for simple public pages → L2 for heavy → **L3-fast for login-gated** → L3-fallback only when BrowserXxx is insufficient.
**Default priority**: L1 for simple public pages → L2 for heavy → **L3-fast for login-gated** → L3-fallback only when the built-in browser is insufficient.
---
@@ -348,33 +350,49 @@ See [references/cdp-browser.md](references/cdp-browser.md) for:
---
## L3-fast: BrowserXxx Tool Cheatsheet (v2.0 recommended)
## L3-fast: Built-in Browser Cheatsheet (v2.1)
**Only after you call `Skill('web-access')` will the following tools appear in `tools[]`.**
| Tool | One-line example |
|------|-----------------|
| `BrowserListTabs()` | List all open tabs |
| `BrowserNavigate({ url })` | Open URL in a new tab |
| `BrowserNavigate({ target, url })` | Navigate an existing tab |
| `BrowserEval({ target, expression })` | Run JS in the tab to extract structured data |
| `BrowserClick({ target, selector, mode: 'real-mouse' })` | Real-mouse mode for anti-bot-strict sites |
| `BrowserScreenshot({ target })` | Saved under ${DESIRECORE_ROOT}/screenshots/ |
| `BrowserScroll({ target, direction: 'bottom' })` | Trigger lazy loading |
| `BrowserSetFiles({ target, selector, files })` | Upload local files (**user confirmation required**) |
| `BrowserCloseTab({ target })` | Clean up temporary tabs at task end |
| `BrowserManage({ action: 'create_space', name, persistence: 'ephemeral' })` | One isolated Space per task |
| `BrowserManage({ action: 'start_session', spaceId, capabilities })` | Start a session, returns sessionId + first tab |
| `BrowserManage({ action: 'list_tabs' \| 'create_tab' \| 'close_session' })` | Tab / lifecycle management |
| `BrowserAct({ action: 'tab.navigate', params: { url } })` | Navigate the current tab |
| `BrowserSnapshot({ mode: 'semantic' })` | Read the page: interactive elements + `ref` handles |
| `BrowserAct({ action: 'input.click', params: { ref } })` | Click by snapshot `ref`, never by raw x/y |
| `BrowserAct({ action: 'input.text', params: { text } })` | Type into the focused element |
| `BrowserAct({ action: 'input.wheel', params: { deltaX: 0, deltaY: 720 } })` | Scroll to trigger lazy loading |
| `BrowserAct({ action: 'tab.activate', params: { bounds } })``page.screenshot` | **activate first, then screenshot** |
| `BrowserImport({ action: 'discover' \| 'plan' \| 'apply' })` | Reuse the user's login cookies (human-approved) |
Full API and edge cases: see [references/browser-tools.md](references/browser-tools.md).
**How to read a page** — pick by what you need:
| You need | Use | Note |
|----------|-----|------|
| Interactive elements + `ref` handles | `BrowserSnapshot({ mode: 'semantic' })` | Buttons / inputs / links only — **no article text** |
| Article text on a small/simple page | `BrowserSnapshot({ mode: 'accessibility' })` | Returns StaticText nodes; fails with `BROWSER_RESULT_TOO_LARGE` on real content pages (2 MB result cap, and the `depth` argument is currently ignored by the host) |
| Article text on a real page | L2 Jina Reader (public) or L3-fallback Playwright (login-gated) | The built-in browser has no working bulk text-extraction channel yet |
| What the page looks like | `tab.activate``BrowserAct({ action: 'page.screenshot' })` | Full-page only; read it visually |
`page.evaluate` is **not** an extraction channel: it needs human approval per call and its string/object return values come back as `[REDACTED:browser-runtime-value]`.
### Recommended flow (Xiaohongshu example)
```
1. BrowserListTabs() → check whether there's an already-logged-in xhs tab
2. If not → BrowserNavigate({ url: "https://www.xiaohongshu.com/explore/abc123" })
3. BrowserEval({ target, expression: "...JSON.stringify({title, content})" })
4. SitePatternRead({ domain: "xiaohongshu.com" }) ← read accumulated experience
5. At task end → BrowserCloseTab({ target })
6. If you find a new pitfall → SitePatternWrite({ domain, scope: "agent", mode: "merge", content })
1. BrowserManage({ action: 'create_space', name: 'xhs-note', persistence: 'ephemeral' })
2. BrowserManage({ action: 'start_session', spaceId, capabilities: [...] })
3. BrowserImport({ action: 'discover' }) → plan → apply for xiaohongshu.com ← reuse login
4. BrowserAct({ action: 'tab.navigate', params: { url: 'https://www.xiaohongshu.com/explore/abc123' } })
5. BrowserSnapshot({ mode: 'semantic' }) ← element refs for interaction (no body text)
tab.activate + page.screenshot ← confirm the note actually rendered
→ extract the note text via L3-fallback Playwright
6. SitePatternRead({ domain: 'xiaohongshu.com' }) ← read accumulated experience
7. At task end → BrowserManage({ action: 'close_session', sessionId })
8. If you find a new pitfall → SitePatternWrite({ domain, scope: 'agent', mode: 'merge', content })
```
---
@@ -446,9 +464,11 @@ Read [references/jina-reader.md](references/jina-reader.md) for Jina Reader posi
-**Forgetting the year in time-sensitive queries** — "best AI models" returns 2023 results; "best AI models 2026" returns current.
-**Hardcoding login credentials in scripts** — always rely on the user's pre-logged CDP session.
-**Citing only after the fact** — collect URLs as you fetch, not from memory afterwards.
-**(v2.0) Writing Python heredoc when BrowserXxx would do** — slow, requires Python+Playwright install, and bloats context. Prefer L3-fast; fall back to Python only when BrowserXxx is insufficient (race / long-wait / custom scripts).
-**(v2.0) Discovering new pitfalls and not writing a site-pattern** — next time the same Agent runs the task, it'll repeat the same mistakes. Anything that took 2+ steps to figure out is worth `SitePatternWrite(scope='agent', mode='merge')`.
-**(v2.0) Writing cookies / phone numbers to scope='agent'** — that layer is Git-tracked and may be published to the marketplace. SitePatternWrite auto-downgrades, but don't deliberately write secrets to the agent layer.
-**(v2.1) Writing Python heredoc when the built-in browser would do** — slow, requires Python+Playwright install, and bloats context. Prefer L3-fast; fall back to Python only when the built-in browser is insufficient (race / long-wait / custom scripts).
-**(v2.1) Calling `page.screenshot` before `tab.activate`** — tabs are parked off-screen at `(-10000,-10000,1x1)` and have no compositing surface, so the capture stalls until the 30s deadline **and the tab host is destroyed**; every later call then fails with `BROWSER_TAB_HOST_NOT_FOUND`. Always `tab.activate` with real bounds first.
-**(v2.1) Reaching for `page.evaluate` to read a page** — it needs human approval on every call, its string/object return values come back as `[REDACTED:browser-runtime-value]` (only number/boolean/null survive), and anti-debug sites stall it for tens of seconds. Read pages with `BrowserSnapshot` instead.
-**(v2.1) Discovering new pitfalls and not writing a site-pattern** — next time the same Agent runs the task, it'll repeat the same mistakes. Anything that took 2+ steps to figure out is worth `SitePatternWrite(scope='agent', mode='merge')`.
-**(v2.1) Writing cookies / phone numbers to scope='agent'** — that layer is Git-tracked and may be published to the marketplace. SitePatternWrite auto-downgrades, but don't deliberately write secrets to the agent layer.
---

View File

@@ -4,7 +4,7 @@
## L0一句话摘要
四层联网访问工具包——搜索公开页面、Jina 优化抓取、BrowserXxx 内置工具家族v2.0、Python Playwright CDP 兜底。
四层联网访问工具包——搜索公开页面、Jina 优化抓取、内置受管浏览器登录态访问v2.1、Python Playwright CDP 兜底。
## L1概述与使用场景
@@ -14,24 +14,26 @@ web-access 是一个**流程型技能Procedural Skill**,提供四层互
- **L1**WebSearch + WebFetch公开页面轻量
- **L2**Jina ReaderJS 渲染的重页面,默认节省 Token
- **L3-fast**BrowserXxx 内置工具家族,**v2.0 新增**):登录态站点首选——零 Python 依赖、内置 cdp-proxy 子进程、支持 CDP 真实鼠标事件
- **L3-fast**内置受管浏览器,**v2.1 重写**):到达并*操作*登录态/交互站点——每个任务独立 BrowserSpace 隔离、零 Python 依赖、每次动作都有可审计回执。**抽取长正文仍归 L2 / L3-fallback**,见下方取文说明
- **L3-fallback**Chrome CDP + Python Playwright复杂自动化场景兜底长等待、特殊 race condition 等)
### v2.0 新增BrowserXxx 工具家族(默认隐藏,激活后才暴露)
### v2.1 重写:内置受管浏览器(默认隐藏,激活后才暴露)
调用 `Skill('web-access')` 加载本技能时,以下 11 个工具被注入到当前会话,让 LLM 直接驱动浏览器:
调用 `Skill('web-access')` 加载本技能时,以下 8 个工具被注入到当前会话,让 LLM 直接驱动内置浏览器:
| 工具 | 用途 |
|------|------|
| BrowserListTabs / BrowserNavigate / BrowserCloseTab | tab 管理 |
| BrowserEval | 执行 JS 提取数据 |
| BrowserClick (`mode: js \| real-mouse`) | 点击元素real-mouse 反爬更强 |
| BrowserScreenshot / BrowserScroll | 截图、滚动触发懒加载 |
| BrowserSetFiles | 上传本地文件(需用户确认 |
| BrowserManage | 建/销隔离 BrowserSpace、启动会话、管理标签页 |
| BrowserSnapshot | `semantic` / `accessibility` / `visual` 快照——读页面的主通道 |
| BrowserAct | 一次调用一个受管动作:导航、点击、输入、滚动、截图…… |
| BrowserImport | 从用户 Chrome/Edge/Firefox/Safari 配置导入 Cookie需人工审批 |
| BrowserShare | 把 Space/Session 委派给其他 Agent隔离 / 快照 / 写时复制 / 实时共享 |
| SitePatternRead / SitePatternWrite | 按域名累积"站点经验"AgentFS 三层) |
| LocalBookmarks | 检索本地 Chrome 书签 / 历史 |
> **重要**:未调用 Skill('web-access') 之前,这些工具**不会**出现在 LLM 的 tools 列表里——默认对话不消耗其 token。详见 [references/browser-tools.md](references/browser-tools.md)。
>
> **v2.1 已移除**`BrowserListTabs` / `BrowserNavigate` / `BrowserEval` / `BrowserClick` / `BrowserScreenshot` / `BrowserScroll` / `BrowserSetFiles` / `BrowserCloseTab` 及其背后的 cdp-proxy 已停用,调用会返回「该旧 BrowserXxx/cdp-proxy 入口已停用」。本版要求客户端 v10.0.98+。
### 使用场景
@@ -44,7 +46,7 @@ web-access 是一个**流程型技能Procedural Skill**,提供四层互
- **四层递进**:从轻量搜索到重度 JS 渲染到登录态访问,按需选择
- **Token 优化**Jina Reader 默认减少 50-80% Token 消耗
- **登录态复用**通过 CDP 连用户已登录的 Chrome无需重复登录
- **登录态复用**用 BrowserImport 把用户已有 Cookie 导入隔离 Space兜底层仍可 CDP 连用户 Chrome,无需重复登录
## L2详细规范
@@ -60,7 +62,7 @@ If any fetch fails, explicitly tell the user which URL failed and which fallback
## Prerequisites: Chrome CDP Setup (for login-gated sites)
**Only required when accessing sites that need the user's login session** (小红书/B站/微博/飞书/Twitter/知乎/公众号).
**Only required for the L3-fallback layer**Python Playwright。L3-fast 内置浏览器不需要——用 `BrowserImport` 复用登录态即可。
### One-time setup
@@ -119,10 +121,11 @@ User intent
│ (Jina Reader = default for JS-rendered content, saves tokens)
├─ "Read this login-gated page" (小红书/B站/微博/飞书/Twitter/知乎/公众号)
─→ 1. Verify CDP ready (curl http://localhost:9222/json/version)
2. Bash: python3 script with playwright.connect_over_cdp()
3. Extract content → feed to Jina Reader for clean Markdown
(or use BeautifulSoup directly on the raw HTML)
─→ 到达BrowserManage(create_space/start_session) → BrowserImport(按域导入 Cookie)
→ BrowserAct(tab.navigate) → tab.activate + page.screenshot 确认落到正文页
semantic 快照不含正文,不能用来读内容)
└─→ 取正文:确认 CDP 就绪后 python3 playwright.connect_over_cdp()
│ → page.content() → Jina Reader / BeautifulSoup
├─ "API documentation / GitHub / npm package info"
│ └─→ Prefer official API endpoints over scraping HTML:
@@ -131,9 +134,9 @@ User intent
│ - PyPI: curl https://pypi.org/pypi/<pkg>/json
└─ "Real-time interactive task" (click, fill form, scroll, screenshot)
├─→ **Default: BrowserXxx tools** (BrowserNavigate / BrowserEval / BrowserClick / BrowserScreenshot —
├─→ **Default: 内置受管浏览器** (BrowserManage → BrowserAct → BrowserSnapshot —
│ see references/browser-tools.md, no Python needed)
└─→ Fallback: CDP + Python Playwright (references/cdp-browser.md) when BrowserXxx is insufficient
└─→ Fallback: CDP + Python Playwright (references/cdp-browser.md) when 内置浏览器 is insufficient
(e.g., complex race conditions, multi-event waits, long-running in-browser scripts)
```
@@ -143,10 +146,10 @@ User intent
|-------|----------|--------------|------------|
| L1 | Public, static | `WebFetch` | Low |
| L2 | JS-heavy, long articles, token savings | `Bash curl r.jina.ai` | **Lowest** (Markdown pre-cleaned) |
| **L3-fast** | **Login-gated, interactive (PRIMARY)** | **BrowserXxx 工具家族** | Medium |
| **L3-fast** | **登录态导航与交互 (PRIMARY)** | **内置受管浏览器BrowserManage / BrowserAct / BrowserSnapshot** | Medium |
| L3-fallback | 复杂自动化race / long-wait / 自定义脚本) | `Bash + Python Playwright CDP` | Medium |
**Default priority**: L1 for simple public pages → L2 for heavy → **L3-fast for login-gated** → L3-fallback only when BrowserXxx 不够用。
**Default priority**: L1 for simple public pages → L2 for heavy → **L3-fast for login-gated** → L3-fallback only when 内置浏览器不够用。
---
@@ -262,33 +265,49 @@ See [references/cdp-browser.md](references/cdp-browser.md) for:
---
## L3-fast: BrowserXxx 工具速查v2.0 推荐
## L3-fast: 内置受管浏览器速查v2.1
**只在你调用 `Skill('web-access')` 加载本技能后,下面这组工具才会出现在 tools[] 里。**
| 工具 | 一行示例 |
|------|---------|
| `BrowserListTabs()` | 列出所有打开 tab |
| `BrowserNavigate({ url })` | 在新 tab 打开 URL |
| `BrowserNavigate({ target, url })` | 在指定 tab 跳转 |
| `BrowserEval({ target, expression })` | 在 tab 内跑 JS提取结构化数据 |
| `BrowserClick({ target, selector, mode: 'real-mouse' })` | 反爬严格站点用真实鼠标事件 |
| `BrowserScreenshot({ target })` | 写入 ${DESIRECORE_ROOT}/screenshots/ |
| `BrowserScroll({ target, direction: 'bottom' })` | 触发懒加载 |
| `BrowserSetFiles({ target, selector, files })` | 上传本地文件(**需用户确认** |
| `BrowserCloseTab({ target })` | 任务收尾清理临时 tab |
| `BrowserManage({ action: 'create_space', name, persistence: 'ephemeral' })` | 每个任务一个隔离 Space |
| `BrowserManage({ action: 'start_session', spaceId, capabilities })` | 启动会话,返回 sessionId 与首个标签页 |
| `BrowserManage({ action: 'list_tabs' \| 'create_tab' \| 'close_session' })` | 标签页与生命周期管理 |
| `BrowserAct({ action: 'tab.navigate', params: { url } })` | 当前标签页导航 |
| `BrowserSnapshot({ mode: 'semantic' })` | 读页面:可交互元素 + `ref` 句柄 |
| `BrowserAct({ action: 'input.click', params: { ref } })` | 按快照 `ref` 点击,不要用裸 x/y |
| `BrowserAct({ action: 'input.text', params: { text } })` | 向聚焦元素输入文本 |
| `BrowserAct({ action: 'input.wheel', params: { deltaX: 0, deltaY: 720 } })` | 滚动触发懒加载 |
| `BrowserAct({ action: 'tab.activate', params: { bounds } })``page.screenshot` | **先 activate 再截图** |
| `BrowserImport({ action: 'discover' \| 'plan' \| 'apply' })` | 复用用户登录态 Cookie需人工审批 |
完整 API 与边界条件见 [references/browser-tools.md](references/browser-tools.md)。
**怎么读页面** —— 按需求选通道:
| 你要什么 | 用什么 | 说明 |
|----------|--------|------|
| 可交互元素 + `ref` 句柄 | `BrowserSnapshot({ mode: 'semantic' })` | 只有按钮/输入框/链接,**不含正文文本** |
| 小页面的正文 | `BrowserSnapshot({ mode: 'accessibility' })` | 返回 StaticText 节点;真实内容页会报 `BROWSER_RESULT_TOO_LARGE`(结果上限 2 MB`depth` 参数当前被宿主忽略) |
| 真实页面的正文 | L2 Jina Reader公开页或 L3-fallback Playwright登录态 | 内置浏览器目前没有可用的批量取文通道 |
| 页面长什么样 | `tab.activate``BrowserAct({ action: 'page.screenshot' })` | 只有整页截图,靠看图读 |
`page.evaluate` **不是**取文通道:每次调用需人工审批,且字符串/对象返回值会被替换成 `[REDACTED:browser-runtime-value]`
### 推荐流程(小红书示例)
```
1. BrowserListTabs() → 看是否已有登录态 tab
2. 没有 → BrowserNavigate({ url: "https://www.xiaohongshu.com/explore/abc123" })
3. BrowserEval({ target, expression: "(...)JSON.stringify({title, content})" })
4. SitePatternRead({ domain: "xiaohongshu.com" }) ← 读累积经验
5. 任务结束 → BrowserCloseTab({ target })
6. 如发现新陷阱 → SitePatternWrite({ domain, scope: "agent", mode: "merge", content })
1. BrowserManage({ action: 'create_space', name: 'xhs-note', persistence: 'ephemeral' })
2. BrowserManage({ action: 'start_session', spaceId, capabilities: [...] })
3. BrowserImport({ action: 'discover' }) → plan → apply 授权 xiaohongshu.com ← 复用登录态
4. BrowserAct({ action: 'tab.navigate', params: { url: 'https://www.xiaohongshu.com/explore/abc123' } })
5. BrowserSnapshot({ mode: 'semantic' }) ← 只拿交互用的元素 ref不含正文
tab.activate + page.screenshot ← 确认确实渲染出了笔记
→ 正文抽取走 L3-fallback Playwright
6. SitePatternRead({ domain: 'xiaohongshu.com' }) ← 读累积经验
7. 任务结束 → BrowserManage({ action: 'close_session', sessionId })
8. 如发现新陷阱 → SitePatternWrite({ domain, scope: 'agent', mode: 'merge', content })
```
---
@@ -360,9 +379,11 @@ Read [references/jina-reader.md](references/jina-reader.md) for Jina Reader posi
-**Forgetting the year in time-sensitive queries** — "best AI models" returns 2023 results; "best AI models 2026" returns current.
-**Hardcoding login credentials in scripts** — always rely on the user's pre-logged CDP session.
-**Citing only after the fact** — collect URLs as you fetch, not from memory afterwards.
-**(v2.0) 在能用 BrowserXxx 时仍写 Python heredoc** — 慢、依赖 Python+Playwright 安装、上下文体积大。优先 L3-fast只在 BrowserXxx 不够race / 长等待 / 自定义脚本)时才回退。
-**(v2.0) 任务结束发现新陷阱却不写 site-pattern** — 下次同 Agent 再做相同任务会重复踩坑。任何"花了 2+ 步才搞清楚的细节"都值得 `SitePatternWrite(scope='agent', mode='merge')`
-**(v2.0) 把含 cookie / 手机号的内容写到 scope='agent'** — 这层会被 Git 提交、可能发布到市场。SitePatternWrite 会自动降级,但你不该故意往 agent 层写敏感信息
-**(v2.1) 在能用内置浏览器时仍写 Python heredoc** — 慢、依赖 Python+Playwright 安装、上下文体积大。优先 L3-fast只在内置浏览器不够race / 长等待 / 自定义脚本)时才回退。
-**(v2.1) `tab.activate` 就直接 `page.screenshot`** — 标签页默认停在窗口外 `(-10000,-10000,1x1)`,没有合成表面,截图会卡满 30 秒 deadline **并把标签页宿主打掉**,之后所有调用都报 `BROWSER_TAB_HOST_NOT_FOUND`。务必先用真实 bounds `tab.activate`
-**(v2.1) `page.evaluate` 读页面** — 每次调用都需人工审批,返回的字符串/对象会被治理策略替换为 `[REDACTED:browser-runtime-value]`(只有 number/boolean/null 能穿透),且反调试站点会把它挂起几十秒。读页面请用 `BrowserSnapshot`
-**(v2.1) 任务结束发现新陷阱却不写 site-pattern** — 下次同 Agent 再做相同任务会重复踩坑。任何"花了 2+ 步才搞清楚的细节"都值得 `SitePatternWrite(scope='agent', mode='merge')`
-**(v2.1) 把含 cookie / 手机号的内容写到 scope='agent'** — 这层会被 Git 提交、可能发布到市场。SitePatternWrite 会自动降级,但你不该故意往 agent 层写敏感信息。
---

View File

@@ -1,113 +1,163 @@
# BrowserXxx 工具速查L3-fast
# 内置受管浏览器工具速查L3-fast
> 适配自 [eze-is/web-access](https://github.com/eze-is/web-access) 的 `references/cdp-api.md`MIT作者 一泽 Eze
> DesireCore 把 cdp-proxy 内嵌为子进程,并通过这组 BuiltinTool 调用——比直接 curl 更安全(不暴露端口给 prompt 注入)、比 Python heredoc 更轻(无 Python/Playwright 依赖)。
> v2.1 起本层从「cdp-proxy 驱动用户自己的 Chrome」改为「DesireCore 内置受管浏览器」
> 每个任务跑在独立 BrowserSpace 里Cookie / Storage / 缓存互不串扰),每个动作都经过
> Capability → Grant → Lease → Origin → Host fencing 校验并留下可审计回执。
>
> 要求客户端 **v10.0.98+**。旧的 `BrowserListTabs` / `BrowserNavigate` / `BrowserEval` /
> `BrowserClick` / `BrowserScreenshot` / `BrowserScroll` / `BrowserSetFiles` /
> `BrowserCloseTab` 与其背后的 cdp-proxy 已停用,调用会直接返回
> 「该旧 BrowserXxx/cdp-proxy 入口已停用;请改用 BrowserManage、BrowserSnapshot 或 BrowserAct」。
## 何时用 BrowserXxx vs Python Playwright
## 何时用内置浏览器 vs Python Playwright
| 场景 | 推荐 |
|------|------|
| 抓取登录态站点(小红书 / B站 / 微博 / 飞书 / 知乎) | **BrowserXxx**fast零 Python |
| 简单点击 / 滚动 / 截图 / 上传文件 | **BrowserXxx** |
| 需要复杂等待逻辑page.wait_for_selector + race condition | Python Playwrightcdp-browser.md |
| 需要在浏览器内运行长时间脚本(>30 s | Python Playwright |
| 到达并操作登录态站点(小红书 / B站 / 微博 / 飞书 / 知乎) | **内置浏览器**(配合 BrowserImport 导入 Cookie |
| 抽取登录态站点的长正文 | Python Playwright内置浏览器没有批量取文通道见下 |
| 简单点击 / 滚动 / 截图 | **内置浏览器** |
| 多个任务要互不串扰地并行 | **内置浏览器**(一任务一 Space |
| 需要复杂等待逻辑wait_for_selector + race condition | Python Playwrightcdp-browser.md |
| 需要在浏览器内运行长时间脚本(>30 s | Python Playwright内置浏览器单条命令 30 s deadline |
| 需要对元素做放大裁剪截图 | Python Playwright内置浏览器只有整页截图 |
## 前置条件
1. 用户已启动调试模式 Chrome端口 9222见 SKILL.md 的 Prerequisites 部分)
2. cdp-proxy 子进程会在首次工具调用时由 agent-service lazy spawn
1. 客户端 v10.0.98+`~/.desirecore/config/browser.json``electron-embedded`
`standalone-managed` Provider 处于 `enabled`(默认即开启)
2. 无需用户手工启动调试 Chrome也无需 Python / Playwright
## 工具一览
每个工具默认 `hidden: true`**只有 web-access 技能被激活后才暴露给 LLM**。
### BrowserListTabs
### BrowserManage
列出已打开 tab。返回每行 `[targetId] title — url`
Space / Session / Tab 的生命周期
```yaml
BrowserListTabs:
# 无参数
BrowserManage:
action: create_space # list_spaces | create_space | start_session | join_session
# | leave_session | list_sessions | list_tabs | create_tab
# | freeze_session | resume_session | close_session
name: xhs-note # create_space 用
persistence: ephemeral # ephemeral=查完即弃,不落 Profilepersistent=保留登录态
providerPreference: [electron-embedded]
```
### BrowserNavigate
打开 URL省略 `target` 时新开 tab。
```yaml
BrowserNavigate:
url: https://www.xiaohongshu.com/explore/...
target: <可选 targetId>
BrowserManage:
action: start_session
spaceId: bsp_xxx
capabilities: # 只申请你真正要用的,最小权限
- browser.observe.tabs
- browser.observe.snapshot
- browser.observe.screenshot
- browser.navigate.create-tab
- browser.navigate.url
- browser.navigate.activate-tab
- browser.input.pointer.click
- browser.input.keyboard
```
### BrowserEval
`create_space` 会触发一次用户确认。任务收尾用 `close_session` 释放。
在指定 tab 内执行 JS`returnByValue: true` + `awaitPromise: true`)。
### BrowserSnapshot
读页面的**主通道**。返回可交互元素及其 `ref` 句柄、`rect``disabled` 状态。
```yaml
BrowserEval:
target: <targetId>
expression: |
(() => {
const t = document.querySelector('h1.video-title')?.textContent || ''
const d = document.querySelector('.video-desc')?.textContent || ''
return JSON.stringify({ title: t.trim(), desc: d.trim() })
})()
BrowserSnapshot:
mode: semantic # semantic默认| accessibility | visual
sessionId: bss_xxx # 当前 Agent 有多个会话时用于消歧
tabId: btab_xxx
```
提示:
- DOM 节点不能直接返回,要提取属性
- 大量数据用 `JSON.stringify()` 包裹返回字符串
- 风险等级 medium是任意 JS 入口,不要执行不可信代码
- `semantic` 只列 button / input / a 等可交互元素,**不含图片和正文文本节点**
- 元素 `name` 往往是 placeholder如「请输入」无标签时只能靠 `rect.y` 排序定位
- 页面重排后旧 `ref` 会失效——**每次交互前重新取快照**
- `accessibility` 能拿到 StaticText 正文,但**只在很简单的页面上可用**:实测
example.com 正常返回,维基百科条目一律 `BROWSER_RESULT_TOO_LARGE`(回执上限 2 MB
且 schema 里的 `depth` 参数目前被宿主忽略(硬编码 depth=50调小也没用
- 因此**取真实页面正文仍要靠 L2 Jina Reader公开页或 L3-fallback Playwright登录态**
### BrowserClick
### BrowserAct
一次调用一个受管动作。完整 `action` 见工具 schema常用的
```yaml
BrowserClick:
target: <targetId>
selector: button.submit
mode: real-mouse # 默认 js登录态站点反爬严格时建议 real-mouse
BrowserAct:
action: tab.navigate
params: { url: https://www.xiaohongshu.com/explore/... }
```
`mode: real-mouse` 走 CDP `Input.dispatchMouseEvent` 派发真实鼠标事件——能触发文件对话框、绕过部分反自动化检测。
### BrowserScreenshot
```yaml
BrowserScreenshot:
target: <targetId>
filename: 自定义文件名.png # 可选;写入 ${DESIRECORE_ROOT}/screenshots/
BrowserAct:
action: input.click
params: { ref: bref_xxx } # 用快照 ref坐标会因页面重排失效
```
### BrowserScroll
```yaml
BrowserScroll:
target: <targetId>
direction: bottom # 或 top与 y 二选一
# y: 3000 # 按像素滚动
BrowserAct:
action: input.text
params: { text: 搜索关键词 }
```
### BrowserSetFiles**需用户确认**
为 input[type=file] 设置本地文件,绕过文件对话框。涉及上传,必须经 user confirmation。
```yaml
BrowserSetFiles:
target: <targetId>
selector: input[type=file]
files:
- /Users/me/Pictures/photo.png
BrowserAct:
action: input.wheel
params: { deltaX: 0, deltaY: 720, x: 640, y: 400 }
```
### BrowserCloseTab
```yaml
BrowserCloseTab:
target: <targetId>
BrowserAct:
action: tab.activate # 截图前必须先做这一步
params: { bounds: { x: 0, y: 0, width: 1280, height: 900 } }
```
任务收尾建议清理你创建的临时 tab避免 cdp-proxy 的 tab 池堆积15 min 后会自动 GC但显式关更整洁
```yaml
BrowserAct:
action: page.screenshot
params: { format: png } # 结果落 artifact store回执给 artifact.id / sha256 / bytes
```
### BrowserImport**需人工审批**
把用户浏览器里的登录态 Cookie 导入当前 Space替代旧版「attach 用户已登录的 Chrome」。
```yaml
BrowserImport:
action: discover # discover | plan | apply | ...
```
```yaml
BrowserImport:
action: apply
planId: bip_xxx
domains: [xiaohongshu.com] # 必须逐域显式授权
conflictStrategy: newer-wins
```
解密与过滤全在 Host 侧完成,**Cookie 值不会进入 Agent 上下文或审计日志**。
### BrowserShare
把 Space / Session 委派给另一个 Agent`shareMode` 可选 `snapshot`(只读副本)、
`copy-on-write`(写时复制)、`live-shared`(实时共享)、`handoff`(移交控制权)。
## 已知边界(照做,别试探)
| 边界 | 说明 |
|------|------|
| **截图前必须 `tab.activate`** | 标签页默认停在 `(-10000,-10000,1x1)`,没有合成表面。直接截图会卡满 30 s deadline**并把标签页宿主打掉**,之后全部报 `BROWSER_TAB_HOST_NOT_FOUND` |
| **同时只有一个可见标签页** | `tab.activate` 绑定主窗口、全局互斥。多 Space 可以并发导航/快照/输入,但截图必须逐个 activate 串行 |
| **`page.evaluate` 基本不可用** | 每次调用需人工审批;返回的字符串/对象被替换为 `[REDACTED:browser-runtime-value]`(只有 number/boolean/null 穿透);反调试站点会把它挂起几十秒。读页面用 `BrowserSnapshot` |
| **`cdp.raw` 需人工审批** | `browser.raw_cdp.*` 属于永远人工闸门的能力,无人值守流程用不了(元素级裁剪截图因此不可用) |
| **没有批量取文通道** | `semantic` 不含正文,`accessibility` 在真实页面上超限,`page.evaluate` 被审批+脱敏。要正文请回落 Jina / Playwright |
| **单条命令 30 s deadline** | 超时即判 `browser.host.gone`,会话作废 |
| **用户真实鼠标会抢控制权** | 鼠标划过可见标签页会触发 `trusted-user-input` 并递增 control epoch可能打断 Agent 的租约 |
| **artifact 不要走 `/save`** | 该接口会弹系统「另存为」对话框等人点。artifact 文件在 `${DESIRECORE_ROOT}/browser/artifacts/<bart_id>/`,直接读即可,默认保留 24 小时 |
## SitePatternRead / SitePatternWrite
@@ -120,7 +170,7 @@ SitePatternWrite:
mode: merge # 默认 merge 追加replace 覆盖
content: |
## 已知陷阱
- 2026-05: ...
- 2026-08: ...
```
含 cookie/token/手机号/邮箱时会自动降级 scope='user'。
@@ -129,14 +179,18 @@ SitePatternWrite:
| 错误 | 原因 | 解决 |
|------|------|------|
| `Chrome 未开启远程调试端口` | 用户没启动调试 Chrome | 引导用户跑 SKILL.md 中的启动命令 |
| `attach 失败` | targetId 无效或 tab 已关闭 | 重新 `BrowserListTabs` |
| `CDP 命令超时` | 页面长时间未响应 | 检查页面状态,必要时 `BrowserCloseTab` 后重开 |
| `CDP proxy 请求被中止或超时` | 代理子进程异常或网络故障 | 等待 ProxyController 自动重启(最多 3 次) |
| `该旧 BrowserXxx/cdp-proxy 入口已停用` | 还在调 v2.0 的旧工具 | 改用 BrowserManage / BrowserSnapshot / BrowserAct |
| `BROWSER_TAB_HOST_NOT_FOUND` | 标签页宿主已销毁(多因上一条命令超时) | 重建 Session检查是否漏了 `tab.activate` |
| `BROWSER_COMMAND_DEADLINE_EXCEEDED` | 单条命令超 30 s | 截图先 activate避免 `page.evaluate` |
| `BROWSER_TOOL_SESSION_FORBIDDEN` | 会话已关闭/崩溃,或不属于当前 Agent | 重新 `list_sessions`,必要时重建 |
| `BROWSER_TOOL_SESSION_AMBIGUOUS` | 当前 Agent 有多个会话且未传 sessionId | 显式传 `sessionId` |
| `BROWSER_HUMAN_APPROVAL_REQUIRED` | 触到人工闸门能力evaluate / raw_cdp / 上传下载 / Cookie 导入等) | 向用户说明用途并等待审批,或换用无需审批的路径 |
| `BROWSER_RESULT_TOO_LARGE` | 回执超过 2 MB`accessibility` 快照最常见) | 改用 `semantic` 快照 + 截图;取正文回落 Jina / Playwright |
## 调用链路
```
Agent → BrowserXxx 工具 → proxy-client → cdp-proxy 子进程 → Chrome (DevTools Protocol)
↑ 首次调用 lazy spawn 子进程
Agent → BrowserManage/Snapshot/Act → browser-use serviceCapability/Grant/Lease/Policy 校验)
→ BrowserHostelectron-embedded 或 standalone-managed→ Chromium
↑ 每步产出带 digest 的回执,写入审计事件流
```

View File

@@ -5,7 +5,7 @@ type: site-pattern
pinned: true
confidence: medium
learned_at: '2026-05-05'
updated_at: '2026-05-05'
updated_at: '2026-08-06'
---
## L0
@@ -18,7 +18,7 @@ updated_at: '2026-05-05'
## 推荐流程
- 仅取标题/UP 主/播放数 → WebFetch 即可
- 取完整简介 / 评论 → BrowserNavigate + BrowserEval
- 取完整简介 / 评论 → 内置浏览器 BrowserAct(tab.navigate) 到达页面,正文抽取回落 L3-fallback Playwright
- 批量数据 → 优先尝试 `api.bilibili.com` 公开接口(有专门的 wbi 签名机制)
## 推荐选择器

View File

@@ -5,7 +5,7 @@ type: site-pattern
pinned: true
confidence: high
learned_at: '2026-05-05'
updated_at: '2026-05-05'
updated_at: '2026-08-06'
---
## L0
@@ -19,7 +19,7 @@ updated_at: '2026-05-05'
## 推荐流程
1. 公开文档companion 页面/官方文档站点 `feishu.cn/hc/...`)→ WebFetch / Jina
2. 用户文档 → BrowserNavigate已登录 Chrome+ BrowserEval 抓正文
2. 用户文档 → 内置浏览器 BrowserImport 导入 Cookie + BrowserAct(tab.navigate) 到达,正文抽取回落 Playwright
3. 长期程序化访问 → 申请 OpenAPI access_token走 HTTP避免 CDP
## 推荐选择器

View File

@@ -5,7 +5,7 @@ type: site-pattern
pinned: true
confidence: medium
learned_at: '2026-05-05'
updated_at: '2026-05-05'
updated_at: '2026-08-06'
---
## L0
@@ -18,8 +18,8 @@ updated_at: '2026-05-05'
## 推荐流程
1. 单条公开微博 → 优先尝试 `https://m.weibo.cn/status/<id>`WebFetch 看是否拿到正文
2. 拿不到 → BrowserNavigate已登录态 Chrome+ BrowserClick 点"展开" + BrowserEval 取正文
3. 用户主页时间线必须登录BrowserScroll 触发懒加载
2. 拿不到 → 内置浏览器 BrowserImport 导入 Cookie + BrowserAct(tab.navigate) + BrowserAct(input.click ref) 点"展开",正文抽取回落 Playwright
3. 用户主页时间线必须登录BrowserAct(input.wheel) 触发懒加载
## 推荐选择器
- 单条详情:`.weibo-text` / `[class*='WB_text']`

View File

@@ -5,7 +5,7 @@ type: site-pattern
pinned: true
confidence: high
learned_at: '2026-05-05'
updated_at: '2026-05-05'
updated_at: '2026-08-06'
---
## L0
@@ -18,10 +18,10 @@ updated_at: '2026-05-05'
- xsec_token详情页 URL 包含 `xsec_token=...`**通过站内交互生成**——直接拼 URL 容易失败
## 推荐流程
1. 通过 BrowserListTabs 找到已登录的 xhs tab如无BrowserNavigate 打开
2. BrowserEval 注入选择器抓取标题与正文
3. 列表页用 `[...document.querySelectorAll('.note-card a')].map(a => a.href)` 收集详情页链接
4. 单条笔记结尾调用 `BrowserCloseTab` 释放 tab避免 tab 池溢出
1. BrowserManage(create_space/start_session) → BrowserImport 按域导入 xiaohongshu.com 的 Cookie
2. BrowserAct(tab.navigate) 打开笔记;列表页用 BrowserSnapshot(semantic) 收 `.note-card` 链接的 ref
3. 正文抽取回落 L3-fallback Playwright内置浏览器的 semantic 快照不含正文accessibility 在本站会超限)
4. 收尾 BrowserManage(close_session)ephemeral Space 不留 Profile
## 推荐选择器
- 笔记标题:`#detail-title``h1[class*="title"]`
@@ -36,8 +36,8 @@ updated_at: '2026-05-05'
## 反爬细节
- xsec_token 由前端生成,与会话/路由绑定,不能跨 tab 复用太久
- User-Agent 检查较弱,但 navigator.webdriver 必须为 falsecdp-proxy 已默认绕过)
- click 操作建议优先用 `mode='real-mouse'`CDP 真实鼠标事件),避免被 .click() 检测
- User-Agent 检查较弱,但 navigator.webdriver 必须为 false
- 点击走 `BrowserAct(input.click)`CDP 派发的真实指针事件),不要用页面内 `.click()`
## 速率限制
- 自评:单 IP 每分钟 ≤ 30 个详情页请求;超过会出验证码

View File

@@ -5,7 +5,7 @@ type: site-pattern
pinned: true
confidence: medium
learned_at: '2026-05-05'
updated_at: '2026-05-05'
updated_at: '2026-08-06'
---
## L0
@@ -18,8 +18,8 @@ updated_at: '2026-05-05'
## 推荐流程
1. 专栏文章 → WebFetch / Jina Reader 优先
2. 问答详情 → BrowserNavigate + BrowserEval批量回答用 `[...document.querySelectorAll('.AnswerItem')].map(...)`
3. 评论 → 必须登录BrowserClick 展开BrowserScroll 加载更多
2. 问答详情 → 内置浏览器 BrowserAct(tab.navigate) 到达;批量回答的正文抽取回落 Playwright`.AnswerItem`
3. 评论 → 必须登录BrowserAct(input.click ref) 展开BrowserAct(input.wheel) 加载更多
## 推荐选择器
- 文章标题:`h1.Post-Title` / `h1[class*='Title']`