> For the complete documentation index, see [llms.txt](https://developers.oxylabs.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://developers.oxylabs.io/products/cn/headless-browser.md).

# 无头浏览器

无头浏览器让你无需在本地管理远程实例，即可运行和控制用于基于浏览器的自动化、测试和网页抓取。它内置自适应安全、自动 CAPTCHA 处理、地理定位、集成住宅代理、会话录制、粘性会话和持久配置文件。

## 支持的库

无头浏览器可与任何支持以下内容的库配合使用 **Chrome DevTools Protocol (CDP)**，包括：

* [Playwright](https://playwright.dev/) （Python 和 Node.js）
* [Puppeteer](https://pptr.dev/) （Node.js）
* 其他兼容 CDP 的自动化框架

## 连接详情

<table data-header-hidden><thead><tr><th width="160.5">字段</th><th>说明</th></tr></thead><tbody><tr><td><strong>协议</strong></td><td><code>wss://</code> （WebSocket Secure）</td></tr><tr><td><strong>主机（Chromium）</strong></td><td><code>ubc.oxylabs.io</code></td></tr><tr><td><strong>身份验证</strong></td><td>在 URL 中，用户信息 – <code>wss://USERNAME:PASSWORD@host</code>。必须包含用户名后缀 token（例如 <code>user_ab12</code>）。不支持基于标头的身份验证。</td></tr><tr><td><strong>传输</strong></td><td>CDP – <code>chromium.connectOverCDP</code> （Playwright） / <code>puppeteer.connect</code> （Puppeteer）</td></tr><tr><td><strong>域</strong></td><td><code>oxylabs.io</code> – 你进行身份验证并连接的端点（例如 <a href="http://ubc.oxylabs.io">ubc.oxylabs.io</a>)<br><code>headlesify.io</code> – 仪表板、会话检查和录制（例如 <a href="http://dashboard.headlesify.io">dashboard.headlesify.io</a>, <a href="http://vnc.headlesify.io">vnc.headlesify.io</a>).</td></tr><tr><td><strong>速率限制</strong></td><td><code>100</code> 并发会话， <code>10</code> 每秒会话。 <a href="#need-a-feature-enabled-1">查看更多</a>.</td></tr></tbody></table>

## 功能

Oxylabs 无头浏览器包含内置的云原生功能，旨在通过追加到 WebSocket 连接 URL 的查询参数使用。

<table data-header-hidden><thead><tr><th width="250"></th><th></th></tr></thead><tbody><tr><td><a href="/pages/7cd3e76278f749033b5b53e82e25d8f104f638ca"><strong>CAPTCHA 处理</strong></a> </td><td>自动、实时的 CAPTCHA 处理和监控。</td></tr><tr><td><a href="/pages/536317ffb843e3f19eb234523b280d19b934d8c5"><strong>代理和地理定位目标设置</strong></a></td><td>通过特定国家、州或城市路由会话。</td></tr><tr><td><a href="/pages/e8fd844ab77dcab9d97c682f939503978bf0c87f"><strong>设备模拟</strong></a></td><td>模拟特定设备指纹和视口。</td></tr><tr><td><a href="/pages/d9884d46cf2dca96508b8863f40b1954a6551a02#session-inspection-vnc"><strong>会话检查（VNC）</strong></a></td><td>监控实时无头浏览器会话。</td></tr><tr><td><a href="/pages/d9884d46cf2dca96508b8863f40b1954a6551a02#session-recording"><strong>会话录制</strong></a> </td><td>以视频格式录制浏览器会话。</td></tr><tr><td><a href="/pages/91c5a7510ae7c5390998d7b58ec7538cccb6b5cc#persistent-sessions"><strong>持久会话</strong></a></td><td>创建和管理粘性浏览器实例。</td></tr><tr><td><a href="/pages/91c5a7510ae7c5390998d7b58ec7538cccb6b5cc#persistent-profiles"><strong>持久配置文件</strong></a></td><td>跨会话保存和恢复 Cookie/localStorage。 <em>(</em><a href="#need-a-feature-enabled-1"><em>需要激活</em></a><em>)</em></td></tr></tbody></table>

### 传递参数

所有功能都通过将查询参数直接追加到你的 WebSocket Secure 端点，并使用和号（`&`).

```bash
# Example: Connecting to Chrome with US Geolocation, CAPTCHA handling, and Live VNC Stream
wss://USER:PASS@ubc.oxylabs.io?p_cc=US&solve_captcha=true&o_vnc=true
```

## 代码示例

以下是初始化云托管浏览器会话的基本示例：

{% tabs %}
{% tab title="Python（Playwright）" %}

```python
from playwright.sync_api import sync_playwright

username = "USERNAME" # include any account suffix
password = "PASSWORD"
endpoint = "ubc.oxylabs.io"
browser_url = f"wss://{username}:{password}@{endpoint}?p_cc=US"

with sync_playwright() as p:
    browser = p.chromium.connect_over_cdp(browser_url)
    page = browser.new_page()
    page.goto("https://ip.oxylabs.io/location")
    print(page.title())
    browser.close()
```

{% endtab %}

{% tab title="JavaScript（Playwright）" %}

```javascript
process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0"; //For testing only
import { chromium } from "playwright";

const username = "USERNAME";
const password = "PASSWORD";
const endpoint = "ubc.oxylabs.io";
const browserUrl = `wss://${username}:${password}@${endpoint}?p_cc=US`;

(async () => {
    const browser = await chromium.connectOverCDP(browserUrl);
    const ctx = browser.contexts()[0] || (await browser.newContext());
    const page = ctx.pages()[0] || (await ctx.newPage());
    await page.goto("https://ip.oxylabs.io/location");
    console.log(await page.title());
    await browser.close();
})();
```

{% endtab %}

{% tab title="JavaScript（Puppeteer）" %}

```javascript
process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0"; //For testing only
import puppeteer from "puppeteer";

const username = "USERNAME";
const password = "PASSWORD";
const endpoint = "ubc.oxylabs.io";
const browserUrl = `wss://${username}:${password}@${endpoint}?p_cc=US`;

(async () => {
    const browser = await puppeteer.connect({ browserWSEndpoint: browserUrl });
    const page = await browser.newPage();
    await page.goto("https://ip.oxylabs.io/location");
    console.log(await page.title());
    await browser.close();
})();
```

{% endtab %}
{% endtabs %}

{% hint style="info" %}
**注意：** 示例使用 `USERNAME` 和 `PASSWORD` 仅为可读性而使用。实际项目中，请从环境变量中加载它们（例如 `process.env.OXYLABS_USERNAME` / `process.env.OXYLABS_PASSWORD`）通过一个 `.env` 文件。
{% endhint %}

{% hint style="warning" %}
**JavaScript：** 如果遇到 TLS/证书错误，在 Node.js 中 require Playwright 之前先使用 `NODE_TLS_REJECT_UNAUTHORIZED="0"` 标志。仅用于本地测试。在生产环境中，应将信任范围限定到特定连接，或改为将提供商的 CA 证书添加到你的信任存储中。
{% endhint %}

## 参数参考 <a href="#need-a-feature-enabled" id="need-a-feature-enabled"></a>

<table><thead><tr><th width="200">参数</th><th width="431.5">说明</th><th>类型</th></tr></thead><tbody><tr><td><code>p_cc</code></td><td>ISO 3166-1 alpha-2 中的国家地理定位 <code>2 位字母代码（例如</code> US <code>US</code>, <code>DE</code>).</td><td>字符串</td></tr><tr><td><code>p_state</code></td><td>州地理定位，小写（例如 <code>texas</code>）。如果同时使用， <code>p_cc</code> 会覆盖 <a href="https://content.gitbook.com/content/BQ7Zf9paoN3FTeGcyfY1/blobs/cVjpiu1GKicluiVIT9og/us_states.txt">支持的州列表</a>.</td><td>字符串</td></tr><tr><td><code>p_city</code></td><td>城市地理定位，小写， <code>_</code> 用于空格（例如 <code>new_york</code>). <code>p_cc</code> / <code>p_state</code> 必填。</td><td>字符串</td></tr><tr><td><code>p_device</code></td><td>设置设备指纹、视口和用户代理。支持 <code>桌面</code> （默认）和 <code>移动</code>.</td><td>字符串</td></tr><tr><td><code>solve_captcha</code></td><td>在页面加载时自动、实时地解决 CAPTCHA。默认： <code>true</code>.</td><td>布尔值</td></tr><tr><td><code>record</code></td><td>录制无头会话视频。默认： <code>false</code>.</td><td>布尔值</td></tr><tr><td><code>record_name</code></td><td>为录制命名，便于查找（<code>^[a-zA-Z0-9_-]{1,64}$</code>).</td><td>字符串</td></tr><tr><td><code>session_name</code></td><td>粘性会话 – 重新连接到同一个实时远程浏览器（<code>^[A-Za-z0-9-]{3,36}$</code>，支持连字符，不支持下划线）。最长 TTL – 24 小时。</td><td>字符串</td></tr><tr><td><code>keep_alive</code></td><td>设置为 <code>false</code>时，在客户端断开连接时关闭远程浏览器实例。默认： <code>true</code>.</td><td>布尔值</td></tr><tr><td><mark style="background-color:yellow;"><code>o_profile</code></mark></td><td>持久配置文件 – 使用命名配置文件保存/恢复 Cookie 和 <code>localStorage</code> （<code>^[A-Za-z0-9_-]{1,36}$</code>).</td><td>字符串</td></tr><tr><td><mark style="background-color:yellow;"><code>o_profile_save</code></mark></td><td>持久配置文件 – 强制在会话中途保存配置文件。默认： <code>true</code>.</td><td>布尔值</td></tr><tr><td><code>proxy_resi_ses_id</code></td><td>用于在多个会话中固定住宅代理出口 IP 的自定义会话 ID（<code>^[A-Za-z0-9]{3,36}$</code>).</td><td>字符串</td></tr><tr><td><code>proxy_resi_ses_time</code></td><td>保持固定的住宅代理出口 IP 的时长，单位为分钟。最小 <code>1</code>，最大 <code>1440</code> （24 小时）。</td><td>整数</td></tr></tbody></table>

&#x20;    – 在你的账户手动激活后可用。 [了解更多](#need-a-feature-enabled-1).

## 推荐设置

### 优化流量

抓取动态页面时，浏览器通常会下载不必要的资源，例如大型媒体、跟踪脚本、图像和字体。这会消耗带宽并减慢执行时间。

你可以在这些请求消耗资源之前，通过程序拦截并中止它们：

{% tabs %}
{% tab title="Python（Playwright）" %}

```python
# Abort heavy assets to save bandwidth and improve speeds
def block_resources(route):
    if route.request.resource_type in ["image", "stylesheet", "media", "font"]:
        route.abort()
    else:
        route.continue_()

page.route("**/*", block_resources)
```

{% endtab %}

{% tab title="JavaScript（Playwright）" %}

```javascript
// Abort heavy assets to save bandwidth and improve speeds
await page.route("**/*", (route) => {
    const type = route.request().resourceType();
    if (["image", "stylesheet", "media", "font"].includes(type)) {
        return route.abort();
    }
    return route.continue();
});
```

{% endtab %}
{% endtabs %}

### 错误处理和重试 <a href="#error-handling-and-retries" id="error-handling-and-retries"></a>

网络波动和每秒 10 个会话的速率限制意味着单个 `connectOverCDP` 调用可能会暂时失败。请将连接包装在 `重试` 中，并使用指数 `退避`，同时为每次尝试设置超时。下面的示例使用标准 Playwright API：

```javascript
const { chromium } = require("playwright");

const MAX_RETRIES = 5;
const BASE_DELAY_MS = 1000;

async function connectWithRetry(endpoint, { maxRetries = MAX_RETRIES } = {}) {
    let lastError;
    for (let attempt = 0; attempt < maxRetries; attempt++) {
        try {
            // Cap how long a single connection attempt may take.
            return await chromium.connectOverCDP(endpoint, { timeout: 60_000 });
        } catch (err) {
            lastError = err;
            // Exponential backoff with jitter — backs off when you hit the
            // 10-new-sessions/second rate limit instead of hammering the endpoint.
            const delay = BASE_DELAY_MS * 2 ** attempt + Math.random() * 250;
            console.warn(
                `connect attempt ${attempt + 1} failed: ${err.message}; ` +
                `retrying in ${Math.round(delay)}ms`
            );
            await new Promise((resolve) => setTimeout(resolve, delay));
        }
    }
    throw lastError;
}
```

### 资源清理 <a href="#resource-cleanup" id="resource-cleanup"></a>

始终在完成后关闭浏览器，即使自动化在中途抛出异常。使用 `try { ... } finally { ... }` 块，以便清理在每条路径上都执行：

```javascript
const browser = await connectWithRetry(endpoint);
try {
    const ctx = browser.contexts()[0] || (await browser.newContext());
    const page = ctx.pages()[0] || (await ctx.newPage());
    await page.goto("https://ip.oxylabs.io/location");
    // ... your automation ...
} finally {
    // Runs even if the block above throws. Without this, a session left open
    // after an exception lingers and counts against your 100 concurrent-session limit.
    await browser.close();
}
```

如果在 connect 和 close 之间发生异常且你未清理，远程会话将保持打开，并占用你的一个 **100 个并发会话** ，直到被回收。在高负载下泄漏会话会耗尽配额并阻止新的连接。

## 需要启用某项功能？ <a href="#need-a-feature-enabled" id="need-a-feature-enabled"></a>

某些无头浏览器功能默认关闭或受限。要访问它们，请联系 Oxylabs 支持（[在线聊天](https://oxylabs.io/) 或 [电子邮件](mailto:support@oxylabs.io)）或你的专属客户经理：

* **持久配置文件** – 获取该功能和 `o_profile` 参数的访问权限。
* **更多配置文件** – 提高账户的 `max_profiles` 持久配置文件上限。
* **受限目标** – 通过 KYC 流程解锁更多目标类别。
* **更高的速率限制** – 提高到超过 100 个并发会话 / 每秒 10 个。


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://developers.oxylabs.io/products/cn/headless-browser.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
