# 处理 CAPTCHA 事件

### 基于事件的方法&#x20;

要监控 CAPTCHA 解决过程，我们建议使用基于事件的方法。它允许你的脚本监听来自扩展直接发送的自定义消息。

#### 工作原理

扩展向浏览器的 `window` 对象发送消息。你可以通过添加一个“message”事件监听器来捕获这些消息。

|                               |                     |
| ----------------------------- | ------------------- |
| `oxylabs-captcha-solve-start` | 检测到 CAPTCHA 并已开始解决。 |
| `oxylabs-captcha-solve-end`   | CAPTCHA 已成功解决。      |
| `oxylabs-captcha-solve-error` | 自动解决器未能绕过 CAPTCHA。  |

你可以订阅这些事件以暂停自动化，并仅在 CAPTCHA 成功处理后恢复。通常，CAPTCHA 解决需要最多 30 秒，取决于 CAPTCHA 的类型和复杂性，但在某些情况下可能需要更长时间，因此请为 CAPTCHA 解决留出足够时间。

#### 代码示例

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

```python
import sys
from playwright.sync_api import sync_playwright

# 配置
EXTENSION_NAME = 'oxylabs-runtime'
CAPTCHA_SOLVE_END = 'oxylabs-captcha-solve-end'
CAPTCHA_SOLVE_ERROR = 'oxylabs-captcha-solve-error'
UB_BROWSER_URL = 'wss://<username>:<password>@ubc.oxylabs.io'
CAPTCHA_CHECK_TIMEOUT_SEC = 60
TARGET_URL = 'https://www.indeed.com/cmp/Bank-of-the-West/reviews?lang=any&fcountry=ALL&sort=date'

def run():
    with sync_playwright() as p:
        print('正在打开浏览器页面...')
        # 使用 CDP 连接到远程浏览器
        browser = p.chromium.connect_over_cdp(UB_BROWSER_URL)
        
        # 获取默认上下文并创建新页面
        ctx = browser.contexts[0]
        page = ctx.new_page()

        # 这必须在导航之前完成。
        ctx.add_init_script(f"""
            window.addEventListener("message", (event) => {{
                if (event.data && event.data.source === "{EXTENSION_NAME}") {{
                    window.__extensionStatus = event.data.type;
                }}
            }});
        """)

        print('正在打开目标网站...')
        page.goto(TARGET_URL, wait_until='domcontentloaded')

        try:
            # 等待扩展状态变化
            page.wait_for_function(
                """
                ([solveEnd, solveError]) => {
                    const status = window.__extensionStatus;
                    if (status === solveError) {
                        throw new Error("CAPTCHA solving failed");
                    }
                    return status === solveEnd;
                }
                """,
                arg=[CAPTCHA_SOLVE_END, CAPTCHA_SOLVE_ERROR],
                timeout=CAPTCHA_CHECK_TIMEOUT_SEC * 1000
            )
            print('CAPTCHA 已成功解决，继续抓取...')
            
        except Exception as err:
            print(f'Error during CAPTCHA solve: {err}')
            browser.close()
            sys.exit(1)

        page.wait_for_selector('h1[data-testid="PageHeader-title-reviews"]')
        page.screenshot(path='page_screenshot.jpg')

        page.close()
        browser.close()
        print('完成。')

if __name__ == "__main__":
    run()
```

{% endtab %}

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

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

const 
    EXTENSION_NAME = 'oxylabs-runtime',
    CAPTCHA_SOLVE_END = 'oxylabs-captcha-solve-end',
    CAPTCHA_SOLVE_ERROR = 'oxylabs-captcha-solve-error',
    UB_BROWSER_URL = 'wss://<username>:<password>@ubc.oxylabs.io',
    CAPTCHA_CHECK_TIMEOUT_SEC = 60,
    TARGET_URL = 'https://www.indeed.com/cmp/Bank-of-the-West/reviews?lang=any&fcountry=ALL&sort=date';

(async () => {
    console.log('正在打开浏览器页面...');
    const browser = await chromium.connectOverCDP(UB_BROWSER_URL);
    const ctx = browser.contexts()[0];
    const page = await ctx.newPage();

    // 这必须在导航之前完成。
    await ctx.addInitScript((extensionName) => {
        window.addEventListener("message", (e) => {
            if (e.data?.source !== extensionName) return;
            window.__extensionStatus = e.data.type;
        });
    }, EXTENSION_NAME);

    console.log('正在打开目标网站...');
    await page.goto(TARGET_URL, { waitUntil: 'domcontentloaded' });

    try {
        await page.waitForFunction(
            ([solveEnd, solveError]) => {
                const status = window.__extensionStatus;
                if (status === solveError) {
                    throw new Error("CAPTCHA solving failed");
                }
                return status === solveEnd;
            },
            [CAPTCHA_SOLVE_END, CAPTCHA_SOLVE_ERROR],
            { timeout: CAPTCHA_CHECK_TIMEOUT_SEC * 1000 }
        );
        console.log('CAPTCHA 已成功解决，继续抓取...');
    } catch (err) {
        console.error('CAPTCHA 解决期间出错：', err.message);
        await browser.close();
        process.exit(1);
    }

    await page.waitForSelector('h1[data-testid="PageHeader-title-reviews"]');
    await page.screenshot({ path: 'page_screenshot.jpg' });

    await page.close();
    await browser.close();
    console.log('完成。');
})();

```

{% endtab %}

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

```javascript
const puppeteer = require('puppeteer');

const 
    EXTENSION_NAME = 'oxylabs-runtime', 
    CAPTCHA_SOLVE_END = 'oxylabs-captcha-solve-end',
    CAPTCHA_SOLVE_ERROR = 'oxylabs-captcha-solve-error',
    UB_BROWSER_URL = 'wss://<username>:<password>@ubc.oxylabs.io',
    CAPTCHA_CHECK_TIMEOUT_SEC = 60,
    TARGET_URL = 'https://www.indeed.com/cmp/Bank-of-the-West/reviews?lang=any&fcountry=ALL&sort=date';

(async () => {
    console.log('正在打开浏览器页面...');
    
    const browser = await puppeteer.connect({
        browserWSEndpoint: UB_BROWSER_URL,
    });
    const page = await browser.newPage();

    // 这必须在导航之前完成。
    await page.evaluateOnNewDocument((extensionName) => {
        window.addEventListener("message", (e) => {
            if (e.data?.source !== extensionName) return;
            window.__extensionStatus = e.data.type;
        });
    }, EXTENSION_NAME);

    console.log('正在打开目标网站...');
    await page.goto(TARGET_URL, { waitUntil: 'domcontentloaded' });

    try {
        await page.waitForFunction(
            (solveEnd, solveError) => {
                const status = window.__extensionStatus;
                if (status === solveError) {
                    throw new Error("CAPTCHA solving failed");
                }
                return status === solveEnd;
            },
            { timeout: CAPTCHA_CHECK_TIMEOUT_SEC * 1000 },
            CAPTCHA_SOLVE_END, 
            CAPTCHA_SOLVE_ERROR
        );
        console.log('CAPTCHA 已成功解决，继续抓取...');
    } catch (err) {
        console.error('CAPTCHA 解决期间出错：', err.message);
        await browser.close();
        process.exit(1);
    }

    await page.waitForSelector('h1[data-testid="PageHeader-title-reviews"]');
    await page.screenshot({ path: 'page_screenshot.jpg' });

    await page.close();
    await browser.disconnect();
    console.log('完成。');
})();

```

{% endtab %}
{% endtabs %}
