Tutorials

CAPTCHA trong phương thức bật lên: Phát hiện và chèn mã thông báo

Người dùng nhấp vào "Gửi" và một phương thức bật lên với thử thách CAPTCHA. Khóa trang web không có trong nguồn trang ban đầu — nó tải động khi phương thức mở. Tập lệnh tự động hóa của bạn cần kích hoạt phương thức, đợi CAPTCHA hiển thị, trích xuất tham số, giải quyết và đưa mã thông báo trước khi phương thức hết thời gian hoặc phiên người dùng hết hạn.

Các mẫu CAPTCHA phương thức

mẫu Trình kích hoạt Thử thách
Phương thức đăng nhập Nhấp vào nút "Đăng nhập" CAPTCHA tải bên trong lớp phủ div
Quảng cáo xen kẽ chống bot Tự động sau hành vi đáng ngờ Trang khối phương thức toàn màn hình
Xác nhận thanh toán Gửi hình thức thanh toán Phương thức xuất hiện để xác minh
Hộp thoại giới hạn tỷ lệ Đã phát hiện quá nhiều yêu cầu Phương thức có cổng CAPTCHA
Sự đồng ý của cookie + CAPTCHA Chuyến thăm đầu tiên CAPTCHA được nhúng trong hộp thoại đồng ý

Python: Trình xử lý CAPTCHA theo phương thức của nhà viết kịch

import requests
import time
from playwright.sync_api import sync_playwright

API_KEY = "YOUR_API_KEY"
SUBMIT_URL = "https://ocr.captchaai.com/in.php"
RESULT_URL = "https://ocr.captchaai.com/res.php"

def solve_captcha(sitekey, pageurl, method="userrecaptcha"):
    """Submit and poll a CAPTCHA."""
    params = {
        "key": API_KEY,
        "method": method,
        "json": 1,
    }
    if method == "userrecaptcha":
        params["googlekey"] = sitekey
        params["pageurl"] = pageurl
    elif method == "turnstile":
        params["sitekey"] = sitekey
        params["pageurl"] = pageurl

    resp = requests.post(SUBMIT_URL, data=params, timeout=30).json()
    if resp.get("status") != 1:
        raise RuntimeError(f"Submit failed: {resp.get('request')}")

    task_id = resp["request"]
    for _ in range(60):
        time.sleep(5)
        poll = requests.get(RESULT_URL, params={
            "key": API_KEY, "action": "get",
            "id": task_id, "json": 1,
        }, timeout=15).json()

        if poll.get("request") == "CAPCHA_NOT_READY":
            continue
        if poll.get("status") == 1:
            return poll["request"]
        raise RuntimeError(f"Solve failed: {poll.get('request')}")

    raise RuntimeError("Timeout")

def detect_modal_captcha(page):
    """
    Detect CAPTCHA inside a visible modal/dialog.
    Returns (sitekey, method) or (None, None).
    """
    return page.evaluate("""
        () => {
            // Find visible modals
            const modalSelectors = [
                '.modal.show',
                '.modal[style*="display: block"]',
                'dialog[open]',
                '[role="dialog"]:not([aria-hidden="true"])',
                '.overlay.visible',
                '.popup.active',
                '[class*="modal"][class*="open"]',
            ];

            let modal = null;
            for (const sel of modalSelectors) {
                const el = document.querySelector(sel);
                if (el && el.offsetParent !== null) {
                    modal = el;
                    break;
                }
            }

            // If no modal found, search entire document
            const searchRoot = modal || document;

            // Check for reCAPTCHA
            const recaptcha = searchRoot.querySelector('.g-recaptcha[data-sitekey]');
            if (recaptcha) {
                return { sitekey: recaptcha.dataset.sitekey, method: 'userrecaptcha' };
            }

            // Check for Turnstile
            const turnstile = searchRoot.querySelector('.cf-turnstile[data-sitekey]');
            if (turnstile) {
                return { sitekey: turnstile.dataset.sitekey, method: 'turnstile' };
            }

            // Check for hCaptcha
            const hcaptcha = searchRoot.querySelector('.h-captcha[data-sitekey]');
            if (hcaptcha) {
                return { sitekey: hcaptcha.dataset.sitekey, method: 'hcaptcha' };
            }

            return null;
        }
    """)

