开放接口文档

启元指纹浏览器 · 本地客户端开放 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.exe
QiyuanCloudRuntime.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。同一端口只能运行其中一种模式。

请求说明

快速验证

# 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"

环境接口

GET /open/env/list 查询环境列表

Query 参数

字段类型必填说明
pagenumber可选页码,默认 1
page_sizenumber可选每页数量,默认 20,最大 100
keywordstring可选按环境名称模糊搜索

响应示例

{
  "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"
      }
    ]
  }
}
POST /open/env/create 新增环境

基础信息字段

字段类型必填默认值说明
namestring必填—环境名称
platformstring可选Win32操作系统。可选值:Win32 / MacIntel / Linux x86_64
browser_kernelstring可选chrome浏览器内核:chrome 谷歌 / firefox 火狐。不传兼容旧 API,使用谷歌
browser_versionstring可选所选内核的最新版本完整内核版本号。不填时按 browser_kernel 选择最新版本;Firefox 未配置版本列表时需显式传入
user_agentstring可选自动生成User-Agent。不填时根据 platform + browser_version 自动生成(UA 随版本变化)
proxy_modestring可选自动判断代理方式:no_proxy 无代理 / existing 已添加代理 / custom 自定义代理。不传时根据 proxy_ip_code/custom_proxy 自动判断,都未传则使用无代理
open_home_pageboolean可选false是否打开首页
enable_tabsboolean可选false是否启用多标签页
tabsstring可选""标签页 URL,多个用换行分隔(enable_tabs=true 时生效)
sync_user_infoboolean可选false是否开启云端用户信息同步(账号数据云备份)
cookiestring可选""初始 Cookie 内容
launch_argsstring可选""额外浏览器启动参数,空格分隔;参数需适用于所选内核
remarkstring可选""备注
tag_idsnumber[]可选[]标签 ID 列表

代理字段

字段类型必填说明
proxy_ip_codestring条件必填proxy_mode=existing 时必填,值来自 GET /open/proxy/list 的 code 字段
custom_proxyobject条件必填proxy_mode=custom 时必填。自定义代理对象,不需要代理名称
custom_proxy.input_typestring可选manual 手动填写(默认)/ api API 提取
custom_proxy.typestring可选代理协议,默认 http;可选 http / https / socks5
custom_proxy.addrstring条件必填手动填写时必填,代理主机地址,不包含协议和端口
custom_proxy.portinteger条件必填手动填写时必填,范围 1~65535
custom_proxy.usernamestring可选手动代理认证用户名
custom_proxy.passwordstring可选手动代理认证密码
custom_proxy.api_urlstring条件必填API 提取时必填,仅支持 http/https URL;接口需返回 ip:port,多条可用换行、回车或 Tab 分隔。每次打开环境前重新提取

proxy_ip_code 与 custom_proxy 不能同时使用。

指纹字段

所有指纹字段均为可选,未传时使用后端默认值。

字段类型默认值说明 / 可选值
webrtcstringdisabledip 基于IP  |  real 真实  |  disabled 禁用  |  transform_google 转发
webglstringrealreal 真实  |  custom 自定义(需同时提供 webgl_vendor 和 webgl_renderer)
webgl_vendorstring—webgl=custom 时必填。厂商名,如 Google Inc. (Intel) / Google Inc. (NVIDIA) / Google Inc. (AMD) / Google Inc. (Apple)。查看 GPU 数据集
webgl_rendererstring—webgl=custom 时必填。使用与厂商匹配的完整 ANGLE renderer 字符串
webgpustringbaseglbasegl 基于WebGL  |  real 真实  |  custom 自定义(需提供 webgpu_vendor/architecture/device/description)
webgpu_vendorstring—webgpu=custom 时使用,如 intel / nvidia / amd / apple。查看 GPU 数据集
webgpu_architecturestring—如 common-shader-cores / rdna-3 / apple-gpu
webgpu_devicestring—如 integrated-gpu / discrete-gpu
webgpu_descriptionstring—如 NVIDIA GeForce RTX 4070 Ti / Intel(R) Iris(R) Xe Graphics
timezonestringipip 基于IP  |  real 真实  |  custom 自定义(需提供 timezone_value)
timezone_valuestring—timezone=custom 时使用,IANA 时区格式,如 Asia/Shanghai / America/New_York / Europe/London。查看时区数据集
geo_locationstringipip 基于IP  |  real 真实  |  custom 自定义(需提供 longitude 和 latitude)
longitudestring—geo_location=custom 时使用,经度,如 116.3
latitudestring—geo_location=custom 时使用,纬度,如 39.9
languagestringipip 基于IP  |  real 真实  |  custom 自定义(需提供 languages 数组)
languagesstring[]—language=custom 时使用,语言代码数组,如 ["zh-CN","en-US"]。查看语言数据集
ui_languagestringlanguagelanguage 跟随语言  |  real 真实  |  custom 自定义(需提供 ui_language_value)
ui_language_valuestring—ui_language=custom 时使用,单个语言代码,如 zh-CN。查看语言数据集
screen_resolutionstringrealreal 真实  |  custom 自定义(需提供 screen_resolution_value)
screen_resolution_valuestring—screen_resolution=custom 时使用,格式 宽|高,可选:1920|1080 / 2560|1440 / 3840|2160 / 1366|768 / 1440|900 / 1536|864 / 1280|720 / 2560|1080 等
fontstringrandomdisabled 关闭(值固定为0) |  random 随机(服务端生成 -2~2 整数偏移量)
canvasstringrandomdisabled 关闭  |  random 随机(服务端生成 0~1 浮点噪点,2位小数)
audiostringrandomdisabled 关闭  |  random 随机(服务端生成 0~99 整数噪点)
client_rectsstringrandomdisabled 关闭  |  random 随机(服务端生成 0~0.00001 浮点偏移,6位小数)
speech_voicesbooleantruetrue 开启  |  false 关闭语音合成设备伪装
media_devicesstringrandomdisabled 关闭(null) |  random 随机(服务端生成5个随机媒体设备ID)
local_port_accessstringnone本机端口扫描保护:none 禁止访问全部 127.0.0.1/::1 端口;all 不额外限制;或填写英文逗号分隔的允许端口,如 80,443,9222
do_not_trackinteger1Do Not Track:1 开启(默认) |  0 关闭
cpu_coresstringrealreal 使用真实值  |  2 / 4 / 6 / 8 / 10 / 12 / 16 / 20 / 24 / 32
memory_gbstringrealreal 使用真实值  |  2 / 4 / 8 / 16 / 32 / 64 / 128(单位 GB)
tlsstringenableddisabled 关闭  |  enabled 启用(不传 tls_features 则默认启用全部特征)
tls_featuresstring[]—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/update 修改环境(只传需要修改的字段)

