关于 Web Speed
Web Speed 是供 Agent 使用的网页结构化 MCP 服务,可将网页转为包含标题、链接、表单和表格的地图,不依赖 LLM 处理内容。它还可抓取站点页面并分类,帮助 Agent 规划网页交互。
主要功能
- 01提取网页结构化地图
- 02提交表单并解析结果页
- 03抓取站点并生成页面地图
- 04按 CSS 选择器检查元素
- 05分类页面类型并管理缓存
适用场景
- 01从网页提取导航和正文链接
- 02规划跨多个页面的操作流程
- 03读取表单字段并提交数据
- 04检查商品列表或表格中的元素
MCP 相关
Web Speed 通过 MCP 向客户端提供六种网页工具,包括页面解析、表单提交、站点抓取、元素检查、页面分类和缓存失效。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
工具
本地服务需要在你的电脑上运行后才能读取工具,维护者暂未提供工具列表。
详细介绍
Web Speed
Web Speed 为 AI Agent 解决信噪比问题。现代 Web 面向人类阅读进行了优化(杂乱的 HTML、复杂的布局、以 JS 为主的界面),而 Web Speed 会将这些混乱内容转换为确定性的、高效利用令牌的结构化地图,专为高吞吐量的 Agent 集群而设计。
内部不含 AI。 不依赖 anthropic、openai 或任何大模型。所有解读都由调用它的 Agent 完成。
我们还建议为你选择的大模型设置一个主指令文件(gemini.md、“Claude 指令”等)。此处有一份示例文档。
存在的意义
| 问题 | Web Speed 解决方案 |
|---|---|
| 原始 HTML 包含超过 150,000 个字符的脚本、样式和 SVG 噪声 | 移除所有非结构化内容 → 最多减少 97% 的令牌用量 |
| 大模型会在原始 DOM 中臆造元素 ID,并遗漏交互点 | 返回一份固定的结构化地图——页面上有什么就有什么,不会凭空捏造 |
| 自定义爬虫会因网站不同而失效 | 确定性协议——Web 上的所有网站都使用相同的 JSON 结构 |
| Agent 必须每次往返都重新发现页面 | site_map 可在一次调用中爬取整个域名 |
工具
| 工具 | 描述 |
|---|---|
interpret_page | 完整的结构化地图:标题、导航、内容链接、表单、表格、文本、元数据 |
submit_form | 提交表单(GET 或 POST),并获取提交后页面的地图 |
site_map | 从根 URL 开始爬取,并返回所有页面的合并地图 |
inspect_element | 获取与 CSS 选择器匹配的节点的详细结构化数据 |
page_type | 即时页面分类——login、listing、article、form、navigation、other |
invalidate_cache | 清除缓存的地图,以便下次调用时获取最新内容 |
安装
Mac / Linux
cd web-interpreter
python3 -m venv venv
source venv/bin/activate
pip install -r requirements.txt
Windows
cd web-interpreter
python -m venv venv
venv\Scripts\activate
pip install -r requirements.txt
运行
使用 MCP 检查器进行本地开发:
mcp dev server.py
通过 stdio 直接运行(MCP 客户端的启动方式):
python server.py
注册到 Claude / Cowork
将以下内容添加到 ~/Library/Application Support/Claude/claude_desktop_config.json(Mac)或 Windows 上对应的配置文件中:
{
"mcpServers": {
"web-speed": {
"command": "/absolute/path/to/web-interpreter/venv/bin/python",
"args": ["/absolute/path/to/web-interpreter/server.py"]
}
}
}
然后退出并重新启动 Claude Desktop / Cowork。这六个工具将显示在 web-speed MCP 服务下。
读取本地开发服务(可选启用)
默认情况下,Web Speed 会阻止私有地址和环回地址(SSRF 防护),因此访问 http://127.0.0.1:8080
会返回 BLOCKED。如需读取自己的开发服务,请在 WEBSPEED_ALLOW_HOSTS 中列出确切的 host:port 对:
"web-speed": {
"command": "/absolute/path/to/web-interpreter/venv/bin/python",
"args": ["/absolute/path/to/web-interpreter/server.py"],
"env": { "WEBSPEED_ALLOW_HOSTS": "127.0.0.1:8080" }
}
- 使用逗号分隔;IPv6 地址需加方括号:
127.0.0.1:8080,[::1]:3000,localhost:5173。 - 主机名和端口必须完全匹配。
127.0.0.1:8080不会开放127.0.0.1:6379或任何其他地址。 - 必须始终指定端口,即使是 80 或 443 也不例外。
- 不支持通配符或 CIDR 范围。格式错误的条目会被忽略,因此拼写错误的地址仍会被阻止。
- 优先使用字面 IP 地址。添加主机名条目意味着信任该名称解析到的地址。
- 在服务会获取他人选择的 URL 的任何环境中,都不要设置此项。
测试
venv/bin/python -m unittest discover -s tests
输出架构
interpret_page
{
"url": "https://example.com/",
"fetched_at": "2025-01-01T12:00:00Z",
"page_type": "other",
"title": "Example Domain",
"description": "",
"headings": [
{ "level": 1, "text": "Example Domain" }
],
"navigation": [
{ "label": "Home", "url": "https://example.com/", "location": "header" }
],
"content_links": {
"total": 47,
"truncated": false,
"items": [
{ "label": "More information...", "url": "https://www.iana.org/domains/example" }
]
},
"forms": [
{
"id": "search",
"action": "https://example.com/search",
"method": "GET",
"fields": [
{
"name": "q",
"type": "text",
"label": "Search",
"placeholder": "Search...",
"required": false,
"value": ""
},
{
"name": "_csrf",
"type": "hidden",
"label": "",
"placeholder": "",
"required": false,
"value": "abc123"
}
]
}
],
"tables": [
{
"id": "results",
"headers": ["Name", "Price", "Stock"],
"rows": [["Widget A", "$9.99", "In stock"]]
}
],
"text_blocks": [
{ "tag": "p", "text": "This domain is for use in illustrative examples." }
],
"metadata": {
"lang": "en",
"canonical": "",
"open_graph": { "title": "", "description": "", "image": "" }
}
}
关键字段:
navigation— 语义化 nav/header/footer 元素中的链接(网站框架、菜单)。最多返回 60 个。content_links— 页面主体中的链接(文章、搜索结果、列表)。始终包含total,因此即使截断到 60 个,也能知道实际数量。forms— 每个表单及其所有字段;CSRF 令牌会在隐藏字段的value中原样保留。page_type— 根据结构推断:密码字段 →login;多个条目或链接 →listing;包含段落的<article>→article;表单 →form;以链接为主 →navigation。
page_type
轻量级工具——只返回分类结果。页面已缓存时可即时返回。
{
"url": "https://example.com/login",
"fetched_at": "2025-01-01T12:00:00Z",
"page_type": "login",
"title": "Sign In"
}
submit_form
与 interpret_page 输出格式相同,适用于服务器在提交后跳转到的页面。
{
"url": "https://example.com/login",
"method": "POST",
"fields": {
"email": "[email protected]",
"password": "hunter2",
"_csrf": "abc123"
}
}
CSRF 令牌按原样放入 fields 中——从先前 interpret_page 调用返回的 forms 数组中的隐藏字段提取。
inspect_element
获取匹配 CSS 选择器的节点的深层结构化数据。最多返回 25 个元素。
{
"url": "https://example.com/shop",
"selector": ".product-card",
"matched": 48,
"truncated": true,
"elements": [
{
"tag": "div",
"id": "product-42",
"classes": ["product-card", "featured"],
"text": "Widget Pro $49.99 Add to cart",
"attributes": { "id": "product-42" },
"links": [{ "label": "Add to cart", "url": "https://example.com/cart/add/42" }],
"fields": [],
"children": [
{ "tag": "h3", "text": "Widget Pro" },
{ "tag": "span", "text": "$49.99" },
{ "tag": "a", "text": "Add to cart", "href": "https://example.com/cart/add/42" }
]
}
]
}
选择器示例:#login-form、.product-card、table.results tbody tr、nav a、[data-testid="price"]
site_map
{
"root_url": "https://example.com",
"crawled_at": "2025-01-01T12:00:00Z",
"total_pages": 8,
"pages": [
{
"url": "https://example.com",
"title": "Home",
"page_type": "navigation",
"depth": 0,
"links_to": ["https://example.com/about", "https://example.com/contact"]
}
],
"all_forms": [
{
"found_on": "https://example.com/contact",
"id": "contact",
"action": "https://example.com/contact/submit",
"method": "POST",
"fields": [
{ "name": "email", "type": "email", "label": "Your email", "placeholder": "", "required": true, "value": "" },
{ "name": "message", "type": "textarea", "label": "Message", "placeholder": "", "required": true, "value": "" }
]
}
],
"all_navigation": [
{ "label": "About", "url": "https://example.com/about" },
{ "label": "Contact", "url": "https://example.com/contact" }
]
}
invalidate_cache
{ "url": "https://example.com", "invalidated": true }
错误
工具不会抛出异常。发生故障时:
{
"error": true,
"code": "FETCH_FAILED | PARSE_FAILED | TIMEOUT | NOT_HTML",
"message": "human-readable explanation",
"url": "https://example.com/broken"
}
Agent 应如何使用输出
浏览网站:
查看 navigation 获取网站框架元素(菜单、页眉、页脚),查看 content_links 获取页面正文中的链接。即使列表被截断,content_links.total 也会告知链接总数。选择符合目标的链接,然后调用 interpret_page。
提交表单:
查看 forms。每个字段都包含 name(要发送的内容)、type(预期数据类型)、label/placeholder(字段用途)、required 和 value。隐藏字段(type: "hidden")携带 CSRF 令牌——将其 value 原样传回。构建一个扁平的 name → value 字典,然后调用 submit_form。
提交前先分类:
如果需要分支处理逻辑(例如判断当前页面是登录页还是仪表板),但不想花费完整调用 interpret_page 的成本,请先调用 page_type。
深入查看组件:
在地图中看到表格,但想查看各行?看到商品列表,但想获取每张卡片的链接和价格?调用 inspect_element 并传入 CSS 选择器,即可获取这些特定节点的结构化详情,而无需重新加载整个页面。
预先规划多步骤工作流:
开始前调用 site_map。你会获得每个页面的标题、类型、深度和出站链接,以及网站上的所有表单——无需一次往返,就能规划完整工作流(查找登录表单、查找数据录入页面、查找提交端点)。
page_type 是参考信号,而非保证:
分类结果基于启发式判断。提供空 HTML 外壳的 JavaScript 渲染型 SPA 通常会被归类为 other——密码字段要等 JavaScript 运行后才会出现在 HTML 中。将 page_type 作为快速筛选依据,然后根据实际的 forms 和 headings 进行验证。
共享注册表同步
默认情况下,OSS 服务每次构建新的页面地图时,都会异步提交到 Web Speed 共享注册表 api.getwebspeed.io。这是众包飞轮——每个获取 URL 的 Agent 都会将其加入全局缓存,让世界各地的下一个 Agent 即时获得响应。
此功能默认启用,仅可选择退出。 默认开启是因为贡献者越多,所有 Agent 的运行速度就越快。
共享内容
仅共享页面结构数据:
- 页面类型、标题、描述
- 标题、导航链接、内容链接
- 表单字段名称、类型和标签(不含值)
- 表格、文本块
- Open Graph 元数据
绝不共享: Cookie、会话令牌、表单值、JS 渲染的地图(其中可能包含特定会话的登录状态)。
禁用同步
启动服务前设置环境变量:
WEB_SPEED_REGISTRY_SYNC=false python server.py
或在 MCP 客户端配置中设置:
{
"mcpServers": {
"web-speed": {
"command": "/path/to/venv/bin/python",
"args": ["/path/to/server.py"],
"env": {
"WEB_SPEED_REGISTRY_SYNC": "false"
}
}
}
}
指向可自托管的注册表
如果你在运行自己的托管实例,可将同步目标设为该实例:
WEB_SPEED_REGISTRY_URL=https://your-instance.example.com python server.py
同步行为
- 发出后即不再等待:贡献内容会在后台发送。无论 ping 是否成功,Agent 的请求都会以全速完成。
- 仅在缓存未命中时同步:本地 24h 磁盘缓存中已有的地图不会重新发送。
- 故障静默处理:网络错误、超时和服务器拒绝仅记录在 DEBUG 级别,不会反馈给 Agent。
架构
URL ──▶ fetcher.py (httpx: 10s timeout, 5 redirects, Chrome UA
▼ OR Playwright headless Chromium for js=true)
cleaner.py (BeautifulSoup/lxml: strip noise, split nav vs content
▼ links, filter layout tables, deduplicate text blocks,
structured map infer page_type, detect auth_gated)
▼
cache.py (24h TTL, MD5 keyed JSON files in ./cache/)
▼
registry_sync.py (fire-and-forget POST to api.getwebspeed.io/v1/contribute)
▼
server.py (FastMCP: 8 tools over stdio)
没有 AI。没有解读。Agent 才是大脑。
已知限制
- 由 JS 渲染的 SPA:通过 JavaScript(React、Vue、Angular)加载内容的页面只会返回预渲染的 HTML 框架。由 JS 注入的密码字段、搜索结果和导航内容会缺失。请对可见内容使用
inspect_element,并在 SPA 占比较高的目标页面中搭配浏览器自动化工具使用。 page_type启发式判断:分类依据页面结构,速度快但并非万无一失。包含大量站内链接的营销页面可能会被归类为listing;有邮箱字段但没有密码字段的页面则不会被归类为login。- 缓存存储在本地磁盘:
./cache/目录位于本地。在多进程或分布式部署中,各实例之间不会共享缓存条目。如需共享缓存,请将cache.py替换为 Redis 或 Memcached 后端。 - 未实施速率限制:Web Speed 不会限制出站请求。对于高请求量的 Agent 集群,请在服务前部署速率限制代理(例如 Cloudflare、nginx)。
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。