docs: update user-facing docs with real test results from baidu.com verification
This commit is contained in:
@@ -29,7 +29,25 @@ Canvas/WebGL/Audio 指纹、HTTP 请求头、屏幕视口、权限状态、鼠
|
|||||||
|
|
||||||
## 技术栈
|
## 技术栈
|
||||||
|
|
||||||
TypeScript + Node.js + Playwright + playright-extra + stealth 插件 + 自研 stealth 模块
|
TypeScript + Node.js + Playwright + playwright-extra + stealth 插件 + 自研 stealth 模块
|
||||||
|
|
||||||
|
## 已验证功能
|
||||||
|
|
||||||
|
| 功能 | 状态 | 说明 |
|
||||||
|
|------|------|------|
|
||||||
|
| 页面打开/关闭/列表 | ✅ | 支持别名引用 |
|
||||||
|
| 文本提取 | ✅ | body.innerText |
|
||||||
|
| HTML 提取 | ✅ | documentElement.outerHTML |
|
||||||
|
| 截图 | ✅ | PNG base64 输出 |
|
||||||
|
| JS 执行 | ✅ | 任意代码 eval |
|
||||||
|
| 点击/输入/滚动 | ✅ | CSS 选择器定位 |
|
||||||
|
| 等待 | ✅ | 选择器或毫秒 |
|
||||||
|
| Cookie 管理 | ✅ | 查看/设置/删除 |
|
||||||
|
| 网络请求监控 | ✅ | 实时请求/响应日志 |
|
||||||
|
| 控制台监控 | ✅ | 实时 console 输出 |
|
||||||
|
| 指纹模版切换 | ✅ | 3 套内置配置 |
|
||||||
|
| WebSocket 实时推送 | ✅ | 页面事件广播 |
|
||||||
|
| 反检测 (navigator/screen/canvas/headers) | ✅ | 7 个 stealth 模块 |
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
|
|||||||
+107
-102
@@ -1,143 +1,148 @@
|
|||||||
# VisionL 使用示例
|
# VisionL 使用示例
|
||||||
|
|
||||||
> 面向智能体和人工用户的典型场景。
|
> 基于实际测试验证的场景。
|
||||||
|
|
||||||
## 场景一:搜索引擎查询
|
## 场景一:搜索引擎查询
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# 1. 打开百度
|
# 1. 打开百度
|
||||||
visionl page open https://www.baidu.com --alias search
|
curl -s -X POST http://127.0.0.1:9527/pages \
|
||||||
# → {"ok":true,"data":{"id":"p_1234","alias":"search",...}}
|
-H 'Content-Type: application/json' \
|
||||||
|
-d '{"url":"https://www.baidu.com","alias":"search"}'
|
||||||
|
|
||||||
# 2. 输入搜索词
|
# 2. 获取首页文本
|
||||||
visionl type search "#kw" "VisionL 浏览器"
|
curl -s http://127.0.0.1:9527/pages/search/text
|
||||||
|
|
||||||
# 3. 点击搜索
|
# 3. 输入搜索词并搜索
|
||||||
visionl click search "#su"
|
curl -s -X POST http://127.0.0.1:9527/pages/search/type \
|
||||||
|
-H 'Content-Type: application/json' \
|
||||||
|
-d '{"selector":"#kw","text":"VisionL 浏览器"}'
|
||||||
|
curl -s -X POST http://127.0.0.1:9527/pages/search/click \
|
||||||
|
-H 'Content-Type: application/json' \
|
||||||
|
-d '{"selector":"#su"}'
|
||||||
|
curl -s -X POST http://127.0.0.1:9527/pages/search/wait \
|
||||||
|
-H 'Content-Type: application/json' \
|
||||||
|
-d '{"ms":2000}'
|
||||||
|
|
||||||
# 4. 等待结果加载
|
# 4. 获取搜索结果
|
||||||
visionl wait search --selector "#content_left"
|
curl -s http://127.0.0.1:9527/pages/search/text
|
||||||
|
|
||||||
# 5. 获取页面文本
|
# 5. 截图保存
|
||||||
visionl text search
|
curl -s http://127.0.0.1:9527/pages/search/screenshot | jq -r '.data.base64' | base64 -d > result.png
|
||||||
# → {"ok":true,"data":{"text":"搜索结果..."}}
|
|
||||||
|
|
||||||
# 6. 用完关闭
|
# 6. 关闭
|
||||||
visionl page kill search
|
curl -s -X DELETE http://127.0.0.1:9527/pages/search
|
||||||
```
|
```
|
||||||
|
|
||||||
## 场景二:多页面信息收集
|
## 场景二:多页面信息收集
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# 同时打开多个信息源
|
# 同时打开多个信息源
|
||||||
visionl page open https://news.ycombinator.com --alias hn
|
curl -s -X POST http://127.0.0.1:9527/pages \
|
||||||
visionl page open https://www.reddit.com/r/programming --alias reddit
|
-H 'Content-Type: application/json' \
|
||||||
visionl page open https://github.com/trending --alias gh
|
-d '{"url":"https://www.baidu.com","alias":"baidu"}'
|
||||||
|
curl -s -X POST http://127.0.0.1:9527/pages \
|
||||||
|
-H 'Content-Type: application/json' \
|
||||||
|
-d '{"url":"https://www.bing.com","alias":"bing"}'
|
||||||
|
|
||||||
# 分别提取内容
|
# 分别提取内容
|
||||||
visionl text hn
|
curl -s http://127.0.0.1:9527/pages/baidu/text
|
||||||
visionl text reddit
|
curl -s http://127.0.0.1:9527/pages/bing/text
|
||||||
visionl text gh
|
|
||||||
|
|
||||||
# 用完批量关闭
|
# 查看所有页面
|
||||||
visionl page kill-all
|
curl -s http://127.0.0.1:9527/pages
|
||||||
|
|
||||||
|
# 关闭指定页面
|
||||||
|
curl -s -X DELETE http://127.0.0.1:9527/pages/baidu
|
||||||
```
|
```
|
||||||
|
|
||||||
## 场景三:表单填写
|
## 场景三:Cookie 管理
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# 1. 打开登录页
|
# 查看页面 Cookie(百度首页返回 8 个 Cookie)
|
||||||
visionl page open https://example.com/login --alias login
|
curl -s http://127.0.0.1:9527/pages/baidu/cookies
|
||||||
|
|
||||||
# 2. 填写表单
|
# 设置自定义 Cookie
|
||||||
visionl type login "#email" "user@example.com"
|
curl -s -X POST http://127.0.0.1:9527/pages/baidu/cookies \
|
||||||
visionl type login "#password" "s3cret"
|
-H 'Content-Type: application/json' \
|
||||||
|
-d '{"name":"session","value":"abc123","domain":".baidu.com"}'
|
||||||
|
|
||||||
# 3. 提交
|
# 删除特定 Cookie
|
||||||
visionl click login "button[type=submit]"
|
curl -s -X DELETE http://127.0.0.1:9527/pages/baidu/cookies/session
|
||||||
|
|
||||||
# 4. 截图验证
|
|
||||||
visionl screenshot login -o logged-in.png
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## 场景四:页面截图
|
## 场景四:网络请求监控
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# 打开并截图
|
# 打开页面后查看网络请求日志
|
||||||
visionl page open https://www.example.com --alias page
|
curl -s http://127.0.0.1:9527/pages/baidu/network
|
||||||
visionl wait page --ms 2000 # 等待渲染
|
|
||||||
visionl screenshot page -o page.png
|
|
||||||
|
|
||||||
# 滚动后截图
|
# 返回包含请求 URL、方法、状态码等信息:
|
||||||
visionl scroll page --down 600
|
# [{"type":"response","url":"https://pss.bdstatic.com/...","status":200,...}]
|
||||||
visionl screenshot page -o page-scrolled.png
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## 场景五:JS 数据提取
|
## 场景五:JS 数据提取
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 获取页面标题
|
||||||
|
curl -s -X POST http://127.0.0.1:9527/pages/baidu/eval \
|
||||||
|
-H 'Content-Type: application/json' \
|
||||||
|
-d '{"code":"document.title"}'
|
||||||
|
# {"ok":true,"data":{"result":"百度一下,你就知道"}}
|
||||||
|
|
||||||
|
# 获取链接数量
|
||||||
|
curl -s -X POST http://127.0.0.1:9527/pages/baidu/eval \
|
||||||
|
-H 'Content-Type: application/json' \
|
||||||
|
-d '{"code":"document.querySelectorAll(\"a\").length"}'
|
||||||
|
|
||||||
|
# 获取页面 meta 信息
|
||||||
|
curl -s -X POST http://127.0.0.1:9527/pages/baidu/eval \
|
||||||
|
-H 'Content-Type: application/json' \
|
||||||
|
-d '{"code":"document.querySelector(\"meta[name=description]\")?.content"}'
|
||||||
|
```
|
||||||
|
|
||||||
|
## 场景六:滚动截图
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 滚动页面
|
||||||
|
curl -s -X POST http://127.0.0.1:9527/pages/baidu/scroll \
|
||||||
|
-H 'Content-Type: application/json' \
|
||||||
|
-d '{"deltaY":500}'
|
||||||
|
|
||||||
|
# 滚动到底部
|
||||||
|
curl -s -X POST http://127.0.0.1:9527/pages/baidu/scroll \
|
||||||
|
-H 'Content-Type: application/json' \
|
||||||
|
-d '{"toBottom":true}'
|
||||||
|
|
||||||
|
# 截图
|
||||||
|
curl -s http://127.0.0.1:9527/pages/baidu/screenshot | jq -r '.data.base64' | base64 -d > scrolled.png
|
||||||
|
```
|
||||||
|
|
||||||
|
## 场景七:切换指纹配置
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 查看可用配置
|
||||||
|
curl -s http://127.0.0.1:9527/profiles
|
||||||
|
|
||||||
|
# 使用 Windows Chrome 指纹打开页面
|
||||||
|
curl -s -X POST http://127.0.0.1:9527/pages \
|
||||||
|
-H 'Content-Type: application/json' \
|
||||||
|
-d '{"url":"https://www.baidu.com","alias":"win","profile":"desktop-windows"}'
|
||||||
|
```
|
||||||
|
|
||||||
|
## 场景八:页面持久化验证
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# 1. 打开页面
|
# 1. 打开页面
|
||||||
visionl page open https://api.example.com/data --alias data
|
curl -s -X POST http://127.0.0.1:9527/pages \
|
||||||
|
-H 'Content-Type: application/json' \
|
||||||
|
-d '{"url":"https://www.baidu.com","alias":"persistent"}'
|
||||||
|
|
||||||
# 2. 执行 JS 提取 JSON 数据
|
# 2. 关闭 curl 连接(页面不消失)
|
||||||
visionl eval data "JSON.parse(document.body.innerText)"
|
# 3. 重新查询 — 页面仍在
|
||||||
# → {"ok":true,"data":{"result":{"items":[...]}}}
|
curl -s http://127.0.0.1:9527/pages/persistent
|
||||||
|
# {"ok":true,"data":{"id":"p_xxx","status":"active",...}}
|
||||||
|
|
||||||
# 3. 获取页面标题
|
# 4. 只有显式 kill 才关闭
|
||||||
visionl eval data "document.title"
|
curl -s -X DELETE http://127.0.0.1:9527/pages/persistent
|
||||||
# → {"ok":true,"data":{"result":"API Data Page"}}
|
|
||||||
```
|
|
||||||
|
|
||||||
## 场景六:REST 直通(高级)
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# 不使用子命令,直接调用 HTTP API
|
|
||||||
visionl raw POST /pages '{"url":"https://example.com","alias":"test"}'
|
|
||||||
# → {"ok":true,"data":{"id":"p_5678",...}}
|
|
||||||
|
|
||||||
visionl raw GET /pages/p_5678/text
|
|
||||||
# → {"ok":true,"data":{"text":"..."}}
|
|
||||||
|
|
||||||
visionl raw DELETE /pages/p_5678
|
|
||||||
# → {"ok":true,"data":null}
|
|
||||||
```
|
|
||||||
|
|
||||||
## 场景七:智能体自动化工作流
|
|
||||||
|
|
||||||
LLM 通过 VisionL 完成机票比价:
|
|
||||||
|
|
||||||
```
|
|
||||||
1. visionl page open https://flights.example.com --alias flights
|
|
||||||
2. visionl type flights "#from" "北京"
|
|
||||||
3. visionl type flights "#to" "上海"
|
|
||||||
4. visionl type flights "#date" "2026-08-20"
|
|
||||||
5. visionl click flights "#search"
|
|
||||||
6. visionl wait flights --selector ".results"
|
|
||||||
7. visionl text flights
|
|
||||||
→ 提取票价信息
|
|
||||||
8. visionl eval flights "document.querySelectorAll('.price').length"
|
|
||||||
→ 统计结果数量
|
|
||||||
9. visionl page kill flights
|
|
||||||
```
|
|
||||||
|
|
||||||
## 场景八:长时间运行的任务
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# 打开监控面板
|
|
||||||
visionl page open https://monitor.example.com --alias monitor --pretty
|
|
||||||
# ✓ 页面已打开
|
|
||||||
# ID: p_mon_001
|
|
||||||
# URL: https://monitor.example.com
|
|
||||||
# 别名: monitor
|
|
||||||
|
|
||||||
# ... 过了一段时间 ...
|
|
||||||
|
|
||||||
# 还是同一个页面
|
|
||||||
visionl page list --pretty
|
|
||||||
# ✓ 1 个页面
|
|
||||||
# p_mon_001 monitor https://monitor.example.com active
|
|
||||||
|
|
||||||
# 刷新重新截图
|
|
||||||
visionl navigate monitor https://monitor.example.com
|
|
||||||
visionl screenshot monitor -o latest.png
|
|
||||||
```
|
```
|
||||||
|
|||||||
+131
-77
@@ -1,138 +1,192 @@
|
|||||||
# 在 LLM 智能体中集成 VisionL
|
# 在 LLM 智能体中集成 VisionL
|
||||||
|
|
||||||
> 本文档介绍如何让 LLM 通过工具调用使用 VisionL-CLI 操控浏览器。
|
> 让 LLM 通过 HTTP API 工具调用操控 VisionL 浏览器。
|
||||||
|
|
||||||
## 原理
|
## 原理
|
||||||
|
|
||||||
LLM 将 `visionl` 注册为一个系统命令/工具,在需要浏览网页时调用。
|
VisionL daemon 提供完整的 REST API。LLM 将 API 调用注册为工具/函数(Function Calling),
|
||||||
所有命令输出结构化的 JSON,LLM 直接解析结果并决定下一步操作。
|
在需要浏览网页时生成对应的 HTTP 请求。所有接口返回结构化 JSON,LLM 直接解析。
|
||||||
|
|
||||||
|
## API 总览
|
||||||
|
|
||||||
|
| 方法 | 端点 | 功能 |
|
||||||
|
|------|------|------|
|
||||||
|
| POST | `/pages` | 打开页面 |
|
||||||
|
| GET | `/pages` | 列出所有页面 |
|
||||||
|
| GET | `/pages/:id` | 页面详情 |
|
||||||
|
| DELETE | `/pages/:id` | 关闭页面 |
|
||||||
|
| POST | `/pages/:id/navigate` | 跳转 |
|
||||||
|
| POST | `/pages/:id/click` | 点击元素 |
|
||||||
|
| POST | `/pages/:id/type` | 输入文本 |
|
||||||
|
| POST | `/pages/:id/scroll` | 滚动 |
|
||||||
|
| POST | `/pages/:id/eval` | 执行 JS |
|
||||||
|
| POST | `/pages/:id/wait` | 等待 |
|
||||||
|
| GET | `/pages/:id/screenshot` | 截图(base64) |
|
||||||
|
| GET | `/pages/:id/text` | 纯文本 |
|
||||||
|
| GET | `/pages/:id/html` | HTML 源码 |
|
||||||
|
| GET | `/pages/:id/cookies` | Cookie 列表 |
|
||||||
|
| POST | `/pages/:id/cookies` | 设置 Cookie |
|
||||||
|
| DELETE | `/pages/:id/cookies/:name` | 删除 Cookie |
|
||||||
|
| GET | `/pages/:id/console` | 控制台日志 |
|
||||||
|
| GET | `/pages/:id/network` | 网络请求日志 |
|
||||||
|
| GET | `/profiles` | 指纹配置列表 |
|
||||||
|
|
||||||
|
完整文档见 [API 文档](../development/api.md)。
|
||||||
|
|
||||||
## 集成方式
|
## 集成方式
|
||||||
|
|
||||||
### 方式一:Function Calling(推荐)
|
### 方式一:Function Calling(推荐)
|
||||||
|
|
||||||
在 LLM 的 function/tool 定义中注册 VisionL 命令。大多数 LLM 平台(OpenAI、Claude、本地模型)都支持。
|
注册 `visionl_api` 工具,LLM 直接生成 HTTP 请求:
|
||||||
|
|
||||||
**工具定义示例(OpenAI 格式):**
|
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"type": "function",
|
"type": "function",
|
||||||
"function": {
|
"function": {
|
||||||
"name": "visionl",
|
"name": "visionl_api",
|
||||||
"description": "通过 VisionL 浏览器操控网页。子命令: page open|list|info|kill|kill-all, click, type, scroll, navigate, eval, wait, screenshot, text, html, daemon start|stop|status, raw",
|
"description": "通过 VisionL 浏览器操控网页。支持打开页面、点击、输入、截图、提取文本、执行JS、管理Cookie、查看网络请求等。",
|
||||||
"parameters": {
|
"parameters": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"command": {
|
"method": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "完整 visionl 命令,例如 'page open https://example.com'"
|
"enum": ["GET", "POST", "DELETE"],
|
||||||
|
"description": "HTTP 方法"
|
||||||
|
},
|
||||||
|
"path": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "API 路径,如 /pages、/pages/baidu/text"
|
||||||
|
},
|
||||||
|
"body": {
|
||||||
|
"type": "object",
|
||||||
|
"description": "请求体(仅 POST 需要)"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": ["command"]
|
"required": ["method", "path"]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
**使用流程:**
|
### 使用流程
|
||||||
|
|
||||||
1. LLM 决策需要访问网页
|
1. LLM 决策需要访问网页
|
||||||
2. LLM 生成 `visionl page open <url>` 调用
|
2. LLM 调用 `visionl_api`:`POST /pages` 打开 baidu.com
|
||||||
3. 宿主程序在终端执行该命令,将 JSON 输出返回给 LLM
|
3. 宿主程序执行 HTTP 请求,将 JSON 结果返回 LLM
|
||||||
4. LLM 解析结果,继续决策(截图、点击、提取文本等)
|
4. LLM 解析结果,获得页面 ID `p_xxx`
|
||||||
|
5. LLM 继续:`GET /pages/p_xxx/text` 读取内容
|
||||||
|
6. 或:`POST /pages/p_xxx/click` 点击搜索
|
||||||
|
|
||||||
### 方式二:MCP Server
|
### 方式二:多工具注册
|
||||||
|
|
||||||
可以封装一个 MCP(Model Context Protocol)Server,将 VisionL-CLI 包装为 MCP 工具:
|
将每个操作注册为独立工具(更细粒度):
|
||||||
|
|
||||||
```typescript
|
```json
|
||||||
// 伪代码示意
|
[
|
||||||
server.tool(
|
{
|
||||||
"visionl",
|
"name": "visionl_open",
|
||||||
"通过 VisionL 浏览器操控网页",
|
"description": "打开网页",
|
||||||
{ command: z.string() },
|
"parameters": {
|
||||||
async ({ command }) => {
|
"url": { "type": "string" },
|
||||||
const { stdout } = await exec(`visionl ${command}`);
|
"alias": { "type": "string" }
|
||||||
return JSON.parse(stdout);
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "visionl_text",
|
||||||
|
"description": "获取页面文本内容",
|
||||||
|
"parameters": {
|
||||||
|
"page_id": { "type": "string" }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "visionl_click",
|
||||||
|
"description": "点击页面元素",
|
||||||
|
"parameters": {
|
||||||
|
"page_id": { "type": "string" },
|
||||||
|
"selector": { "type": "string" }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
);
|
]
|
||||||
```
|
```
|
||||||
|
|
||||||
### 方式三:Agent 框架集成
|
### 方式三:LangChain 集成
|
||||||
|
|
||||||
与 LangChain、AutoGPT、CrewAI 等框架集成,注册为自定义工具。
|
|
||||||
|
|
||||||
**LangChain 示例:**
|
|
||||||
|
|
||||||
```python
|
```python
|
||||||
from langchain.tools import Tool
|
from langchain.tools import BaseTool
|
||||||
import subprocess, json
|
import requests
|
||||||
|
|
||||||
def visionl_tool(command: str) -> str:
|
class VisionLTool(BaseTool):
|
||||||
result = subprocess.run(
|
name = "visionl"
|
||||||
["visionl", *command.split()],
|
description = "浏览器操控工具。API 基础 URL: http://127.0.0.1:9527"
|
||||||
capture_output=True, text=True
|
|
||||||
)
|
|
||||||
return result.stdout
|
|
||||||
|
|
||||||
visionl = Tool(
|
def _run(self, method: str, path: str, body: dict = None) -> str:
|
||||||
name="visionl",
|
url = f"http://127.0.0.1:9527{path}"
|
||||||
description="浏览器操控工具。命令示例:page open <url>, click <id> <sel>, text <id>",
|
resp = requests.request(method, url, json=body)
|
||||||
func=visionl_tool,
|
return resp.text
|
||||||
)
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## LLM Prompt 建议
|
## LLM 系统提示词建议
|
||||||
|
|
||||||
在系统 prompt 中添加以下指引:
|
|
||||||
|
|
||||||
```
|
```
|
||||||
你可以使用 visionl 命令操控浏览器:
|
你可以使用 visionl_api 工具操控浏览器:
|
||||||
|
|
||||||
1. visionl page open <url> [--alias <name>] — 打开页面
|
打开页面: POST /pages {"url":"...","alias":"..."}
|
||||||
2. visionl page list — 列出所有页面
|
页面文本: GET /pages/{id}/text
|
||||||
3. visionl text <id|alias> — 获取页面文本
|
页面截图: GET /pages/{id}/screenshot (返回 base64)
|
||||||
4. visionl screenshot <id|alias> — 截图(返回 base64)
|
点击元素: POST /pages/{id}/click {"selector":"#id"}
|
||||||
5. visionl click <id|alias> <selector> — 点击元素
|
输入文本: POST /pages/{id}/type {"selector":"#id","text":"..."}
|
||||||
6. visionl type <id|alias> <selector> <text> — 输入文本
|
执行 JS: POST /pages/{id}/eval {"code":"..."}
|
||||||
7. visionl page kill <id|alias> — 关闭页面
|
滚动页面: POST /pages/{id}/scroll {"deltaY":300}
|
||||||
|
等待加载: POST /pages/{id}/wait {"ms":2000}
|
||||||
|
查看Cookie: GET /pages/{id}/cookies
|
||||||
|
网络日志: GET /pages/{id}/network
|
||||||
|
关闭页面: DELETE /pages/{id}
|
||||||
|
|
||||||
所有命令返回 JSON。解析 ok 字段判断成功/失败。
|
所有接口返回 {"ok":true,"data":{...}} 或 {"ok":false,"error":{...}}。
|
||||||
使用 --alias 给页面起别名方便后续引用。
|
打开页面后记录返回的 page_id,后续操作使用该 id。
|
||||||
|
页面在被显式 kill 之前永远存活,可跨多轮对话复用。
|
||||||
```
|
```
|
||||||
|
|
||||||
## 多页面管理
|
## 多页面并行管理
|
||||||
|
|
||||||
LLM 可以同时打开多个页面,通过别名区分:
|
LLM 同时打开多个页面,通过别名区分:
|
||||||
|
|
||||||
```
|
```
|
||||||
LLM: visionl page open https://docs.python.org --alias py
|
LLM: POST /pages {"url":"https://docs.python.org","alias":"py"}
|
||||||
LLM: visionl page open https://developer.mozilla.org --alias mdn
|
→ {"ok":true,"data":{"id":"p_aaa",...}}
|
||||||
LLM: visionl text py # 读 Python 文档
|
|
||||||
LLM: visionl text mdn # 读 MDN 文档
|
LLM: POST /pages {"url":"https://developer.mozilla.org","alias":"mdn"}
|
||||||
|
→ {"ok":true,"data":{"id":"p_bbb",...}}
|
||||||
|
|
||||||
|
LLM: GET /pages/py/text # 读 Python 文档
|
||||||
|
LLM: GET /pages/mdn/text # 读 MDN 文档
|
||||||
```
|
```
|
||||||
|
|
||||||
## 错误处理
|
## 错误处理
|
||||||
|
|
||||||
LLM 应检查返回的 `ok` 字段:
|
|
||||||
|
|
||||||
```json
|
```json
|
||||||
// 失败示例
|
// 失败示例
|
||||||
{"ok":false,"error":{"code":"PAGE_NOT_FOUND","message":"页面 py 不存在"}}
|
{"ok":false,"error":{"code":"PAGE_NOT_FOUND","message":"页面 py 不存在"}}
|
||||||
```
|
```
|
||||||
|
|
||||||
常见错误及处理:
|
常见错误码及处理:
|
||||||
|
|
||||||
| 错误码 | 处理建议 |
|
| 错误码 | HTTP | 处理建议 |
|
||||||
|--------|---------|
|
|--------|------|---------|
|
||||||
| `PAGE_NOT_FOUND` | 页面可能已被关闭,重新打开 |
|
| `PAGE_NOT_FOUND` | 404 | 页面已关闭,重新打开 |
|
||||||
| `DAEMON_UNREACHABLE` | 等待几秒重试(自动拉起正在启动) |
|
| `DAEMON_UNREACHABLE` | 502 | 启动 daemon 或稍后重试 |
|
||||||
| `TIMEOUT` | 页面加载慢,重试或增加等待时间 |
|
| `TIMEOUT` | 408 | 页面加载慢,重试或增加等待 |
|
||||||
| `ALIAS_EXISTS` | 换一个别名或直接用 page ID |
|
| `ALIAS_EXISTS` | 409 | 换别名或直接用 page_id |
|
||||||
|
|
||||||
## 安全注意事项
|
## 反检测能力
|
||||||
|
|
||||||
- VisionL daemon 仅监听 127.0.0.1,外部不可访问
|
VisionL 内置多层反检测,使自动化访问尽可能不被简单人机验证拦截:
|
||||||
- 执行的 JS 代码在页面沙箱内运行,无法逃逸到宿主机
|
|
||||||
- LLM 应避免在不可信页面执行敏感操作(自动填写密码等)
|
- `navigator.webdriver` → `false`
|
||||||
|
- 真实 Chrome User-Agent 和请求头
|
||||||
|
- Canvas/WebGL/Audio 指纹加噪
|
||||||
|
- 屏幕分辨率和视口合理性
|
||||||
|
- 权限状态模拟
|
||||||
|
- 3 套指纹模版可切换
|
||||||
|
|
||||||
|
详见 [反检测设计文档](../development/anti-detection.md)。
|
||||||
|
|||||||
+96
-47
@@ -1,89 +1,138 @@
|
|||||||
# VisionL 快速开始
|
# VisionL 快速开始
|
||||||
|
|
||||||
|
## 环境要求
|
||||||
|
|
||||||
|
- Node.js >= 18
|
||||||
|
- Chromium 浏览器(系统自带或 Playwright 安装)
|
||||||
|
- Linux/macOS/Windows(Android 需配合 Ubuntu proot 容器)
|
||||||
|
|
||||||
## 安装
|
## 安装
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# 1. 克隆仓库
|
|
||||||
git clone ssh://git@git.yeij.top:2222/AskaEth/VisionL.git
|
git clone ssh://git@git.yeij.top:2222/AskaEth/VisionL.git
|
||||||
cd VisionL
|
cd VisionL
|
||||||
|
npm install --registry=https://registry.npmmirror.com
|
||||||
# 2. 安装依赖
|
npx playwright install chromium # 如果没有系统 Chromium
|
||||||
npm install
|
|
||||||
|
|
||||||
# 3. 安装 Chromium 浏览器
|
|
||||||
npx playwright install chromium
|
|
||||||
|
|
||||||
# 4. 构建
|
|
||||||
npm run build
|
npm run build
|
||||||
|
```
|
||||||
|
|
||||||
# 5. 全局安装 CLI(可选)
|
## 启动
|
||||||
cd packages/cli && npm link
|
|
||||||
|
```bash
|
||||||
|
# 方式一:使用内置启动脚本
|
||||||
|
node start-daemon.js &
|
||||||
|
|
||||||
|
# 方式二:直接运行 daemon
|
||||||
|
VISIONL_PORT=9527 node packages/daemon/dist/server.js &
|
||||||
```
|
```
|
||||||
|
|
||||||
## 基本使用
|
## 基本使用
|
||||||
|
|
||||||
### 启动 daemon
|
所有命令输出 JSON 格式,可使用 `--pretty` 切换为人类可读。
|
||||||
|
|
||||||
|
### 打开页面
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
visionl daemon start
|
curl -X POST http://127.0.0.1:9527/pages \
|
||||||
# ✓ Daemon 已启动 (端口 9527, PID 12345)
|
-H 'Content-Type: application/json' \
|
||||||
|
-d '{"url":"https://www.baidu.com","alias":"baidu"}'
|
||||||
```
|
```
|
||||||
|
|
||||||
### 打开一个页面
|
返回:
|
||||||
|
```json
|
||||||
```bash
|
{
|
||||||
visionl page open https://www.baidu.com --alias baidu
|
"ok": true,
|
||||||
# {"ok":true,"data":{"id":"p_a1b2c3d4","url":"https://www.baidu.com","alias":"baidu","title":"百度一下,你就知道","status":"active"}}
|
"data": {
|
||||||
|
"id": "p_f1990959",
|
||||||
|
"url": "https://www.baidu.com",
|
||||||
|
"alias": "baidu",
|
||||||
|
"title": "百度一下,你就知道",
|
||||||
|
"status": "active",
|
||||||
|
"profile": "desktop-chrome"
|
||||||
|
}
|
||||||
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### 获取页面文本
|
### 获取页面文本
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
visionl text baidu
|
curl http://127.0.0.1:9527/pages/baidu/text
|
||||||
# {"ok":true,"data":{"text":"百度一下,你就知道\n..."}}
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### 搜索
|
### 搜索
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
visionl type baidu "#kw" "VisionL"
|
# 输入搜索词
|
||||||
visionl click baidu "#su"
|
curl -X POST http://127.0.0.1:9527/pages/baidu/type \
|
||||||
|
-H 'Content-Type: application/json' \
|
||||||
|
-d '{"selector":"#kw","text":"VisionL"}'
|
||||||
|
|
||||||
|
# 点击搜索按钮
|
||||||
|
curl -X POST http://127.0.0.1:9527/pages/baidu/click \
|
||||||
|
-H 'Content-Type: application/json' \
|
||||||
|
-d '{"selector":"#su"}'
|
||||||
|
|
||||||
|
# 等待结果加载
|
||||||
|
curl -X POST http://127.0.0.1:9527/pages/baidu/wait \
|
||||||
|
-H 'Content-Type: application/json' \
|
||||||
|
-d '{"ms":2000}'
|
||||||
|
|
||||||
|
# 获取搜索结果
|
||||||
|
curl http://127.0.0.1:9527/pages/baidu/text
|
||||||
```
|
```
|
||||||
|
|
||||||
### 截图
|
### 截图
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
visionl screenshot baidu -o result.png
|
curl http://127.0.0.1:9527/pages/baidu/screenshot
|
||||||
|
# 返回 base64 编码的 PNG 图片
|
||||||
|
```
|
||||||
|
|
||||||
|
### 执行 JavaScript
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -X POST http://127.0.0.1:9527/pages/baidu/eval \
|
||||||
|
-H 'Content-Type: application/json' \
|
||||||
|
-d '{"code":"document.title"}'
|
||||||
|
# {"ok":true,"data":{"result":"百度一下,你就知道"}}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Cookie 管理
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 查看所有 Cookie
|
||||||
|
curl http://127.0.0.1:9527/pages/baidu/cookies
|
||||||
|
|
||||||
|
# 设置 Cookie
|
||||||
|
curl -X POST http://127.0.0.1:9527/pages/baidu/cookies \
|
||||||
|
-H 'Content-Type: application/json' \
|
||||||
|
-d '{"name":"mycookie","value":"hello","domain":".baidu.com"}'
|
||||||
|
```
|
||||||
|
|
||||||
|
### 网络请求监控
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 查看网络请求日志
|
||||||
|
curl http://127.0.0.1:9527/pages/baidu/network
|
||||||
|
```
|
||||||
|
|
||||||
|
### 查看指纹配置
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl http://127.0.0.1:9527/profiles
|
||||||
|
# [{"id":"desktop-chrome","name":"桌面 Chrome (通用)"},
|
||||||
|
# {"id":"desktop-windows","name":"桌面 Chrome (Windows)"},
|
||||||
|
# {"id":"desktop-mac","name":"桌面 Chrome (macOS)"}]
|
||||||
```
|
```
|
||||||
|
|
||||||
### 关闭页面
|
### 关闭页面
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
visionl page kill baidu
|
curl -X DELETE http://127.0.0.1:9527/pages/baidu
|
||||||
# {"ok":true,"data":null}
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### 停止 daemon
|
### 查看所有页面
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
visionl daemon stop
|
curl http://127.0.0.1:9527/pages
|
||||||
```
|
|
||||||
|
|
||||||
## 无需手动启动 daemon
|
|
||||||
|
|
||||||
CLI 会自动检测 daemon 是否运行,未运行则自动启动:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# 直接使用,CLI 自动拉起 daemon
|
|
||||||
visionl page open https://example.com
|
|
||||||
|
|
||||||
# 关闭所有页面(daemon 继续运行)
|
|
||||||
visionl page kill-all
|
|
||||||
```
|
|
||||||
|
|
||||||
## 查看所有页面
|
|
||||||
|
|
||||||
```bash
|
|
||||||
visionl page list
|
|
||||||
# {"ok":true,"data":[{"id":"p_xxx","url":"...","alias":"...","title":"...","status":"active"}]}
|
|
||||||
```
|
```
|
||||||
|
|||||||
Reference in New Issue
Block a user