内容
# turbo-surf
> 原生速度,无浏览器网页爬虫 + AI 代理 **MCP 服务器** - 构建于 [turbo-dom](https://github.com/miaskiewicz/turbo-dom) 之上。获取 + 解析 + 提取 + 运行页面 JS,无需无头浏览器;服务端渲染页面速度快 100 倍以上。
turbo-surf 是一个单一的原生(Rust)引擎 - 无 Chromium,无像素,无布局:
- **爬虫** - 指向一个域名并流式传输页面记录:索引交互元素、链接/表单图、辅助树、markdown 和纯文本视图、渲染 HTML 捕获、CSS/XPath 节点查询和模式驱动的结构化提取。
- **代理工具** - 一个 60 工具的 **MCP** 服务器代理直接通过 stdio(`crawl`、`batch`、`navigate`、`click/fill/submit`、`query`、`extract`、`accessibility tree`、`markdown`、`render`/`eval_js`/`inject_js`、`cookies/headers`、`snapshot`)。
对于需要 JavaScript 的页面,它运行其脚本 - 要么通过挖掘服务器嵌入的水分状态,要么通过在 **真正的 V8 隔离**(无浏览器)中执行页面 JS 并重新渲染 DOM。其页面 API 类似于 Playwright:基准测试套件使用未修改的 Playwright 脚本驱动引擎。
## 有什么不同
该领域中的大多数工具选择一条路线:爬虫 **或** 浏览器自动化库,它们从真正的浏览器(Playwright/Puppeteer/Selenium)或进程内假 DOM(无安全隔离)获取 DOM(jsdom,happy-dom)。turbo-surf 在四个方面同时是不同的:
1. **开箱即用的 AI 代理支持**。它附带一个完整的 **MCP 服务器**(60 个工具:导航、点击/填充/提交、查询、提取、辅助树、markdown、`crawl` 整个网站、`batch` URL 列表、`render`/`set_mode` 运行页面 JS、`eval_js`/`inject_js` 针对实时渲染堆与 DOM 历史记录、cookie/header、`snapshot`...),因此代理可以直接驱动真实页面,无需浏览器和胶水代码 - `npx turbo-surf-mcp`。大多数爬虫是需要自己包装的库;这个是一个日第一的代理工具。
2. **单个原生引擎上的爬虫 + 代理表面**。同一个引擎批量爬取一个域名并提供 MCP 工具 - 栈中没有任何浏览器。其页面 API 类似于 Playwright(基准测试套件在上面运行未修改的 Playwright 例程)。
3. **它自己的 DOM,不是浏览器的**。turbo-dom 是一个原生 + WASM HTML 解析器,具有延迟复制写入 DOM - 原生速度解析,无像素/布局/IPC。
4. **V8 隔离运行页面 JS + 重新渲染**。页面(或您自己的)JavaScript 在真正的 V8 隔离(`deno_core` 运行时 - 宿主堆栈无法访问客人,具有失控执行预算)中运行,针对原生 rtdom DOM,然后重新渲染。大多数具有 JS 能力的爬虫驱动一个完整的无头浏览器,或者在进程中使用假 DOM 运行页面脚本,没有真正的安全隔离(Node 的 `vm` [明确不是安全边界](https://nodejs.org/api/vm.html);参见 happy-dom [CVE-2025-61927](https://github.com/capricorn86/happy-dom/wiki/JavaScript-Evaluation-Warning))。
参见 [CHANGELOG.md](./CHANGELOG.md) 以了解已发布的内容和 [rust/README.md](./rust/README.md) 以了解引擎内部。
状态:**v0.2.2 - 工作**([npm](https://www.npmjs.com/package/turbo-surf))。一个原生 Rust 引擎(`turbo-dom` crate 上的 7-crate 工作区):强化网络(cookie / `document.cookie` 桥 / robots + crawl-delay / 字符集 / 大小 + 重定向上限,HTTP/2 + 池化客户端,304 条件缓存),爬取协调(全局 + 每主机并发,令牌桶礼貌,后退/重试,规范重复,深度/页面上限),结构化提取,CSS + XPath 查询,无 Chromium 的 JS 渲染层(真正的 V8 隔离原生 DOM)与可重入的实时堆 `eval_js`/`inject_js` + DOM 历史记录,和 60 工具的 MCP 服务器(原生二进制)。针对真实浏览器 + 其他爬虫进行基准测试(如下)。
## 安装
npm 包是一个薄启动器,启动原生二进制:
```sh
npm install -g turbo-surf # 提供 `turbo-surf-mcp` 命令
# … 或在不安装的情况下运行:
npx -y turbo-surf-mcp
```
Node ≥ 20 启动;引擎是每个平台预构建的原生二进制(无 Node 运行时托管它)。
### 发布内容
turbo-surf 从 **一个 `v*` git 标签** 发布到两个注册表(参见 [PUBLISHING.md](./PUBLISHING.md)):
| Artifact | Registry | What it is | For |
|---|---|---|---|
| [`turbo-surf`](https://www.npmjs.com/package/turbo-surf) | **npm** | 一个薄启动器(`cli.js`/`index.js`)**+ 预构建的 `turbo-surf-mcp` 二进制文件**,每个平台的 `bin/` 目录(darwin x64/arm64,linux x64/arm64-gnu,win x64)。`npx` 解析正确的并启动它。 | 运行 **MCP 服务器** / CLI。无 Rust 工具链,无 Chromium,无 Node 托管 Rust。 |
| `turbo-surf-core`、`-view`、`-page`、`-render`、`-mcp` | **crates.io** | Rust crates,按依赖顺序。 | **嵌入** 引擎到 Rust 程序中。 |
`turbo-surf-napi` cdylib 和 `turbo-surf-transform` crate **未** 发布 - napi 仅用于开发工具包 + Playwright 垫片。
## MCP 服务器(代理)
```sh
npx turbo-surf-mcp # stdio MCP 服务器(60 个工具),例如:
# 导航: goto, go_back, go_forward, reload, set_user_agent
# 内容: interactive_elements, accessibility_tree, aria_snapshot, markdown,
# text, html, links, requests, snapshot, query, get_by,
# hydration_state, extract
# 交互: click, fill, submit, click_selector, fill_selector, select_option,
# check, uncheck, fill_many, find_text, forms, extract_links
# 访问器: get_attribute, text_content, inner_html, input_value, count,
# is_visible, is_checked, is_enabled, is_editable, is_focused,
# is_empty, aria_role, accessible_name, accessible_description
# 批量: crawl, batch
# 渲染/JS: render, set_mode, eval_js, inject_js, latest_dom, dom_history,
# evaluate, detect_js, run_playwright
# 会话: get_cookies, set_cookie, set_extra_headers, robots_check
# 直接: fetch_json, fetch_raw
```
`render`/`set_mode` 将页面切换到 JS 渲染层(原生 DOM 上的真正 V8 隔离);然后 `eval_js` 和 `inject_js` 运行在 **实时渲染堆**(页面全局变量,处理程序)并且每个突变都追加到可通过 `latest_dom`/`dom_history` 读取的 DOM 历史记录。
`run_playwright` 直接执行 **Playwright 风格的脚本** - `page` / `locator` / `getBy*` / `expect`(带有 `.not`)/ `test()` 块 - 在引擎上,无浏览器。参数: `{ script, url?, testIdAttribute? }`(`url` 导航首先,遵守 `set_mode` 以便 SPA 水分)。它返回 `{ ok, ran, logs }` 或 `{ ok:false, error, logs }` - 失败的断言是一个结果,而不是工具错误:
```jsonc
// 工具/调用 run_playwright
{ "url": "https://example.com", "testIdAttribute": "data-test-id",
"script": "await expect(page.locator('h1')).toHaveText('Example Domain');\nawait page.fill('#q','rust');\nawait expect(page.locator('#q')).toHaveValue('rust');" }
```
### 在 Claude Code 中设置(一步一步)
从未设置过 MCP 服务器?这是整个过程 - 三个命令。
**1. 检查先决条件。** 您需要 [Node ≥ 20](https://nodejs.org)(`node -v`)和 [Claude Code CLI](https://docs.claude.com/en/docs/claude-code)(`claude --version`)。就是这样 - **没有 Rust,没有 Chromium,没有构建步骤**。`npx` 在您第一次运行时下载一个小的启动器和预构建的原生二进制文件。
**2. 注册服务器。** 运行此命令一次(`--` 将 Claude 的标志与 Claude 将启动的命令分开):
```sh
claude mcp add turbo-surf -- npx -y turbo-surf-mcp
```
这将服务器写入您的 Claude Code 配置。`npx -y turbo-surf-mcp` 解析并启动原生二进制文件通过 stdio - 一个进程,无 Node 托管它,无浏览器。
**3. 验证它已连接。** 列出您的服务器(查找 `turbo-surf` → `✓ connected`):
```sh
claude mcp list
```
现在启动(或重启)Claude Code 并要求它,例如,**使用 turbo-surf 获取 example.com 的 markdown** - 上面有 60 个工具。
**范围(服务器注册的位置)。** 默认情况下,它为您注册。对于存储库,请添加 `--scope project` - 这会编写一个 `.mcp.json`,您可以提交:
```jsonc
// .mcp.json - 已提交;队友自动获取服务器
{
"mcpServers": {
"turbo-surf": { "command": "npx", "args": ["-y", "turbo-surf-mcp"] }
}
}
```
**从检出运行(贡献者)** - 指向本地构建而不是 npm:
```sh
cargo build --release -p turbo-surf-mcp --manifest-path rust/Cargo.toml
claude mcp add turbo-surf -- "$PWD/rust/target/release/turbo-surf-mcp"
```
**故障排除。** `command not found: claude` → 安装 Claude Code CLI。`npx` 挂起第一次运行 → 它正在下载二进制文件;让它完成(或使用 `npx -y turbo-surf-mcp` 在终端中,然后 Ctrl-C)。显示 `✗ failed` 在 `claude mcp list` → 直接运行命令查看错误;在不支持的平台上没有预构建的二进制文件(从上面的检出构建)。
**其他 MCP 客户端**(Claude Desktop,Cursor,...)- 将他们的 MCP 配置的 `command` 指向 `npx` 并使用参数 `["-y", "turbo-surf-mcp"]`,或二进制文件路径。
## Playwright 替代(使用您的 e2e 规范,无浏览器)
turbo-surf 的页面 API 类似于 Playwright,并且 `rust/playwright-shim/` 是一个 **直接替换 `@playwright/test`** 的垫片引擎 - **无 Chromium**。解析钩子模块重写每个 `import … from "@playwright/test"`(和 `playwright` / `playwright-core`)到垫片,因此现有规范 **不变** 在 `node:test` 上:
```sh
node --import ./rust/playwright-shim/register.mjs --test 'e2e/**/*.spec.mjs'
```
它实现了 **Page**、**Locator**、**expect**(所有五个断言类)、**BrowserContext**、**APIRequestContext** 和 **test + fixtures** 引擎:导航,每个 `getBy*` 定位器,定位器组合/过滤,DOM 操作(`click`/`fill`/`check`/`selectOption`/…),`evaluate`/`render` 在 V8 层,cookie + 真实的 `setExtraHTTPHeaders`,以及完整的匹配器集。大多数表面是纯 JS,从不进入 Rust;只有真正的 DOM/渲染语义做(并且 `expect(locator)` 链被批处理为一个穿越)。
什么无浏览器引擎 **物理上无法做到** 的行为诚实地失败(它抛出或无操作 - 从不静默通过):
| 桶 | 示例 | 行为 |
|---|---|---|
| 像素/布局 | `screenshot`、`pdf`、`boundingBox`、`toHaveScreenshot`、`toMatchSnapshot` | **抛出** |
| 输入硬件 | `hover`、`dragTo`、`mouse`/`keyboard`/`touchscreen` | **抛出** |
| 网络拦截 | `route`、`routeFromHAR`、`unroute` | **抛出** |
| JS↔主机绑定 | `exposeFunction`、`exposeBinding` | **抛出** |
| 真正的异步/时间 | `waitFor*`,|实时` `console`/`request` 事件,定时器驱动的突变 | 解决/无操作静态 DOM |
| 布局状态 | `viewportSize`、`emulateMedia`、帧 | 存储/崩溃为自身 |
| 像素/布局 | `screenshot`、`pdf`、`boundingBox`、`toHaveScreenshot`、`toMatchSnapshot` | **抛出** |
| 输入硬件 | `hover`、`dragTo`、`mouse`/`keyboard`/`touchscreen` | **抛出** |
| 网络拦截 | `route`、`routeFromHAR`、`unroute` | **抛出** |
| JS↔主机绑定 | `exposeFunction`、`exposeBinding` | **抛出** |
| 真正的异步/时间 | `waitFor*`,实时 `console`/`request` 事件,定时器驱动的突变 | 解决/无操作静态 DOM |
| 布局状态 | `viewportSize`、`emulateMedia`,帧 | 存储/崩溃为自身 |
完整的方法覆盖范围:[`rust/playwright-shim/LIMITATIONS.md`](./rust/playwright-shim/LIMITATIONS.md)。最佳选择:**服务端渲染和导航时水合**应用。完全由 JS 绘制的客户端 SPA(加载后完全不重新获取)需要一个真正的浏览器。
## 竞争性基准测试
`harness/competitive/` 运行 **相同的 Playwright 脚本** 在 turbo-surf 和浏览器舰队上,针对 Chromium 代理的输出 **一致性** 进行评分并计时。`npm run harness`。turbo-surf 通过其原生引擎驱动每个例程 - turbo-dom + `deno_core` V8 渲染层用于页面 JS - 无 Chromium。 中位数毫秒超过 8 次运行(实时网络),一致性是每个引擎的观察结果与 Chromium 代理的对比:
| 引擎 | 维基百科 | js-quotes | 一致性 |
|---|---|---|---|
| **turbo-surf(无 JS)** | **142** | - *(需要 JS)* | ✓ |
| **turbo-surf(JS)** | -‡ | **132** | ✓ |
| chromium *(oracle)* | 932 | 933 | - |
| firefox | 727 | 925 | ✓ |
| webkit | 1232 | 964 | ✓ |
每个引擎都产生与 Chromium / Firefox / WebKit **相同的观察结果**(一致性 ✓)- 而 turbo-surf 是表格中 **最快的引擎** 在两个坐标轴上。维基百科的点击率在 **142 毫秒**(**比 Chromium 快 ~6.6 倍**,932),以及 `quotes.toscrape.com/js` 上的 **实际 jQuery** - Chromium 提取的相同 10 个引用 - 在 **132 毫秒**(**比 Chromium 快 ~7 倍**,933)内,使用真正的 V8 隔离在原生 rtdom DOM 上,**无 Chromium 进程**。它通过 **连接池化 HTTP 客户端** 保持网络绑定(页面间重用连接/ TLS),**持久 V8 隔离**,其 DOM 安装在同一页面内 `page.evaluate` 中重复使用(一次解析每个页面,调用后 ~0.5 毫秒),**外部脚本缓存**(jQuery 只取一次,不按页面),**每个页面的解析缓存**,以及后退-前进快照缓存,因此 `goBack` 恢复而不是重新获取。分析器:`cargo bench -p turbo-surf-view`(Rust 微基准)+ `harness/hotpath/rust-hotpath.mjs`。
‡ JS 模式运行页面的**自身**脚本;在像维基百科这样的服务端渲染页面上过度运行(使用无 JS 的方式 - 142 毫秒,4/4)。`form` 例程在此运行中被省略(httpbin.org 返回 503/超时,每个引擎)。
测试框架自动检测已安装的引擎(`firefox`/`webkit`,以及像 `playwright-extra`/`patchright`/`rebrowser-playwright` 这样的浏览器检测工具);参见 [harness/competitive/README.md](./harness/competitive/README.md).
## 爬虫 vs 爬虫基准测试
`harness/crawlers/` 将 turbo-surf 与其他开源爬虫在实际的分页网站上进行对比 - **相同** 20 页的相同主机爬取 `books.toscrape.com`,**相同** 约 150 毫秒每请求礼貌度,每个引擎上使用 **相同** 的 CSS 选择器计数项。 中位数 3 次计时运行,实时网络(`npm run crawl-bench`):
| 爬虫 | 运行时模型 | 项目 | 中位数毫秒 | 页面/秒 |
|---|---|---|---|---|
| crawlee `CheerioCrawler` | Node | 339 | 2767 | 7.2 |
| **turbo-surf(无 js)** | **原生 Rust,无浏览器** | 339 | 3271 | **6.1** |
| spider-rs | Rust + N-API | 194 | 3486 | 5.7 |
| got + cheerio(手工制作) | Node | 339 | 5590 | 3.6 |
| node-crawler (`crawler`) | Node | 339 | 49624 | 0.4 |
| Scrapy | Python *(子进程)* | 246 | 49270 | 0.4 |
| Colly | Go *(子进程)* | 320 | 45664 | 0.4 |
**与 CheerioCrawler 对比**(最接近的竞争者)- **相同** 20 页爬取,`maxConcurrency = | 引擎 | 礼貌度 | 中位数毫秒 | 页面/秒 |
|---|---|---|---|
| **turbo-surf(无 js)** | 无(原始) | **1977** | **10.1** |
| crawlee CheerioCrawler | 无(原始) | 2748 | 7.3 |
| crawlee CheerioCrawler | 150 毫秒速率 | 2634 | 7.6 |
| **turbo-surf(无 js)** | 150 毫秒(严格) | 3307 | 6.0 |
原始,**turbo-surf 快 ~1.4 倍**。在“150 毫秒礼貌度”行中,看起来较慢只是因为 turbo-surf 的每主机门控是 **严格** 间隔(它真正等待 150 毫秒主机之间),而 crawlee 的 `maxRequestsPerMinute` 是一个宽容的滑动窗口,允许一个短的 20 页突发几乎原始。通过 **相同** 内容(339 项),无浏览器。
在相同的礼貌度下,多引擎的墙上时钟是 **网络绑定** 的,因此进程内爬虫聚集在一起:turbo-surf 位于 **顶部** 层级,与专用速度引擎(crawlee,spider-rs)并列,并在内存中击败手工制作的 got+cheerio 循环 - 同时提取 **等效** 内容并运行 **无浏览器**。turbo-surf 在其原生 Rust 引擎中运行整个 BFS - 获取,解析,主机门控,每个页面计数项 - 并且 **比 Scrapy/Colly 快 ~13 倍**。重量级引擎落后 ~15 倍:Scrapy 和 Colly 为每个爬取支付一个新进程启动(测试框架使用 CLI 调用),node-crawler 的每个请求开销很高。 turbo-dom 的原始解析优势在这里 **不** 显示 - 在 20 个实时页面上,网络覆盖了亚毫秒级解析;它在内存中显示(链接 ~18k/s,爬取 ~14k 页面/s,以下)。而 turbo-surf 与其他引擎不同,**相同** turbo-surf 也运行 Playwright 脚本(上面的 parity 表)。
### 执行 JS 的爬虫 - turbo-surf 与真正的浏览器
另一组以 `quotes.toscrape.com/js` 为目标,其中引用是客户端构建的(非 JS 爬虫看到 ~0)。turbo-surf 在原生 rtdom DOM 上的真正 V8 隔离中运行页面的脚本,而每个竞争者都驱动一个 **真正的无头 Chromium**(`npm run crawl-bench:js`,10 个页面,中位数 3 次):
| 爬虫 | JS 引擎 | 项目 | 中位数毫秒 | 页面/秒 |
|---|---|---|---|---|
| **turbo-surf(JS)** | **V8 隔离,无浏览器** | 100 | **2989** | **3.35** |
| crawlee `PuppeteerCrawler` | 无头 Chromium | 100 | 5074 | 2.0 |
| crawlee `PlaywrightCrawler` | 无头 Chromium | 100 | 6173 | 1.6 |
| puppeteer-cluster | 无头 Chromium | 100 | 17062 | 0.6 |
turbo-surf 在 **真正的 V8 隔离** 中运行每个页面的脚本在原生 rtdom DOM 上(与渲染 `quotes.toscrape.com/js` 相同的路径,跨页面缓存外部脚本)- **最快的引擎**,提取与真正的浏览器相同的 100 个引用 **快 ~2-6 倍**,无 Chromium 进程并且遵守 150 毫秒的礼貌延迟。运行真正的隔离对抗轻量级 DOM 是罕见的 - 大多数爬虫驱动完整的浏览器(本表格)或使用进程内假 DOM 无真正隔离。参见 [harness/crawlers/README.md](./harness/crawlers/README.md) - 竞争者自动检测,缺失的跳过;使用 `npm i -D @spider-rs/spider-rs crawlee cheerio got crawler` (+ `brew install pipx go && pipx install scrapy` for Scrapy/Colly) 安装。
## 开发
引擎是 Rust(`rust/` 工作区);唯一的 JS 是启动器(`cli.js`/`index.js`)+ 开发工具包。
```sh
cd rust
cargo test --workspace # 离线套件
cargo clippy --workspace --all-targets
cargo fmt
cargo build --release -p turbo-surf-mcp # 启动器启动的 MCP 二进制文件
cargo bench -p turbo-surf-view # Rust 微基准测试(解析/视图)
```
从仓库根目录:`npm run check` 检查/格式化启动器 JS,运行 Rust 网关,并运行 **Playwright shim** 套件(`npm run test:playwright` = `build:addon` → `test:shim` 离线单元测试 → `test:e2e` 替代规范通过 `register.mjs`,无 Chromium)。`npm run harness` / `crawl-bench` / `hotpath` 运行基准测试(为竞争引擎安装 `playwright` + `crawlee` ad-hoc)。
## 许可证
MIT
MCP 配置
以下是此 MCP Server 的配置信息,可直接复制到 Cursor 或其他 MCP 客户端中使用。
mcp.json
连接信息
猜你喜欢
暂无推荐服务器