开放接口文档
启元指纹浏览器 · 本地客户端开放 API · v2.0
认证流程
只需在启动客户端时传入 --run_mode=api --app_id=xxx --app_secret=xxx,
客户端自动完成身份认证,后续所有接口调用均无需额外传递凭证。
AppID 和 AppSecret 从「开发者中心」页面获取。
接入方式
开放接口基于 HTTP 协议,客户端启动后服务默认监听在 http://127.0.0.1:9001(可通过 --port 参数修改)。无需建立长连接,直接发送 HTTP 请求即可。
启动命令
Qiyuan.exe --run_mode=api --port=9001 --app_id=your_app_id --app_secret=your_app_secret
请求说明
- GET 接口:参数通过 URL Query String 传递
- POST 接口:参数通过 JSON Body 传递,请求头需包含
Content-Type: application/json - 无需携带 Authorization 凭证,客户端已登录状态下自动鉴权
快速验证
# 查询环境列表(curl 示例) curl "http://127.0.0.1:9001/open/env/list?page=1&page_size=10"
环境接口 Browser
Query 参数
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| page | number | 可选 | 页码,默认 1 |
| page_size | number | 可选 | 每页数量,默认 20,最大 100 |
| keyword | string | 可选 | 按环境名称模糊搜索 |
响应 data
{
"total": 100,
"page": 1,
"page_size": 20,
"total_pages": 5,
"items": [
{
"code": "a1b2c3d4...", // string 环境唯一标识,后续操作均使用此字段
"name": "测试账号-01", // string 环境名称
"browser_version": "138.0.7204.184", // string 内核版本号,null 表示未配置
"platform": "Win32", // string Win32 / MacIntel / Linux x86_64
"user_agent": "Mozilla/5.0 ...", // string User-Agent 字符串
"proxy_ip_code": "1716523...", // string 绑定代理的唯一标识,未绑定为 null
"remark": "备注信息", // string 备注
"tag_ids": [1, 2], // number[] 标签 ID 列表
"open_home_page": true, // boolean 是否打开首页
"status": "stopped", // string running | stopped
"debug_port": null, // number CDP 调试端口,running 时有值,否则 null
"create_time": "2024-01-01T00:00:00",
"update_time": "2024-06-01T12:00:00"
}
]
}
基础信息字段
| 字段 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
| name | string | 必填 | — | 环境名称 |
| platform | string | 可选 | Win32 | 操作系统。可选值:Win32 / MacIntel / Linux x86_64 |
| browser_version | string | 可选 | 145.0.7632.109(最新) | 完整内核版本号。不填自动取最新版本。可选值:145.0.7632.109 / 139.0.7258.67 / 138.0.7204.184 |
| user_agent | string | 可选 | 自动生成 | User-Agent。不填时根据 platform + browser_version 自动生成(UA 随版本变化) |
| proxy_ip_code | string | 可选 | 绑定代理的唯一标识(来自 GET /open/proxy/list 的 code 字段) | |
| open_home_page | boolean | 可选 | false | 是否打开首页 |
| enable_tabs | boolean | 可选 | false | 是否启用多标签页 |
| tabs | string | 可选 | "" | 标签页 URL,多个用换行分隔(enable_tabs=true 时生效) |
| sync_user_info | boolean | 可选 | false | 是否开启云端用户信息同步(账号数据云备份) |
| cookie | string | 可选 | "" | 初始 Cookie 内容 |
| launch_args | string | 可选 | "" | 额外 Chrome 启动参数,空格分隔,如 --disable-gpu --no-sandbox |
| remark | string | 可选 | "" | 备注 |
| tag_ids | number[] | 可选 | [] | 标签 ID 列表 |
指纹字段
所有指纹字段均为可选,未传时使用后端默认值。
| 字段 | 类型 | 默认值 | 说明 / 可选值 |
|---|---|---|---|
| webrtc | string | disabled | ip 基于IP | real 真实 | disabled 禁用 | transform_google 转发 |
| webgl | string | real | real 真实 | custom 自定义(需同时提供 webgl_vendor 和 webgl_renderer) |
| webgl_vendor | string | — | webgl=custom 时必填。厂商名,如 Intel Inc. / NVIDIA Corporation / AMD / Apple Inc. |
| webgl_renderer | string | — | webgl=custom 时必填。渲染器名,如 Intel(R) UHD Graphics 630 / NVIDIA GeForce RTX 4090 |
| webgpu | string | basegl | basegl 基于WebGL | real 真实 | custom 自定义(需提供 webgpu_vendor/architecture/device/description) |
| webgpu_vendor | string | — | webgpu=custom 时使用,如 intel / nvidia / amd / apple |
| webgpu_architecture | string | — | 如 common-shader-cores / rdna-3 / apple-gpu |
| webgpu_device | string | — | 如 integrated-gpu / discrete-gpu |
| webgpu_description | string | — | 如 NVIDIA GeForce RTX 4090 / Intel Iris Xe Graphics |
| timezone | string | ip | ip 基于IP | real 真实 | custom 自定义(需提供 timezone_value) |
| timezone_value | string | — | timezone=custom 时使用,IANA 时区格式,如 Asia/Shanghai / America/New_York / Europe/London |
| geo_location | string | ip | ip 基于IP | real 真实 | custom 自定义(需提供 longitude 和 latitude) |
| longitude | string | — | geo_location=custom 时使用,经度,如 116.3 |
| latitude | string | — | geo_location=custom 时使用,纬度,如 39.9 |
| language | string | ip | ip 基于IP | real 真实 | custom 自定义(需提供 languages 数组) |
| languages | string[] | — | language=custom 时使用,语言代码数组,如 ["zh-CN","en-US"]。可用值:zh-CN / zh-TW / en-US / en-GB / ja-JP / ko-KR / fr-FR / de-DE / es-ES / pt-BR / ru-RU 等 |
| ui_language | string | language | language 跟随语言 | real 真实 | custom 自定义(需提供 ui_language_value) |
| ui_language_value | string | — | ui_language=custom 时使用,单个语言代码,如 zh-CN |
| screen_resolution | string | real | real 真实 | custom 自定义(需提供 screen_resolution_value) |
| screen_resolution_value | string | — | screen_resolution=custom 时使用,格式 宽|高,可选:1920|1080 / 2560|1440 / 3840|2160 / 1366|768 / 1440|900 / 1536|864 / 1280|720 / 2560|1080 等 |
| font | string | random | disabled 关闭(值固定为0) | random 随机(服务端生成 -2~2 整数偏移量) |
| canvas | string | random | disabled 关闭 | random 随机(服务端生成 0~1 浮点噪点,2位小数) |
| audio | string | random | disabled 关闭 | random 随机(服务端生成 0~99 整数噪点) |
| client_rects | string | random | disabled 关闭 | random 随机(服务端生成 0~0.00001 浮点偏移,6位小数) |
| speech_voices | boolean | true | true 开启 | false 关闭语音合成设备伪装 |
| media_devices | string | random | disabled 关闭(null) | random 随机(服务端生成5个随机媒体设备ID) |
| cpu_cores | string | real | real 使用真实值 | 2 / 4 / 6 / 8 / 10 / 12 / 16 / 20 / 24 / 32 |
| memory_gb | string | real | real 使用真实值 | 2 / 4 / 8 / 16 / 32 / 64 / 128(单位 GB) |
| tls | string | enabled | disabled 关闭 | enabled 启用(不传 tls_features 则默认启用全部特征) |
| tls_features | string[] | — | tls=enabled 时可选,不填则启用全部。可选值(多选)::!aPSK 禁用PSK认证 / :!kRSA 禁用RSA密钥交换 / :!ECDSA 禁用ECDSA证书 / :!ECDSA+SHA1 / :!3DES 禁用3DES加密 |
响应 data
{
"code": "a1b2c3..." // string 新建环境的唯一标识(后续所有操作使用此字段)
}
示例
# 最简调用(版本默认最新,UA 自动生成,指纹全部随机) curl -X POST http://127.0.0.1:9001/open/env/create \ -H "Content-Type: application/json" \ -d '{"name": "账号01"}' # 完整指纹示例 curl -X POST http://127.0.0.1:9001/open/env/create \ -H "Content-Type: application/json" \ -d '{ "name": "账号02", "platform": "Win32", "browser_version": "145.0.7632.109", "proxy_ip_code": "PROXY_CODE", "webrtc": "disabled", "webgl": "custom", "webgl_vendor": "NVIDIA Corporation", "webgl_renderer": "NVIDIA GeForce RTX 4090", "timezone": "custom", "timezone_value": "Asia/Shanghai", "geo_location": "custom", "longitude": "116.3", "latitude": "39.9", "language": "custom", "languages": ["zh-CN", "en-US"], "cpu_cores": "8", "memory_gb": "16" }'
支持与 POST /open/env/create 相同的所有字段(code 必填,其余字段只传需要修改的)。未传的字段保持不变。
必填字段
| 字段 | 类型 | 说明 |
|---|---|---|
| code | string | 环境唯一标识 |
可修改字段
与新增环境入参完全一致(除 name 不再必填),包括所有基础信息字段和指纹字段。
特别说明:若修改了 platform 或 browser_version 但未传 user_agent,系统自动重新生成匹配的 UA。
响应
{ "success": true }
示例
# 只修改备注 curl -X POST http://127.0.0.1:9001/open/env/update \ -H "Content-Type: application/json" \ -d '{"code": "ENV_CODE", "remark": "新备注"}' # 切换代理并修改 WebRTC 策略 curl -X POST http://127.0.0.1:9001/open/env/update \ -H "Content-Type: application/json" \ -d '{"code": "ENV_CODE", "proxy_ip_code": "NEW_PROXY_CODE", "webrtc": "disabled"}'
一键随机重新生成环境的指纹数据,逻辑与客户端界面的"随机指纹"按钮完全一致。WebGL/WebGPU 按平台随机,font/canvas/audio/client_rects/media_devices 全部重新随机,时区/地理位置/语言保持基于IP策略。
Body 参数
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| code | string | 必填 | 环境唯一标识 |
响应 data
{
"webgl_vendor": "NVIDIA Corporation", // 本次随机的 WebGL 厂商
"webgl_renderer": "NVIDIA GeForce RTX 4090", // 本次随机的 WebGL 渲染器
"webgpu_value": "nvidia|common-shader-cores|discrete-gpu|NVIDIA GeForce RTX 4090",
"font": -1, // -2~2 整数偏移
"canvas": 0.73, // 0~1 浮点噪点
"audio": 42, // 0~99 整数噪点
"client_rects": 0.000007, // 0~0.00001 浮点偏移
"speech_voices": true,
"media_devices": ["a3f2...", "..."] // 5个随机设备ID
}
示例
curl -X POST http://127.0.0.1:9001/open/env/randomize_fingerprint \ -H "Content-Type: application/json" \ -d '{"code": "ENV_CODE"}'
Body 参数
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| code | string | 必填 | 环境唯一标识 |
响应
{ "success": true }
Body 参数
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| code | string | 必填 | 环境唯一标识 |
| headless | boolean | 可选 | 是否无头模式,默认 false。设为 true 时浏览器不显示窗口,适合自动化场景 |
| args | string[] | 可选 | 追加给 Chrome 的额外启动参数,如 ["--kiosk", "--blink-settings=imagesEnabled=false"] |
响应 data
{
"pid": 12345, // number 浏览器进程 PID
"debug_port": 19222 // number CDP 调试端口(19222-19999 范围内唯一分配)
}
通过调试端口接入自动化框架
# Playwright (Python) from playwright.sync_api import sync_playwright with sync_playwright() as p: browser = p.chromium.connect_over_cdp('http://127.0.0.1:19222') # Selenium (Python) from selenium import webdriver options = webdriver.ChromeOptions() options.add_experimental_option('debuggerAddress', '127.0.0.1:19222') driver = webdriver.Chrome(options=options)
每次 POST /open/env/open 都会分配唯一调试端口,浏览器关闭后端口自动释放并可被复用。
Body 参数
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| code | string | 必填 | 环境唯一标识 |
响应
{ "success": true } // 浏览器未运行时返回 success: false
Query 参数
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| code | string | 必填 | 环境唯一标识 |
响应 data
{
"code": "a1b2c3...", // string 环境唯一标识
"status": "running", // string running | stopped
"pid": 12345, // number 进程 PID,stopped 时为 null
"debug_port": 19222 // number CDP 调试端口,stopped 时为 null
}
Body 参数
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| code | string | 必填 | 环境唯一标识 |
响应
{ "success": true }
清空操作会删除本地 %appdata%\qiyuan\user_data\{code} 目录,若该环境开启了云同步则同时删除服务器备份。
代理接口 Proxy
Query 参数
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| page | number | 可选 | 页码,默认 1 |
| page_size | number | 可选 | 每页数量,默认 20,最大 100 |
| keyword | string | 可选 | 按名称或地址模糊搜索 |
响应 data
{
"total": 50,
"page": 1,
"page_size": 20,
"total_pages": 3,
"items": [
{
"code": "1716523200abc", // string 代理唯一标识(用于修改 / 删除 / 绑定到环境)
"proxy_name": "美国-01", // string 代理名称
"proxy_type": "socks5", // string http | https | socks5
"proxy_addr": "1.2.3.4", // string 代理服务器地址
"proxy_port": 1080, // number 代理端口
"username": "user", // string 认证用户名,无则 null
"create_time": "2024-01-01T00:00:00",
"update_time": "2024-06-01T12:00:00"
}
]
}
Body 参数
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| proxy_name | string | 必填 | 代理名称 |
| proxy_type | string | 必填 | 代理类型:http / https / socks5 |
| proxy_addr | string | 必填 | 代理服务器地址(IP 或域名) |
| proxy_port | number | 必填 | 代理端口(1-65535) |
| username | string | 可选 | 认证用户名 |
| password | string | 可选 | 认证密码 |
响应 data
{
"code": "1716523200abc" // string 新建代理的唯一标识(用于绑定到环境)
}
Body 参数
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| code | string | 必填 | 代理唯一标识 |
| proxy_name | string | 可选 | 新的代理名称 |
| proxy_type | string | 可选 | 新的代理类型 |
| proxy_addr | string | 可选 | 新的代理地址 |
| proxy_port | number | 可选 | 新的代理端口 |
| username | string | 可选 | 新的认证用户名 |
| password | string | 可选 | 新的认证密码 |
响应
{ "success": true }
Body 参数
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| code | string | 必填 | 代理唯一标识 |
响应
{ "success": true }
统一响应格式
所有接口均以 HTTP 200 返回,响应 Body 为 JSON:
// 成功 { "success": true, "data": { /* 业务数据 */ } } // 失败 { "success": false, "error": "错误描述" }
部分接口成功时不返回 data 字段(如 delete、close),只需判断 success 即可。
使用示例
# 依赖: pip install requests playwright # playwright install chromium import requests BASE = "http://127.0.0.1:9001" def get(path, **params): r = requests.get(BASE + path, params=params) r.raise_for_status() return r.json() def post(path, **body): r = requests.post(BASE + path, json=body) r.raise_for_status() return r.json() # ── 新增代理 ────────────────────────────────────────────────────────────── print("[代理] 正在新增代理...") res = post("/open/proxy/create", proxy_name="美国住宅-01", proxy_type="socks5", proxy_addr="1.2.3.4", proxy_port=1080, username="user", password="pass", ) print("[代理] 结果:", res) proxy_code = res["data"]["code"] print(f"[代理] code={proxy_code}") # ── 新增环境(指纹字段不传则自动随机)──────────────────────────────────── print("[环境] 正在新增环境...") res = post("/open/env/create", name="账号-01", browser_version="138.0.7204.184", # 推荐显式传入;不传则自动取最新,需先在管理界面下载对应版本 # proxy_ip_code=proxy_code, # 如需绑定代理取消注释 timezone="custom", timezone_value="Asia/Shanghai", geo_location="custom", longitude="116.3", latitude="39.9", language="custom", languages=["zh-CN", "en-US"], cpu_cores="8", memory_gb="16", ) print("[环境] 结果:", res) env_code = res["data"]["code"] print(f"[环境] code={env_code}") # ── 刷新指纹 ─────────────────────────────────────────────────────────────── print("[指纹] 正在随机刷新指纹...") res = post("/open/env/randomize_fingerprint", code=env_code) print("[指纹] 结果:", res["data"]) # ── 打开浏览器(headless=False 显示窗口)───────────────────────────────── print("[浏览器] 正在打开浏览器...") res = post("/open/env/open", code=env_code, headless=False) print("[浏览器] 结果:", res) debug_port = res["data"]["debug_port"] print(f"[浏览器] 调试端口={debug_port}") # ── 接入 Playwright ──────────────────────────────────────────────────────── print("[Playwright] 正在连接...") try: from playwright.sync_api import sync_playwright with sync_playwright() as p: browser = p.chromium.connect_over_cdp(f"http://127.0.0.1:{debug_port}") page = browser.contexts[0].new_page() page.goto("https://www.baidu.com") title = page.title() print(f"[Playwright] 页面标题={title}") except Exception as e: print(f"[错误] Playwright 执行失败: {str(e)}") raise finally: print(f"[批量] 获取浏览器状态 {env_code}...") r = get("/open/env/status", code=env_code) print(f"状态结果={r}") print("[关闭] 正在执行兜底关闭...") post("/open/env/close", code=env_code) print("[关闭] 完成") # ── 批量查询环境列表 ─────────────────────────────────────────────────────── print("[批量] 查询环境列表...") res = get("/open/env/list", page=1, page_size=10) for env in res["data"]["items"]: print(f"环境结果={env}")
// 依赖: npm install playwright (Node 18+ 内置 fetch,无需额外安装) const BASE = "http://127.0.0.1:9001"; const get = async (path, params = {}) => { const qs = new URLSearchParams(params).toString(); const r = await fetch(`${BASE}${path}${qs ? "?" + qs : ""}`); return r.json(); }; const post = async (path, body = {}) => { const r = await fetch(BASE + path, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(body), }); return r.json(); }; (async () => { // ── 新增代理 ────────────────────────────────────────────────────────── console.log("[代理] 正在新增代理..."); let res = await post("/open/proxy/create", { proxy_name: "美国住宅-01", proxy_type: "socks5", proxy_addr: "1.2.3.4", proxy_port: 1080, username: "user", password: "pass", }); console.log("[代理] 结果:", res); const proxyCode = res.data.code; // ── 新增环境 ────────────────────────────────────────────────────────── console.log("[环境] 正在新增环境..."); res = await post("/open/env/create", { name: "账号-01", // proxy_ip_code: proxyCode, // 如需绑定代理取消注释 timezone: "custom", timezone_value: "Asia/Shanghai", geo_location: "custom", longitude: "116.3", latitude: "39.9", language: "custom", languages: ["zh-CN", "en-US"], cpu_cores: "8", memory_gb: "16", }); console.log("[环境] 结果:", res); const envCode = res.data.code; // ── 刷新指纹 ────────────────────────────────────────────────────────── console.log("[指纹] 正在随机刷新指纹..."); res = await post("/open/env/randomize_fingerprint", { code: envCode }); console.log("[指纹] 结果:", res.data); // ── 打开浏览器 ──────────────────────────────────────────────────────── console.log("[浏览器] 正在打开浏览器..."); res = await post("/open/env/open", { code: envCode, headless: true }); console.log("[浏览器] 结果:", res); const debugPort = res.data.debug_port; // ── 接入 Playwright ─────────────────────────────────────── const { chromium } = require("playwright"); let browser = null; try { browser = await chromium.connectOverCDP(`http://127.0.0.1:${debugPort}`); const page = browser.contexts()[0].pages()[0]; await page.goto("https://www.example.com"); console.log("[Playwright] 页面标题=", await page.title()); } catch (err) { console.error("[Playwright] 执行失败:", err.message); throw err; } finally { if (browser) await browser.close().catch(() => {}); await post("/open/env/close", { code: envCode }).catch(() => {}); console.log("[关闭] 完成"); } })();
// 依赖: JDK 11+(内置 java.net.http.HttpClient) // org.json:json:20231013 import java.net.URI; import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; import org.json.JSONObject; public class QiyuanDemo { static final String BASE = "http://127.0.0.1:9001"; static final HttpClient client = HttpClient.newHttpClient(); static JSONObject get(String path) throws Exception { var req = HttpRequest.newBuilder() .uri(URI.create(BASE + path)) .GET().build(); var resp = client.send(req, HttpResponse.BodyHandlers.ofString()); return new JSONObject(resp.body()); } static JSONObject post(String path, JSONObject body) throws Exception { var req = HttpRequest.newBuilder() .uri(URI.create(BASE + path)) .header("Content-Type", "application/json") .POST(HttpRequest.BodyPublishers.ofString(body.toString())) .build(); var resp = client.send(req, HttpResponse.BodyHandlers.ofString()); return new JSONObject(resp.body()); } public static void main(String[] args) throws Exception { // ── 新增代理 ────────────────────────────────────────────────── System.out.println("[代理] 正在新增代理..."); JSONObject proxyRes = post("/open/proxy/create", new JSONObject() .put("proxy_name", "美国住宅-01").put("proxy_type", "socks5") .put("proxy_addr", "1.2.3.4").put("proxy_port", 1080) .put("username", "user").put("password", "pass")); System.out.println("[代理] 结果: " + proxyRes); String proxyCode = proxyRes.getJSONObject("data").getString("code"); // ── 新增环境 ────────────────────────────────────────────────── System.out.println("[环境] 正在新增环境..."); JSONObject envRes = post("/open/env/create", new JSONObject() .put("name", "账号-01") // .put("proxy_ip_code", proxyCode) // 如需绑定代理取消注释 .put("timezone", "custom").put("timezone_value", "Asia/Shanghai") .put("geo_location", "custom").put("longitude", "116.3").put("latitude", "39.9") .put("language", "custom").put("languages", new org.json.JSONArray().put("zh-CN").put("en-US")) .put("cpu_cores", "8").put("memory_gb", "16")); System.out.println("[环境] 结果: " + envRes); String envCode = envRes.getJSONObject("data").getString("code"); // ── 刷新指纹 ────────────────────────────────────────────────── System.out.println("[指纹] 正在随机刷新指纹..."); JSONObject fpRes = post("/open/env/randomize_fingerprint", new JSONObject().put("code", envCode)); System.out.println("[指纹] 结果: " + fpRes.opt("data")); // ── 打开浏览器 ──────────────────────────────────────────────── System.out.println("[浏览器] 正在打开浏览器..."); JSONObject openRes = post("/open/env/open", new JSONObject() .put("code", envCode).put("headless", true)); System.out.println("[浏览器] 结果: " + openRes); int debugPort = openRes.getJSONObject("data").getInt("debug_port"); System.out.println("[浏览器] 调试端口=" + debugPort); // ── 接入 Playwright (com.microsoft.playwright) ──────────────── // Playwright pw = Playwright.create(); // Browser browser = pw.chromium() // .connectOverCDP("http://127.0.0.1:" + debugPort); // Page page = browser.contexts().get(0).newPage(); // page.navigate("https://www.example.com"); // System.out.println("[Playwright] 标题=" + page.title()); // ── 关闭浏览器 ──────────────────────────────────────────────── System.out.println("[关闭] 正在关闭浏览器..."); post("/open/env/close", new JSONObject().put("code", envCode)); System.out.println("[关闭] 完成"); } }