Skip to content

快速上手:接管候鸟浏览器环境

本章提供三种语言的完整可运行脚本,选一种您熟悉的,照着跑起来即可。核心逻辑都一样——先向 ApiServer 要 ws 地址,再用 connectOverCDP 接管候鸟浏览器。


方式一:JavaScript / Node.js 版本

创建文件 start.js

javascript
const { chromium } = require('playwright');
const axios = require('axios');

// ============================
// 配置区域(按您的实际情况填写)
// ============================
const API_URL    = 'http://127.0.0.1:8186';
const SESSION_ID = '替换为您的环境ID';   // 右键候鸟环境 → 复制环境ID

async function main() {
  // ── 第一步:通知 ApiServer 开启指定候鸟环境 ──────────
  console.log('⏳ 正在开启候鸟环境...');
  let wsEndpoint;
  try {
    const response = await axios.post(`${API_URL}/api/v1/browser/start`, {
      Session_ID: SESSION_ID
    });
    if (response.data.code !== 0) {
      console.error('❌ 环境启动失败:', response.data.message);
      return;
    }
    // ── 第二步:取出 WebSocket 地址(Playwright 专用字段)──
    wsEndpoint = response.data.data.ws;
    console.log('✅ 环境已开启,ws 地址:', wsEndpoint);
  } catch (err) {
    console.error('❌ 无法连接到 ApiServer,请确认已启动!', err.message);
    return;
  }

  // ── 第三步:用 connectOverCDP 接管候鸟浏览器 ─────────
  const browser = await chromium.connectOverCDP(wsEndpoint);
  console.log('🎉 Playwright 接管成功!');

  try {
    // ── 第四步:获取当前上下文和页面 ────────────────────
    // 候鸟环境已有一个默认上下文,直接取第一个即可
    const context = browser.contexts()[0];
    const page    = context.pages()[0] || await context.newPage();

    // ── 第五步:执行您的业务操作 ─────────────────────────
    await page.goto('https://www.mbbrowser.com', { waitUntil: 'domcontentloaded' });
    console.log('📄 当前页面标题:', await page.title());

    // 等待 3 秒,便于肉眼观察
    await page.waitForTimeout(3000);

    console.log('✅ 脚本执行完毕!');
  } finally {
    // 断开 Playwright 连接(候鸟浏览器窗口继续保持运行)
    await browser.close();
  }
}

main().catch(console.error);

运行:

bash
node start.js

方式二:Python 版本

创建文件 start_playwright.py

python
import requests
from playwright.sync_api import sync_playwright

# ============================
# 配置区域
# ============================
API_URL    = "http://127.0.0.1:8186"
SESSION_ID = "替换为您的环境ID"


def get_ws_endpoint(session_id: str) -> str | None:
    """调用候鸟 ApiServer,开启环境并返回 ws 地址"""
    print("⏳ 正在开启候鸟环境...")
    try:
        resp = requests.post(
            f"{API_URL}/api/v1/browser/start",
            json={"Session_ID": session_id},
            timeout=30
        )
        data = resp.json()
    except requests.exceptions.ConnectionError:
        print("❌ 无法连接到 ApiServer!请确认已启动 apiserver.exe")
        return None

    if data.get("code") != 0:
        print(f"❌ 环境启动失败: {data.get('message')}")
        return None

    ws = data["data"]["ws"]
    print(f"✅ 环境已开启,ws 地址: {ws}")
    return ws


def main():
    ws_endpoint = get_ws_endpoint(SESSION_ID)
    if not ws_endpoint:
        return

    with sync_playwright() as p:
        # ── connectOverCDP 接管候鸟浏览器 ─────────────────
        browser = p.chromium.connect_over_cdp(ws_endpoint)
        print("🎉 Playwright 接管成功!")

        # 取候鸟已有的默认 BrowserContext(保留所有 Cookie、存储等)
        context = browser.contexts[0]
        # 取第一个页面,如果没有则新建
        page = context.pages[0] if context.pages else context.new_page()

        # ── 执行业务操作 ───────────────────────────────────
        page.goto("https://www.mbbrowser.com", wait_until="domcontentloaded")
        print(f"📄 当前页面标题: {page.title()}")

        page.wait_for_timeout(3000)
        print("✅ 脚本执行完毕!")

        browser.close()


if __name__ == "__main__":
    main()

运行(在候鸟虚拟环境中,或直接用系统 Python):

bash
python start_playwright.py

方式三:Java 版本

NOTE

