开放接口文档

启元指纹浏览器 · 本地客户端开放 API · v1

认证流程

只需在启动客户端时传入 --run_mode=api --app_id=xxx --app_secret=xxx, 客户端自动完成身份认证,后续所有接口调用均无需额外传递凭证。
AppID 和 AppSecret 从「开发者中心」页面获取。

建立连接

开放接口是通过Socket.IO协议进行通讯的,客户端启动后,Socket.IO 服务默认监听在 http://127.0.0.1:9001(可通过 --port 参数修改)。

启动命令

Qiyuan.exe --run_mode=api --port=9001 --app_id=your_app_id --app_secret=your_app_secret

接入示例(Node.js)

// npm install socket.io-client
const { io } = require('socket.io-client');
const socket = io('http://127.0.0.1:9001');

socket.on('connect', () => {
  console.log('已连接到启元客户端');
});

socket.emit('env:list', { page: 1, page_size: 10 }, (res) => {
  if (res.success) console.log(res.data.items);
  else console.error(res.error);
});

环境接口

env:list emit 查询环境列表

入参

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

响应 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"
    }
  ]
}
env:create emit 新增环境

基础信息字段

字段类型必填默认值说明
namestring必填环境名称
platformstring可选Win32操作系统。可选值:Win32 / MacIntel / Linux x86_64
browser_versionstring可选145.0.7632.109(最新)完整内核版本号。不填自动取最新版本。可选值:145.0.7632.109 / 139.0.7258.67 / 138.0.7204.184
user_agentstring可选自动生成User-Agent。不填时根据 platform + browser_version 自动生成(UA 随版本变化)
proxy_ip_codestring可选绑定代理的唯一标识(来自 proxy:list 的 code 字段)
open_home_pageboolean可选false是否打开首页
enable_tabsboolean可选false是否启用多标签页
tabsstring可选""标签页 URL,多个用换行分隔(enable_tabs=true 时生效)
sync_user_infoboolean可选false是否开启云端用户信息同步(账号数据云备份)
cookiestring可选""初始 Cookie 内容
launch_argsstring可选""额外 Chrome 启动参数,空格分隔,如 --disable-gpu --no-sandbox
remarkstring可选""备注
tag_idsnumber[]可选[]标签 ID 列表

指纹字段

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