def inject_token_in_modal(page, token, method="userrecaptcha"):
    """Inject token into the CAPTCHA inside the modal."""
    if method == "userrecaptcha":
        page.evaluate("""
            (token) => {
                // Find response textarea (may be inside modal)
                const textareas = document.querySelectorAll('#g-recaptcha-response, [name="g-recaptcha-response"]');
                textareas.forEach(ta => {
                    ta.value = token;
                    ta.style.display = 'block';
                });

                // Trigger callback
                if (typeof ___grecaptcha_cfg !== 'undefined') {
                    Object.values(___grecaptcha_cfg.clients).forEach(client => {
                        Object.values(client).forEach(val => {
                            if (val && typeof val === 'object') {
                                Object.values(val).forEach(v => {
                                    if (v && typeof v.callback === 'function') v.callback(token);
                                });
                            }
                        });
                    });
                }
            }
        """, token)
    elif method == "turnstile":
        page.evaluate("""
            (token) => {
                const inputs = document.querySelectorAll('[name="cf-turnstile-response"]');
                inputs.forEach(inp => { inp.value = token; });

                if (typeof window.turnstileCallback === 'function') {
                    window.turnstileCallback(token);
                }
            }
        """, token)

def handle_modal_captcha(page, trigger_selector=None, timeout=10000):
    """
    Full workflow: trigger modal, detect CAPTCHA, solve, inject.
    """
    # Step 1: Trigger the modal if needed
    if trigger_selector:
        print(f"Clicking trigger: {trigger_selector}")
        page.click(trigger_selector)

    # Step 2: Wait for modal to become visible
    print("Waiting for modal...")
    modal_selectors = [
        ".modal.show",
        "dialog[open]",
        '[role="dialog"]:not([aria-hidden="true"])',
        ".popup.active",
    ]

    modal_visible = False
    for selector in modal_selectors:
        try:
            page.wait_for_selector(selector, timeout=timeout)
            modal_visible = True
            print(f"  Modal detected: {selector}")
            break
        except Exception:
            continue

    if not modal_visible:
        print("  No modal detected")
        return None

    # Step 3: Wait for CAPTCHA to render inside modal
    time.sleep(2)  # Brief pause for dynamic CAPTCHA loading

    captcha_info = detect_modal_captcha(page)
    if not captcha_info:
        print("  No CAPTCHA found in modal")
        return None

    sitekey = captcha_info["sitekey"]
    method = captcha_info["method"]
    print(f"  Found {method} CAPTCHA: {sitekey[:20]}...")

    # Step 4: Solve via CaptchaAI
    token = solve_captcha(sitekey, page.url, method)
    print(f"  Solved: {token[:30]}...")

    # Step 5: Inject token
    inject_token_in_modal(page, token, method)
    print("  Token injected")

    return token

def main():
    with sync_playwright() as p:
        browser = p.chromium.launch(headless=False)
        page = browser.new_page()
        page.goto("https://example.com")
        page.wait_for_load_state("networkidle")

        # Handle CAPTCHA that appears in login modal
        token = handle_modal_captcha(
            page,
            trigger_selector="button#login-btn",
            timeout=10000,
        )

        if token:
            # Fill form fields inside modal
            page.fill('dialog input[name="email"]', "user@example.com")
            page.fill('dialog input[name="password"]', "password123")

            # Submit modal form
            page.click('dialog button[type="submit"]')
            page.wait_for_load_state("networkidle")

        browser.close()

main()

JavaScript: Trình xử lý phương thức Puppeteer

const puppeteer = require("puppeteer");

const API_KEY = "YOUR_API_KEY";
const SUBMIT_URL = "https://ocr.captchaai.com/in.php";
const RESULT_URL = "https://ocr.captchaai.com/res.php";