Java 版本建议通过候鸟客户端的自动化脚本管理器来运行,候鸟会自动处理 Playwright JAR 包和驱动提取。以下代码可以直接在脚本编辑器中使用。

java
import com.microsoft.playwright.*;
import java.net.URI;
import java.net.http.*;
import org.json.*;

public class MBPlaywright {
    static final String API_URL    = "http://127.0.0.1:8186";
    static final String SESSION_ID = "替换为您的环境ID";

    public static void main(String[] args) throws Exception {
        // ── 第一步:调用 ApiServer 开启环境 ──────────────
        System.out.println("⏳ 正在开启候鸟环境...");
        HttpClient httpClient = HttpClient.newHttpClient();
        String body = "{\"Session_ID\":\"" + SESSION_ID + "\"}";
        HttpRequest request = HttpRequest.newBuilder()
            .uri(URI.create(API_URL + "/api/v1/browser/start"))
            .header("Content-Type", "application/json")
            .POST(HttpRequest.BodyPublishers.ofString(body))
            .build();
        HttpResponse<String> response = httpClient.send(
            request, HttpResponse.BodyHandlers.ofString()
        );

        JSONObject data   = new JSONObject(response.body());
        String wsEndpoint = data.getJSONObject("data").getString("ws");
        System.out.println("✅ 环境已开启,ws: " + wsEndpoint);

        // ── 第二步:Playwright connectOverCDP 接管 ────────
        // 设置跳过内置浏览器下载(用候鸟的)
        System.setProperty("playwright.skip.browser.download", "1");

        try (Playwright playwright = Playwright.create()) {
            Browser browser = playwright.chromium().connectOverCDP(wsEndpoint);
            System.out.println("🎉 Playwright 接管成功!");

            BrowserContext context = browser.contexts().get(0);
            Page page = context.pages().isEmpty()
                ? context.newPage()
                : context.pages().get(0);

            page.navigate("https://www.mbbrowser.com");
            System.out.println("📄 当前页面标题: " + page.title());

            Thread.sleep(3000);
            System.out.println("✅ 脚本执行完毕!");

            browser.close();
        }
    }
}

关键代码解析

connectOverCDP vs launch ——最核心的区别

javascript
// ❌ 普通 Playwright 用法:新建一个空白的 Chrome 窗口
const browser = await chromium.launch();

// ✅ 候鸟 Playwright 用法:接管已有的指纹环境
const browser = await chromium.connectOverCDP(wsEndpoint);
对比普通 launch()候鸟 connectOverCDP()
浏览器状态全新空白,什么都没有已有完整指纹、代理、Cookie
执行后果目标网站看到裸机 Chrome目标网站看到"真实用户"
多账号管理无法区分按 Session_ID 精确对应

为什么取 data.ws 而不是 data.http

字段格式示例适用框架
data.http127.0.0.1:9222Selenium(debuggerAddress
data.wsws://127.0.0.1:9222/devtools/browser/xxxPlaywright / Puppeteer

Playwright 的 connectOverCDP 需要完整的 ws://... 地址。

browser.contexts()[0] ——不要创建新上下文

javascript
// ❌ 错误:创建全新上下文,候鸟的 Cookie 和存储会丢失
const context = await browser.newContext();

// ✅ 正确:取候鸟已有的上下文(保留所有账号状态)
const context = browser.contexts()[0];

常见问题排查

❓ 报错 Error: connect ECONNREFUSED 127.0.0.1:8186

ApiServer 没有启动,或端口不对。请确认 apiserver.exe 的终端窗口还在运行。

❓ 报错 Browser closedTarget page, context or browser has been closed

候鸟环境已被关闭(可能超时或手动关闭),需要重新调用 /api/v1/browser/start 开启。

browser.contexts() 返回空数组

候鸟环境刚打开时,默认 Context 可能需要短暂初始化,加个等待:

javascript
// 等待上下文出现(最多 5 秒)
let context;
for (let i = 0; i < 50 && !browser.contexts().length; i++) {
  await new Promise(r => setTimeout(r, 100));
}
context = browser.contexts()[0];

browser.close() 关闭了候鸟窗口?

connectOverCDP 模式下,browser.close() 只断开 Playwright 的连接,不会关闭候鸟的浏览器窗口。若需关闭,调用候鸟 ApiServer 的 stop 接口:

javascript
await axios.post(`${API_URL}/api/v1/browser/stop`, { Session_ID: SESSION_ID });

TIP

跑起来了?下一章 核心 API 通俗详解 教您用 Playwright 强大的 Locator、Page 等 API 完成各种页面操作。