字段类型默认值说明 / 可选值
webrtcstringdisabledip 基于IP  |  real 真实  |  disabled 禁用  |  transform_google 转发
webglstringrealreal 真实  |  custom 自定义(需同时提供 webgl_vendorwebgl_renderer
webgl_vendorstringwebgl=custom 时必填。厂商名,如 Intel Inc. / NVIDIA Corporation / AMD / Apple Inc.
webgl_rendererstringwebgl=custom 时必填。渲染器名,如 Intel(R) UHD Graphics 630 / NVIDIA GeForce RTX 4090
webgpustringbaseglbasegl 基于WebGL  |  real 真实  |  custom 自定义(需提供 webgpu_vendor/architecture/device/description)
webgpu_vendorstringwebgpu=custom 时使用,如 intel / nvidia / amd / apple
webgpu_architecturestringcommon-shader-cores / rdna-3 / apple-gpu
webgpu_devicestringintegrated-gpu / discrete-gpu
webgpu_descriptionstringNVIDIA GeForce RTX 4090 / Intel Iris Xe Graphics
timezonestringipip 基于IP  |  real 真实  |  custom 自定义(需提供 timezone_value
timezone_valuestringtimezone=custom 时使用,IANA 时区格式,如 Asia/Shanghai / America/New_York / Europe/London
geo_locationstringipip 基于IP  |  real 真实  |  custom 自定义(需提供 longitudelatitude
longitudestringgeo_location=custom 时使用,经度,如 116.3
latitudestringgeo_location=custom 时使用,纬度,如 39.9
languagestringipip 基于IP  |  real 真实  |  custom 自定义(需提供 languages 数组)
languagesstring[]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_languagestringlanguagelanguage 跟随语言  |  real 真实  |  custom 自定义(需提供 ui_language_value
ui_language_valuestringui_language=custom 时使用,单个语言代码,如 zh-CN
screen_resolutionstringrealreal 真实  |  custom 自定义(需提供 screen_resolution_value
screen_resolution_valuestringscreen_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)
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加密

响应 data

{
  "code": "a1b2c3..."  // string  新建环境的唯一标识(后续所有操作使用此字段)
}

示例

# 最简调用(版本默认最新,UA 自动生成,指纹全部随机)
call("env:create", {"name": "账号01"})

# 完整指纹示例
call("env:create", {
    "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",
    "webgpu": "basegl",                       # 跟随 WebGL
    "timezone": "custom",
    "timezone_value": "Asia/Shanghai",
    "geo_location": "custom",
    "longitude": "116.3",
    "latitude": "39.9",
    "language": "custom",
    "languages": ["zh-CN", "en-US"],
    "screen_resolution": "custom",
    "screen_resolution_value": "1920|1080",
    "font": "random",
    "canvas": "random",
    "audio": "random",
    "client_rects": "random",
    "speech_voices": True,
    "media_devices": "random",
    "cpu_cores": "8",
    "memory_gb": "16",
    "tls": "enabled",               # 不填 tls_features 则默认启用全部
    "enable_tabs": True,
    "tabs": "https://www.google.com\nhttps://www.example.com",
    "sync_user_info": False,
    "remark": "由脚本创建",
})
env:update emit 修改环境(只传需要修改的字段)

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

必填字段

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

可修改字段

与 env:create 入参完全一致(除 name 不再必填),包括所有基础信息字段和指纹字段。

特别说明:若修改了 platformbrowser_version 但未传 user_agent,系统自动重新生成匹配的 UA。

响应

{ "success": true }

示例

# 只修改备注
call("env:update", {"code": env_code, "remark": "新备注"})

# 切换代理并修改 WebRTC 策略
call("env:update", {
    "code": env_code,
    "proxy_ip_code": "NEW_PROXY_CODE",
    "webrtc": "disabled",
})

# 修改版本(UA 自动跟随更新)
call("env:update", {"code": env_code, "browser_version": "145.0.7632.109"})
env:randomize_fingerprint emit 随机刷新指纹

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

入参

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

响应 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
}

示例

call("env:randomize_fingerprint", {"code": env_code})
env:delete emit 删除环境

入参

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

响应

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

入参

字段类型必填说明
codestring必填环境唯一标识
headlessboolean可选是否无头模式,默认 false。设为 true 时浏览器不显示窗口,适合自动化场景
argsstring[]可选追加给 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)

每次 env:open 都会分配唯一调试端口,浏览器关闭后端口自动释放并可被复用。

env:close emit 关闭浏览器

入参

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

响应

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

入参

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

响应 data

{
  "code": "a1b2c3...",   // string  环境唯一标识
  "status": "running",   // string  running | stopped
  "pid": 12345,          // number  进程 PID,stopped 时为 null
  "debug_port": 19222   // number  CDP 调试端口,stopped 时为 null
}
env:clear_cache emit 清空浏览器缓存

入参

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

响应

{ "success": true }

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

代理接口

proxy:list emit 查询代理列表

入参

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

响应 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"
    }
  ]
}
proxy:create emit 新增代理

入参

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

响应 data

{
  "code": "1716523200abc"    // string  新建代理的唯一标识(用于绑定到环境)
}
proxy:update emit 修改代理

入参

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

响应

{ "success": true }
proxy:delete emit 删除代理

入参

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

响应

{ "success": true }

统一响应格式

所有接口均通过 Socket.IO 的 ACK 回调函数返回结果:

// 成功
{ "success": true, "data": { /* 业务数据 */ } }