async function solveCaptcha(sitekey, pageurl, method = "userrecaptcha") {
  const body = new URLSearchParams({ key: API_KEY, method, json: "1" });
  if (method === "userrecaptcha") { body.set("googlekey", sitekey); body.set("pageurl", pageurl); }
  else if (method === "turnstile") { body.set("sitekey", sitekey); body.set("pageurl", pageurl); }

  const resp = await (await fetch(SUBMIT_URL, { method: "POST", body })).json();
  if (resp.status !== 1) throw new Error(`Submit: ${resp.request}`);

  const taskId = resp.request;
  for (let i = 0; i < 60; i++) {
    await new Promise((r) => setTimeout(r, 5000));
    const url = `${RESULT_URL}?key=${API_KEY}&action=get&id=${taskId}&json=1`;
    const poll = await (await fetch(url)).json();
    if (poll.request === "CAPCHA_NOT_READY") continue;
    if (poll.status === 1) return poll.request;
    throw new Error(`Solve: ${poll.request}`);
  }
  throw new Error("Timeout");
}

async function waitForModal(page, timeout = 10000) {
  const selectors = [".modal.show", "dialog[open]", '[role="dialog"]', ".popup.active"];
  for (const sel of selectors) {
    try {
      await page.waitForSelector(sel, { visible: true, timeout });
      return sel;
    } catch {}
  }
  return null;
}

async function detectModalCaptcha(page) {
  return page.evaluate(() => {
    const checks = [
      { sel: ".g-recaptcha[data-sitekey]", method: "userrecaptcha" },
      { sel: ".cf-turnstile[data-sitekey]", method: "turnstile" },
    ];
    for (const { sel, method } of checks) {
      const el = document.querySelector(sel);
      if (el && el.dataset.sitekey) return { sitekey: el.dataset.sitekey, method };
    }
    return null;
  });
}

async function handleModalCaptcha(page, triggerSelector) {
  // Trigger modal
  if (triggerSelector) await page.click(triggerSelector);

  // Wait for modal
  const modalSel = await waitForModal(page);
  if (!modalSel) { console.log("No modal found"); return null; }
  console.log(`Modal visible: ${modalSel}`);

  // Wait for CAPTCHA render
  await new Promise((r) => setTimeout(r, 2000));

  const info = await detectModalCaptcha(page);
  if (!info) { console.log("No CAPTCHA in modal"); return null; }

  console.log(`Found ${info.method}: ${info.sitekey.substring(0, 20)}...`);
  const token = await solveCaptcha(info.sitekey, page.url(), info.method);
  console.log(`Solved: ${token.substring(0, 30)}...`);

  // Inject token
  await page.evaluate((t, method) => {
    if (method === "userrecaptcha") {
      document.querySelectorAll("#g-recaptcha-response").forEach((el) => { el.value = t; });
    } else if (method === "turnstile") {
      document.querySelectorAll('[name="cf-turnstile-response"]').forEach((el) => { el.value = t; });
    }
  }, token, info.method);

  return token;
}

(async () => {
  const browser = await puppeteer.launch({ headless: false });
  const page = await browser.newPage();
  await page.goto("https://example.com", { waitUntil: "networkidle2" });

  const token = await handleModalCaptcha(page, "button#login-btn");
  if (token) {
    await page.type('dialog input[name="email"]', "user@example.com");
    await page.click('dialog button[type="submit"]');
    await page.waitForNavigation();
  }

  await browser.close();
})();

Cân nhắc về thời gian theo phương thức

Yếu tố tác động Giảm nhẹ
Thời gian chờ tự động đóng phương thức Phương thức có thể đóng trước khi giải quyết xong Bắt đầu giải quyết ngay khi phát hiện
Phiên hết hạn trong khi giải quyết Phiên máy chủ hết hạn trong chế độ chờ Giữ phiên hoạt động với nhịp tim nền
Độ trễ kết xuất CAPTCHA ở chế độ Widget mất 1–3 giây để tải ở chế độ Đợi 2 giây sau khi phương thức hiển thị trước khi giải nén sitekey
Mã thông báo hết hạn trong khi điền biểu mẫu Mã thông báo hết hạn trong khi điền vào biểu mẫu phương thức Giải CAPTCHA cuối cùng, sau khi điền các trường khác

