> 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 管理和住宅代理。可通过代码示例测试，并使用高级功能自定义。

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

## 支持的库

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

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

## 连接详情

{% hint style="warning" %}
**注意：** 无头浏览器正在迁移到新基础设施。请将连接字符串从 `ubc.oxylabs.io` 更新为 `hb.oxylabs.io` 在 **10月1日**之前。自 10月1日 起，发送到旧域名的流量将自动路由到新域名。&#x20;

Dashboard 和会话检查工具也已从 `headlesify.io` 迁移到 `hb.oxylabs.io`。请参阅 [会话检查与录制](/products/cn/headless-browser/session-inspection-and-recording.md) 了解详情。
{% endhint %}

<table><thead><tr><th width="161">字段</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>hb.oxylabs.io</code></td></tr><tr><td><strong>认证</strong></td><td>在 URL 中，用户信息—— <code>wss://USERNAME:PASSWORD@host</code>。必须包含用户名后缀 token（例如 <code>user_ab12</code>）。不支持基于 header 的认证。</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://hb.oxylabs.io">hb.oxylabs.io</a>）、Dashboard（<a href="http://hb.oxylabs.io/dashboard">hb.oxylabs.io/dashboard</a>）、以及会话检查（<a href="http://hb.oxylabs.io/novnc">hb.oxylabs.io/novnc</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="/products/cn/headless-browser/captcha-handling.md"><strong>CAPTCHA 处理</strong></a></td><td>自动实时 CAPTCHA 处理和监控（默认：关闭）。</td></tr><tr><td><a href="/products/cn/headless-browser/geolocation-and-proxy-selection.md"><strong>代理与地理位置定位</strong></a></td><td>将会话路由到特定国家、州或城市。</td></tr><tr><td><a href="/products/cn/headless-browser/device-type.md"><strong>设备模拟</strong></a></td><td>模拟特定设备的指纹和视口。</td></tr><tr><td><a href="/products/cn/headless-browser/session-inspection-and-recording.md#session-inspection-vnc"><strong>会话检查（VNC）</strong></a></td><td>监控实时无头浏览器会话。</td></tr><tr><td><a href="/products/cn/headless-browser/session-inspection-and-recording.md#session-recording"><strong>会话录制</strong></a></td><td>以视频格式录制浏览器会话。</td></tr><tr><td><a href="/products/cn/headless-browser/persistent-sessions-and-profiles.md#persistent-sessions"><strong>持久会话</strong></a></td><td>创建并管理粘性浏览器实例。</td></tr><tr><td><a href="/products/cn/headless-browser/persistent-sessions-and-profiles.md#persistent-profiles"><strong>持久配置文件</strong></a></td><td>在会话之间保存和恢复 Cookie/localStorage。</td></tr></tbody></table>

### 参数传递

所有功能都通过在 WebSocket Secure 端点后直接追加查询参数来启用和配置，并使用和号（`&`).

```bash
# 示例：连接到启用美国地理位置定位和 CAPTCHA 处理的 Chrome
wss://USER:PASS@hb.oxylabs.io?p_cc=US&solve_captcha=true
```

## 代码示例

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

{% tabs %}
{% tab title="Python (Playwrigth)" %}

```python
from playwright.sync_api import sync_playwright

username = "USERNAME" # include any account suffix
password = "PASSWORD"
endpoint = "hb.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 = "hb.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 = "hb.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>国家地理定位，采用 <code>ISO 3166-1 alpha-2</code> 2 位字母代码（例如 <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>false</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>true</code>。默认： <code>false</code>.</td><td>布尔值</td></tr><tr><td><code>o_profile</code></td><td>持久化配置文件——保存/恢复 Cookie 和 <code>localStorage</code> 使用命名配置文件（<code>^[A-Za-z0-9_-]{1,36}$</code>).</td><td>字符串</td></tr><tr><td><code>o_profile_save</code></td><td>持久化配置文件——在会话期间或结束时强制保存配置文件。默认： <code>false</code>.</td><td>布尔值</td></tr><tr><td><code>proxy_resi_ses_id</code></td><td>自定义会话 ID，用于在多个会话间固定住宅出口 IP（<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>

## 推荐配置

### 优化流量

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

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

{% 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 concurrent sessions** 之一，直到它被回收。在高负载下泄漏会话会耗尽限制并阻止新的连接。

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

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

* **更多持久化配置文件** – 提高您账户默认的 5 个已保存配置文件上限。
* **更多持久化会话** – 提高您账户默认的 5 个并发持久化会话上限。
* **受限目标** – 通过 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.