支持与 POST /open/env/create 相同的所有字段(code 必填,其余字段只传需要修改的)。未传的字段保持不变。

必填字段

字段类型说明
codestring环境唯一标识

可修改字段

与新增环境入参完全一致(除 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"}'
POST /open/env/randomize_fingerprint 随机刷新指纹

一键随机重新生成环境的指纹数据,逻辑与客户端界面的"随机指纹"按钮完全一致。WebGL/WebGPU 按平台随机,font/canvas/audio/client_rects/media_devices 全部重新随机,时区/地理位置/语言保持基于IP策略。

Body 参数

字段类型必填说明
codestring必填环境唯一标识

响应示例

{
  "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"}'
POST /open/env/delete 删除环境

Body 参数

字段类型必填说明
codestring必填环境唯一标识

响应

{ "success": true }
POST /open/env/open 打开浏览器(自动同步扩展、分配调试端口)

Body 参数

字段类型必填说明
codestring必填环境唯一标识
headlessboolean可选是否无头模式,默认 false。设为 true 时浏览器不显示窗口,适合自动化场景
openTabsboolean可选是否按环境配置打开标签页,默认 false
needDebugPortboolean可选是否分配并等待调试端口,默认 true。谷歌使用 CDP,火狐使用 WebDriver BiDi;设为 false 时响应中的调试字段为 null
argsstring[]可选追加给所选内核的启动参数;请使用该内核支持的参数

响应示例

// 谷歌:原有 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 都会分配唯一端口,浏览器关闭后端口自动释放并可被复用。

POST /open/env/close 关闭浏览器

Body 参数

字段类型必填说明
codestring必填环境唯一标识

响应

{ "success": true }  // 浏览器未运行时返回 success: false
GET /open/env/status 获取运行状态

Query 参数

字段类型必填说明
codestring必填环境唯一标识

响应示例

{
  "success": true,
  "data": { "code": "11111", "status": "stopped", "pid": null, "debug_port": null }
}
POST /open/env/clear_cache 清空浏览器缓存

Body 参数

字段类型必填说明
codestring必填环境唯一标识

响应

{ "success": true }

清空操作会删除本地 %appdata%\qiyuan\user_data\{code} 目录,若该环境开启了云同步则同时删除服务器备份。

代理接口

GET /open/proxy/list 查询代理列表

Query 参数

字段类型必填说明
pagenumber可选页码,默认 1
page_sizenumber可选每页数量,默认 20,最大 100
keywordstring可选按名称或地址模糊搜索

响应示例

{
  "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"
    }
  ]
  }
}
POST /open/proxy/create 新增代理

Body 参数

字段类型必填说明
proxy_namestring必填代理名称
proxy_typestring必填代理类型:http / https / socks5
proxy_addrstring必填代理服务器地址(IP 或域名)
proxy_portnumber必填代理端口(1-65535)
usernamestring可选认证用户名
passwordstring可选认证密码

响应示例

{ "success": true, "data": { "code": "1716523200abc" } }
POST /open/proxy/update 修改代理

Body 参数

字段类型必填说明
codestring必填代理唯一标识
proxy_namestring可选新的代理名称
proxy_typestring可选新的代理类型
proxy_addrstring可选新的代理地址
proxy_portnumber可选新的代理端口
usernamestring可选新的认证用户名
passwordstring可选新的认证密码

响应

{ "success": true }
POST /open/proxy/delete 删除代理

Body 参数

字段类型必填说明
codestring必填代理唯一标识

响应

{ "success": true }

数据集

创建和修改环境时,可参考以下内置数据集选择相互匹配的指纹参数。以下为版本 2026-07-23 的静态快照。

WebGL + WebGPU

先按平台选择厂商,再在该厂商下选择完整的 webgl_renderer。同一行的 webgl_vendor、webgl_renderer 与 WebGPU 字段必须配套使用。

平台可用厂商
Win32AMD、Intel、NVIDIA
Linux x86_64AMD、Intel、NVIDIA
MacIntelApple

语言

languages 可传下列语言代码;多个语言以字符串数组传递。ui_language_value 使用同一份列表中的单个代码。

时区

timezone_value 可传下列 IANA 时区。

接口规格

请求规格

项目规范
请求 URL本机服务地址 http://127.0.0.1:{port} 加接口路径;默认端口为 9001。
HeaderPOST 请求携带 Content-Type: application/json。Qiyuan 客户端 API 模式无需鉴权 Header;嵌入式客户端设置 service_token 时携带 X-Qiyuan-Runtime-Token。
BodyPOST 接口使用 JSON Object;必填与条件必填字段见各接口说明。
QueryGET 接口使用 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("[关闭] 完成");
    }
}
启元指纹浏览器开放平台 · 如有问题请联系技术支持