Khắc phục sự cố

Vấn đề Nguyên nhân Cách xử lý
Đã phát hiện thấy phương thức nhưng không tìm thấy CAPTCHA CAPTCHA tải không đồng bộ sau khi mở phương thức Tăng thời gian chờ đợi; sử dụng MutationObserver để phát hiện việc chèn tiện ích
Mã thông báo đã được chèn nhưng phương thức không đóng Chức năng gọi lại không được kích hoạt Tìm và gọi lệnh gọi lại CAPTCHA một cách rõ ràng
Phương thức đóng trong khi giải quyết Tự động loại bỏ thời gian chờ Vô hiệu hóa thời gian chờ phương thức thông qua JS: clearTimeout() trên bộ hẹn giờ phương thức
Mã trang web CAPTCHA khác nhau mỗi lần Phương thức tạo phiên bản CAPTCHA động Luôn trích xuất khóa trang web mới từ DOM phương thức, không bao giờ lưu vào bộ đệm
Trình kích hoạt nhấp chuột không mở chế độ Phần tử không tương tác hoặc ở phía sau lớp phủ Sử dụng page.dispatchEvent hoặc đợi phần tử có thể nhấp được

Câu hỏi thường gặp

Làm cách nào để phát hiện một phương thức tự động mở mà không cần trình kích hoạt nhấp chuột?

Sử dụng MutationObserver để theo dõi các phần tử mới xuất hiện trong DOM. Thiết lập nó trước khi điều hướng đến trang. Khi một phần tử phương thức được thêm vào và hiển thị, trình quan sát của bạn sẽ kích hoạt và bạn có thể bắt đầu luồng phát hiện CAPTCHA.

Điều gì sẽ xảy ra nếu CAPTCHA nằm trong iframe phương thức?

Nếu phương thức chứa iframe có CAPTCHA, hãy kết hợp phương pháp này với xử lý iframe. Sau khi phát hiện phương thức, hãy chuyển sang ngữ cảnh iframe bên trong phương thức để trích xuất khóa trang.

Tôi nên điền vào các trường biểu mẫu trước hay sau khi giải CAPTCHA?

Trước. Điền vào tất cả các trường biểu mẫu khác trước, sau đó giải CAPTCHA cuối cùng. Điều này giảm thiểu thời gian giữa việc nhận mã thông báo và gửi biểu mẫu, giảm rủi ro hết hạn.

bài viết liên quan

Các bước tiếp theo

Xử lý CAPTCHA trong các chế độ bật lên một cách liền mạch —lấy khóa API CaptchaAI của bạnvà thực hiện phát hiện phương thức.

Hướng dẫn liên quan:

  • Xử lý nhiều CAPTCHA trên một trang
  • Xử lý Shadow DOM CAPTCHA
  • Trích xuất CAPTCHA iframe: Khung lồng nhau
Os comentários estão desativados para este artigo.

Postagens relacionadas

Reference Tính bền vững phiên trình duyệt cho luồng QA CAPTCHA của bạn
Duy trì phiên trình duyệt qua nhiều bước trong kiểm thử QA CAPTCHA trên staging của bạn để giảm gián đoạn và tăng độ tái lập.

Duy trì phiên trình duyệt qua nhiều bước trong kiểm thử QA CAPTCHA trên staging của bạn để giảm gián đoạn và t...

Apr 30, 2026
Integrations Tách biệt hồ sơ trình duyệt cho QA với CaptchaAI
Tách cookie, storage, tài khoản kiểm thử và cấu hình CAPTCHA theo từng hồ sơ trình duyệt để giữ cho kiểm thử QA trong staging sạch và có thể tái lập.

Tách cookie, storage, tài khoản kiểm thử và cấu hình CAPTCHA theo từng hồ sơ trình duyệt để giữ cho kiểm thử Q...

Apr 29, 2026