开放接口文档
启元指纹浏览器 · 本地客户端开放 API · v2.0
认证流程
普通客户端通过客户端界面手动输入账号密码登录;API 客户端和嵌入式客户端传入 --app_id 和 --app_secret 后自动完成身份认证。
嵌入式客户端的 --service_token 仅用于保护本机接口,不参与云端登录;未配置时,本机调用无需请求令牌。AppID 和 AppSecret 从「开发者中心」页面获取。
接入方式
开放接口基于 HTTP 协议,服务默认监听在 http://127.0.0.1:9001(可通过 --port 修改)。三种接入方式的接口路径、请求参数和响应格式完全一致,请根据使用场景选择一种。
普通客户端模式
适合直接使用 Qiyuan 客户端,通过窗口手动输入账号密码完成登录:
Qiyuan.exe --windowless=false
登录完成后可调用下方开放接口;如需无窗口运行,可将 --windowless 设置为 true。
Qiyuan 客户端 API 模式(推荐)
适合自己运营环境、需要使用 Qiyuan 客户端窗口进行人工管理、登录或排查问题的场景。可直接启动 Qiyuan.exe,或通过命令启动 API 模式:
Qiyuan.exe --run_mode=api --windowsless=false --port=9001 --app_id=your_app_id --app_secret=your_app_secret
--windowsless=false 表示保留客户端窗口。客户端完成登录和初始化后,可直接调用下方开放接口,无需额外请求鉴权头。
嵌入式客户端(自研产品场景使用)
适合将指纹浏览器能力嵌入 Python、Node.js、Java、.NET 或其他自研产品。嵌入式客户端默认无窗口运行,可与自研产品一起发布,无需打开 Qiyuan.exe。
下载 QiyuanCloudRuntime.exeQiyuanCloudRuntime.exe --port=9001 --app_id=your_app_id --app_secret=your_app_secret
首次启动会自动初始化本地运行配置、RSA 公钥、浏览器内核和插件。需要限制本机调用时,可额外传入 --service_token:
QiyuanCloudRuntime.exe --port=9001 --app_id=your_app_id --app_secret=your_app_secret --service_token=your_service_token
未传入 --service_token 时,嵌入式客户端请求无需额外请求头;传入后,每个接口请求都需携带 X-Qiyuan-Runtime-Token: your_service_token。同一端口只能运行其中一种模式。
请求说明
- GET 接口:参数通过 URL Query String 传递
- POST 接口:参数通过 JSON Body 传递,请求头需包含
Content-Type: application/json - Qiyuan 客户端 API 模式无需额外请求鉴权头
- 嵌入式客户端仅在配置
service_token时携带X-Qiyuan-Runtime-Token
快速验证
# Qiyuan 客户端模式,或未配置 service_token 的嵌入式客户端 curl "http://127.0.0.1:9001/open/env/list?page=1&page_size=10" # 配置 service_token 的嵌入式客户端 curl "http://127.0.0.1:9001/open/env/list?page=1&page_size=10" \ -H "X-Qiyuan-Runtime-Token: your_service_token"
环境接口 Browser
Query 参数
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| page | number | 可选 | 页码,默认 1 |
| page_size | number | 可选 | 每页数量,默认 20,最大 100 |
| keyword | string | 可选 | 按环境名称模糊搜索 |
响应示例
{
"success": true,
"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 表示未配置
"browser_kernel": "chrome", // string chrome 谷歌 / firefox 火狐;旧环境默认 chrome
"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、火狐为 BiDi,未运行时为 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_kernel | string | 可选 | chrome | 浏览器内核:chrome 谷歌 / firefox 火狐。不传兼容旧 API,使用谷歌 |
| browser_version | string | 可选 | 所选内核的最新版本 | 完整内核版本号。不填时按 browser_kernel 选择最新版本;Firefox 未配置版本列表时需显式传入 |
| user_agent | string | 可选 | 自动生成 | User-Agent。不填时根据 platform + browser_version 自动生成(UA 随版本变化) |
| proxy_mode | string | 可选 | 自动判断 | 代理方式:no_proxy 无代理 / existing 已添加代理 / custom 自定义代理。不传时根据 proxy_ip_code/custom_proxy 自动判断,都未传则使用无代理 |
| 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 | 可选 | "" | 额外浏览器启动参数,空格分隔;参数需适用于所选内核 |
| remark | string | 可选 | "" | 备注 |
| tag_ids | number[] | 可选 | [] | 标签 ID 列表 |
代理字段
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| proxy_ip_code | string | 条件必填 | proxy_mode=existing 时必填,值来自 GET /open/proxy/list 的 code 字段 |
| custom_proxy | object | 条件必填 | proxy_mode=custom 时必填。自定义代理对象,不需要代理名称 |
| custom_proxy.input_type | string | 可选 | manual 手动填写(默认)/ api API 提取 |
| custom_proxy.type | string | 可选 | 代理协议,默认 http;可选 http / https / socks5 |
| custom_proxy.addr | string | 条件必填 | 手动填写时必填,代理主机地址,不包含协议和端口 |
| custom_proxy.port | integer | 条件必填 | 手动填写时必填,范围 1~65535 |
| custom_proxy.username | string | 可选 | 手动代理认证用户名 |
| custom_proxy.password | string | 可选 | 手动代理认证密码 |
| custom_proxy.api_url | string | 条件必填 | API 提取时必填,仅支持 http/https URL;接口需返回 ip:port,多条可用换行、回车或 Tab 分隔。每次打开环境前重新提取 |
proxy_ip_code 与 custom_proxy 不能同时使用。
指纹字段
所有指纹字段均为可选,未传时使用后端默认值。
| 字段 | 类型 | 默认值 | 说明 / 可选值 |
|---|---|---|---|
| webrtc | string | disabled | ip 基于IP | real 真实 | disabled 禁用 | transform_google 转发 |
| webgl | string | real | real 真实 | custom 自定义(需同时提供 webgl_vendor 和 webgl_renderer) |
| webgl_vendor | string | — | webgl=custom 时必填。厂商名,如 Google Inc. (Intel) / Google Inc. (NVIDIA) / Google Inc. (AMD) / Google Inc. (Apple)。查看 GPU 数据集 |
| webgl_renderer | string | — | webgl=custom 时必填。使用与厂商匹配的完整 ANGLE renderer 字符串 |
| webgpu | string | basegl | basegl 基于WebGL | real 真实 | custom 自定义(需提供 webgpu_vendor/architecture/device/description) |
| webgpu_vendor | string | — | webgpu=custom 时使用,如 intel / nvidia / amd / apple。查看 GPU 数据集 |
| webgpu_architecture | string | — | 如 common-shader-cores / rdna-3 / apple-gpu |
| webgpu_device | string | — | 如 integrated-gpu / discrete-gpu |
| webgpu_description | string | — | 如 NVIDIA GeForce RTX 4070 Ti / Intel(R) Iris(R) 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"]。查看语言数据集 |
| 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) |
| local_port_access | string | none | 本机端口扫描保护:none 禁止访问全部 127.0.0.1/::1 端口;all 不额外限制;或填写英文逗号分隔的允许端口,如 80,443,9222 |
| do_not_track | integer | 1 | Do Not Track:1 开启(默认) | 0 关闭 |
| 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加密 |
响应示例
{ "success": true, "data": { "code": "d911bf3f0c482c42d390d3cab6891484" } }
示例
# 最简调用(版本默认最新,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": "账号-自定义代理", "proxy_mode": "custom", "custom_proxy": { "input_type": "manual", "type": "http", "addr": "127.0.0.1", "port": 7890, "username": "user", "password": "pass" } }' # 使用代理 API 提取(每次打开环境前提取) curl -X POST http://127.0.0.1:9001/open/env/create \ -H "Content-Type: application/json" \ -d '{ "name": "账号-API代理", "proxy_mode": "custom", "custom_proxy": { "input_type": "api", "type": "http", "api_url": "https://proxy.example.com/get" } }' # 完整指纹示例 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": "Google Inc. (NVIDIA)", "webgl_renderer": "ANGLE (NVIDIA, NVIDIA GeForce RTX 4070 Ti Direct3D11 vs_5_0 ps_5_0, D3D11)", "timezone": "custom", "timezone_value": "Asia/Shanghai", "geo_location": "custom", "longitude": "116.3", "latitude": "39.9", "language": "custom", "languages": ["zh-CN", "en-US"], "local_port_access": "80,443,9222", "do_not_track": 1, "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 | 必填 | 环境唯一标识 |
响应示例
{
"success": true,
"data": {
"webgl_vendor": "Google Inc. (Intel)",
"webgl_renderer": "ANGLE (Intel, Intel(R) HD Graphics Family..., D3D11)",
"webgpu_value": "intel|common-shader-cores|integrated-gpu|Intel(R) HD Graphics Family",
"font": -2, "canvas": 0.3, "audio": 80, "client_rects": 0.000005,
"speech_voices": true,
"media_devices": [{ "deviceId": "85c7...3169", "kind": "audioinput", "label": "麦克风阵列 ...", "groupId": "9baa...4f8f" }],
"font_list": ["Arial", "Calibri", "Microsoft YaHei", "..."]
}
}
示例
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 时浏览器不显示窗口,适合自动化场景 |
| openTabs | boolean | 可选 | 是否按环境配置打开标签页,默认 false |
| needDebugPort | boolean | 可选 | 是否分配并等待调试端口,默认 true。谷歌使用 CDP,火狐使用 WebDriver BiDi;设为 false 时响应中的调试字段为 null |
| args | string[] | 可选 | 追加给所选内核的启动参数;请使用该内核支持的参数 |
响应示例
// 谷歌:原有 pid/debug_port 字段保持不变 { "success": true, "data": { "pid": 15012, "debug_port": 19222, "browser_kernel": "chrome", "debug_protocol": "cdp", "debug_endpoint": "http://127.0.0.1:19222" } } // 火狐:调试端口提供 WebDriver BiDi { "success": true, "data": { "pid": 15013, "debug_port": 19223, "browser_kernel": "firefox", "debug_protocol": "webdriver-bidi", "debug_endpoint": "ws://127.0.0.1:19223/session" } }
谷歌:通过 CDP 接入自动化框架
# 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)
火狐请使用支持 WebDriver BiDi 的客户端连接 debug_endpoint。此地址不是 Playwright 原生协议地址,不能传给 playwright.firefox.connect();connect_over_cdp 也只适用于谷歌。needDebugPort=false 时 debug_port、debug_protocol 和 debug_endpoint 均为 null。
每次启用调试端口的 POST /open/env/open 都会分配唯一端口,浏览器关闭后端口自动释放并可被复用。
Body 参数
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| code | string | 必填 | 环境唯一标识 |
响应
{ "success": true } // 浏览器未运行时返回 success: false
Query 参数
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| code | string | 必填 | 环境唯一标识 |
响应示例
{
"success": true,
"data": { "code": "11111", "status": "stopped", "pid": null, "debug_port": null }
}
Body 参数
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| code | string | 必填 | 环境唯一标识 |
响应
{ "success": true }
清空操作会删除本地 %appdata%\qiyuan\user_data\{code} 目录,若该环境开启了云同步则同时删除服务器备份。
代理接口 Proxy
Query 参数
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| page | number | 可选 | 页码,默认 1 |
| page_size | number | 可选 | 每页数量,默认 20,最大 100 |
| keyword | string | 可选 | 按名称或地址模糊搜索 |
响应示例
{
"success": true,
"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 | 可选 | 认证密码 |
响应示例
{ "success": true, "data": { "code": "1716523200abc" } }
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 }
数据集
创建和修改环境时,可参考以下内置数据集选择相互匹配的指纹参数。以下为版本 2026-07-23 的静态快照。
WebGL + WebGPU
先按平台选择厂商,再在该厂商下选择完整的 webgl_renderer。同一行的 webgl_vendor、webgl_renderer 与 WebGPU 字段必须配套使用。
| 平台 | 可用厂商 |
|---|---|
Win32 | AMD、Intel、NVIDIA |
Linux x86_64 | AMD、Intel、NVIDIA |
MacIntel | Apple |
语言
languages 可传下列语言代码;多个语言以字符串数组传递。ui_language_value 使用同一份列表中的单个代码。
时区
timezone_value 可传下列 IANA 时区。
接口规格
请求规格
| 项目 | 规范 |
|---|---|
| 请求 URL | 本机服务地址 http://127.0.0.1:{port} 加接口路径;默认端口为 9001。 |
| Header | POST 请求携带 Content-Type: application/json。Qiyuan 客户端 API 模式无需鉴权 Header;嵌入式客户端设置 service_token 时携带 X-Qiyuan-Runtime-Token。 |
| Body | POST 接口使用 JSON Object;必填与条件必填字段见各接口说明。 |
| Query | GET 接口使用 URL Query String;未传的可选字段使用接口默认值。 |
响应规格
所有接口均以 HTTP 200 返回,响应 Body 为 JSON:
// 成功 { "success": true, "data": { /* 业务数据 */ } } // 失败 { "success": false, "error": "错误描述" }
部分接口成功时不返回 data 字段(如 delete、close),只需判断 success 即可。
使用示例
以下接口均为本机 HTTP + JSON 协议。除 cURL、Python、Node.js、Java 外,也可使用 Go、C#、PHP、Rust 等任意语言的 HTTP Client 调用。
# 1. 查询环境(Qiyuan 客户端模式,或未配置 service_token 的嵌入式客户端) curl "http://127.0.0.1:9001/open/env/list?page=1&page_size=10" # 2. 配置 service_token 的嵌入式客户端:所有请求附加此 Header curl "http://127.0.0.1:9001/open/env/list?page=1&page_size=10" \ -H "X-Qiyuan-Runtime-Token: your_service_token" # 3. 新增环境(最简) curl -X POST "http://127.0.0.1:9001/open/env/create" \ -H "Content-Type: application/json" \ -d '{"name":"账号-01"}' # 4. 新增环境并使用自定义代理、时区和语言 curl -X POST "http://127.0.0.1:9001/open/env/create" \ -H "Content-Type: application/json" \ -d '{"name":"账号-代理","proxy_mode":"custom","custom_proxy":{"input_type":"manual","type":"socks5","addr":"1.2.3.4","port":1080,"username":"user","password":"pass"},"timezone":"custom","timezone_value":"Asia/Shanghai","language":"custom","languages":["zh-CN","en-US"]}' # 5. 新增 API 提取代理(每次打开绑定环境时自动提取) curl -X POST "http://127.0.0.1:9001/open/proxy/create" \ -H "Content-Type: application/json" \ -d '{"proxy_name":"动态住宅代理","proxy_type":"http","proxy_input_type":"api","proxy_api_url":"https://proxy.example.com/get"}' # 6. 打开环境,返回 pid 和 CDP 调试端口 curl -X POST "http://127.0.0.1:9001/open/env/open" \ -H "Content-Type: application/json" \ -d '{"code":"ENV_CODE","needDebugPort":true}' # 7. 查询状态、关闭环境 curl "http://127.0.0.1:9001/open/env/status?code=ENV_CODE" curl -X POST "http://127.0.0.1:9001/open/env/close" -H "Content-Type: application/json" -d '{"code":"ENV_CODE"}'
# 依赖: 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() # ── 新增环境(使用自定义手动代理;代理不需要 name)────────────────────── print("[环境] 正在新增环境...") res = post("/open/env/create", name="账号-01", browser_version="138.0.7204.184", # 推荐显式传入;不传则自动取最新,需先在管理界面下载对应版本 proxy_mode="custom", custom_proxy={ "input_type": "manual", "type": "http", "addr": "127.0.0.1", "port": 7890, "username": "user", "password": "pass", }, 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("[关闭] 完成"); } }