// 失败
{ "success": false, "error": "错误描述" }

部分接口成功时不返回 data 字段(如 delete、close),只需判断 success 即可。

使用示例

# 依赖: pip install "python-socketio[client]" playwright
# playwright install chromium
import socketio, time

SERVER_URL = "http://127.0.0.1:9001"
sio = socketio.Client()

def call(event, data=None):
    result, done = {}, [False]
    def cb(res): result.update(res); done[0] = True
    sio.emit(event, data or {}, callback=cb)
    t = 30
    while not done[0] and t > 0: time.sleep(0.1); t -= 0.1
    return result

print("[连接] 正在连接到启元客户端...")
sio.connect(SERVER_URL)
print("[连接] 已连接")

# ── 新增代理 ──────────────────────────────────────────────────────────────
print("[代理] 正在新增代理...")
res = call("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 = call("env:create", {
    "name": "账号-01",
    # proxy_ip_code 暂不绑定,如需绑定传入: "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 = call("env:randomize_fingerprint", {"code": env_code})
print("[指纹] 结果:", res["data"])

# ── 打开浏览器(headless=False 显示窗口)─────────────────────────────────
print("[浏览器] 正在打开浏览器...")
res = call("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:
    # ===================== 无论成功/失败/崩溃,100% 执行
    print(f"[批量] 获取浏览器状态 {env_code}...")
    r = call("env:status", {"code": env_code})
    print(f"状态结果={r}")
    print("[关闭] 正在执行兜底关闭...")
    call("env:close", {"code": env_code})
    print("[关闭] 完成")


# ── 接入 Selenium ──────────────────────────────────────────────────────────
# pip install selenium
# from selenium import webdriver
# from selenium.webdriver.chrome.options import Options
# from selenium.webdriver.chrome.service import Service
# options = Options()
# options.add_experimental_option("debuggerAddress", f"127.0.0.1:{debug_port}")
# # driver = webdriver.Chrome(options=options)
# # chromedriver 下载地址对应浏览器版本(比如
# #   138.x):https://storage.googleapis.com/chrome-for-testing-public/138.0.7204.184/win64/chromedriver-win64.zip,选对应版本的 win64 chromedriver 下载即可
# service = Service(executable_path=r"D:\webdrivers\chromedriver138.exe")
# driver = webdriver.Chrome(service=service, options=options)
# driver.get("https://www.example.com")
# print("Selenium 页面标题:", driver.title)
# driver.quit()

# ── 批量查询环境列表 ───────────────────────────────────────────────────────
print("[批量] 查询环境列表...")
res = call("env:list", {"page": 1, "page_size": 10})
for env in res["data"]["items"]:
    print(f"环境结果={env}")

sio.disconnect()
print("[连接] 已断开")
// 依赖: npm install socket.io-client playwright
const { io } = require("socket.io-client");

const socket = io("http://127.0.0.1:9001");
const call = (event, data = {}) =>
  new Promise((resolve) => socket.emit(event, data, resolve));

socket.on("connect", async () => {
  console.log("[连接] 已连接到启元客户端");

  // ── 新增代理 ──────────────────────────────────────────────────────────
  console.log("[代理] 正在新增代理...");
  let res = await call("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("[代理] code=", proxyCode);

  // ── 新增环境 ──────────────────────────────────────────────────────────
  console.log("[环境] 正在新增环境...");
  res = await call("env:create", {
    name: "账号-01",
    // proxy_ip_code 暂不绑定,如需绑定传入: 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("[环境] code=", envCode);

  // ── 刷新指纹 ──────────────────────────────────────────────────────────
  console.log("[指纹] 正在随机刷新指纹...");
  res = await call("env:randomize_fingerprint", { code: envCode });
  console.log("[指纹] 结果:", res.data);

  // ── 打开浏览器 ────────────────────────────────────────────────────────
  console.log("[浏览器] 正在打开浏览器...");
  res = await call("env:open", { code: envCode, headless: true });
  console.log("[浏览器] 结果:", res);
  const debugPort = res.data.debug_port;
  console.log("[浏览器] 调试端口=", debugPort);

// ── 接入 Playwright ───────────────────────────────────────
console.log("[Playwright] 正在连接...");
const { chromium } = require("playwright");

let browser = null; // 提升作用域,finally 里能访问

try {
    // 1. 连接浏览器
    browser = await chromium.connectOverCDP(`http://127.0.0.1:${debugPort}`);

    // 2. 获取页面
    const page = browser.contexts()[0].pages()[0];

    // 3. 访问网页
    await page.goto("https://www.example.com");
    const title = await page.title();
    console.log("[Playwright] 页面标题=", title);

} catch (err) {
    // 出错立即抛出,不吞错,保证及时报错
    console.error("[Playwright] 执行失败:", err.message);
    throw err; // 关键:抛出错误,外部能捕获

} finally {
    // ======================= 无论成功/失败/崩溃,100% 执行 =======================
    console.log("[兜底] 开始执行统一关闭流程...");

    try {
        // 1. 关闭 Playwright 浏览器
        if (browser) {
            await browser.close().catch(() => {}); // 关闭失败也不阻塞
            console.log("[Playwright] 已安全关闭");
        }

        // 2. 执行 env:close 兜底
        await call("env:close", { code: envCode }).catch(() => {});
        console.log("[关闭] env:close 已执行");

        // 3. 断开 socket
        if (socket) {
            socket.disconnect();
            console.log("[连接] socket 已断开");
        }

    } catch (cleanupErr) {
        console.warn("[兜底] 关闭流程出现轻微异常:", cleanupErr.message);
    }

    console.log("[兜底] 所有收尾任务执行完成");
}
});
// Maven 依赖:
//   io.socket:socket.io-client:2.1.0
//   org.json:json:20231013
import io.socket.client.IO;
import io.socket.client.Socket;
import org.json.JSONArray;
import org.json.JSONObject;
import java.util.concurrent.CountDownLatch;

public class QiyuanDemo {

    static Socket socket;

    static JSONObject call(String event, JSONObject data) throws Exception {
        JSONObject[] result = {null};
        CountDownLatch latch = new CountDownLatch(1);
        socket.emit(event, data, (Object... args) -> {
            result[0] = new JSONObject(args[0].toString());
            latch.countDown();
        });
        latch.await();
        return result[0];
    }

    public static void main(String[] args) throws Exception {
        System.out.println("[连接] 正在连接到启元客户端...");
        socket = IO.socket("http://127.0.0.1:9001");
        socket.connect();
        Thread.sleep(1000);
        System.out.println("[连接] 已连接");

        // ── 新增代理 ──────────────────────────────────────────────────
        System.out.println("[代理] 正在新增代理...");
        JSONObject proxyRes = call("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("[代理] code=" + proxyCode);

        // ── 新增环境 ──────────────────────────────────────────────────
        System.out.println("[环境] 正在新增环境...");
        JSONObject envRes = call("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 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("[环境] code=" + envCode);

        // ── 刷新指纹 ──────────────────────────────────────────────────
        System.out.println("[指纹] 正在随机刷新指纹...");
        JSONObject fpRes = call("env:randomize_fingerprint",
            new JSONObject().put("code", envCode));
        System.out.println("[指纹] 结果: " + fpRes.opt("data"));

        // ── 打开浏览器 ────────────────────────────────────────────────
        System.out.println("[浏览器] 正在打开浏览器...");
        JSONObject openRes = call("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) ────────────────
        // System.out.println("[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("[关闭] 正在关闭浏览器...");
        call("env:close", new JSONObject().put("code", envCode));
        System.out.println("[关闭] 完成");
        socket.disconnect();
        System.out.println("[连接] 已断开");
    }
}
启元指纹浏览器开放平台 · 如有问题请联系技术支持