Trường Hợp Sử Dụng

Tự động xử lý Bot CAPTCHA bằng CaptchaAI

Bot chạy tốt cho đến khi gặp một trang có CAPTCHA — request bỗng trả về mã lỗi hoặc treo vô thời hạn thay vì hoàn tất tác vụ. Cách xử lý là gắn một bước giải CAPTCHA vào đúng chỗ trong luồng: gửi task tới CaptchaAI, chờ token, điền vào form, gửi tiếp — không cần con người can thiệp.

Nhiều đội automation ở các công ty outsourcing tại TP.HCM và Hà Nội vận hành hàng chục bot song song cho khách hàng nước ngoài — regression test, đăng ký tài khoản thử nghiệm, đồng bộ dữ liệu giữa các hệ thống. Càng nhiều bot chạy song song, tần suất gặp CAPTCHA càng cao, nên framework bot cần xử lý CAPTCHA như một bước bình thường trong luồng, không phải một ngoại lệ vá tạm mỗi khi bot bị kẹt.

Luồng xử lý gồm bốn bước lặp lại trong mọi ví dụ ở bài này:

  • Bot phát hiện trang cần CAPTCHA và gửi task tới CaptchaAI (in.php)
  • CaptchaAI trả về một task_id
  • Bot polling res.php cho đến khi có token
  • Bot gắn token vào form/request rồi gửi tiếp như bình thường

Toàn bộ ví dụ dùng domain demo (example.com, portal.example.com) — khi áp dụng vào hệ thống thật, chỉ chạy trên các luồng bạn có quyền tự động hóa (form của chính bạn, hệ thống nội bộ, hoặc môi trường QA/staging).

CAPTCHA xuất hiện ở đâu trong bot tự động hóa

Bốn nhóm tác vụ dưới đây là nơi bot automation gặp CAPTCHA thường xuyên nhất, cùng phương thức CaptchaAI tương ứng:

Tác vụ của bot CAPTCHA điển hình Phương pháp CaptchaAI
Gửi biểu mẫu (liên hệ, đăng ký nhận tin) reCAPTCHA v2 method=userrecaptcha
Tạo tài khoản hàng loạt cho test reCAPTCHA v2/v3 method=userrecaptcha
Nhập liệu vào cổng nội bộ CAPTCHA hình ảnh method=base64
Đặt lịch/đặt chỗ tự động Cloudflare Turnstile method=turnstile
Gọi API qua cổng có bảo vệ Cloudflare Challenge method=cloudflare_challenge

Mỗi hàng ứng với một method khác nhau trong cùng một API — bot chỉ cần nhận diện loại CAPTCHA trên trang rồi gọi đúng phương thức, không phải viết logic riêng cho từng trang.

Framework bot tái sử dụng cho nhiều loại CAPTCHA

Thay vì viết lại logic giải CAPTCHA trong mỗi bot, gói nó vào một class dùng chung. Class CaptchaBot dưới đây làm ba việc:

  1. Gửi task tới in.php với method tương ứng loại CAPTCHA
  2. Polling res.php mỗi 5 giây cho đến khi có token (hoặc timeout sau 5 phút)
  3. Gắn token vào form_data và tự submit form qua requests.Session
import requests
import time
import logging

logger = logging.getLogger(__name__)

class CaptchaBot:
    def __init__(self, api_key):
        self.api_key = api_key
        self.session = requests.Session()
        self.session.headers.update({
            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
        })

    def solve(self, method, **params):
        """Solve any CAPTCHA type."""
        params["key"] = self.api_key
        params["method"] = method

        resp = requests.get("https://ocr.captchaai.com/in.php", params=params)
        if not resp.text.startswith("OK|"):
            raise Exception(f"Submit error: {resp.text}")

        task_id = resp.text.split("|")[1]
        logger.info(f"Task submitted: {task_id}")

        for _ in range(60):
            time.sleep(5)
            result = requests.get("https://ocr.captchaai.com/res.php", params={
                "key": self.api_key, "action": "get", "id": task_id
            })
            if result.text == "CAPCHA_NOT_READY": continue
            if result.text.startswith("OK|"): return result.text.split("|")[1]
            raise Exception(f"Error: {result.text}")

        raise TimeoutError("CAPTCHA solve timed out")

    def submit_form(self, url, form_data, captcha_field="g-recaptcha-response",
                    site_key=None, captcha_method="userrecaptcha"):
        """Submit a form with CAPTCHA solving."""
        if site_key:
            if captcha_method == "userrecaptcha":
                token = self.solve(captcha_method, googlekey=site_key, pageurl=url)
            elif captcha_method == "turnstile":
                token = self.solve(captcha_method, sitekey=site_key, pageurl=url)
            form_data[captcha_field] = token

        return self.session.post(url, data=form_data)

Ví dụ 1: bot gửi biểu mẫu liên hệ

Trường hợp đơn giản nhất — một form liên hệ được bảo vệ bằng reCAPTCHA. submit_form() tự lấy token rồi POST form trong một lệnh gọi:

bot = CaptchaBot("YOUR_API_KEY")

# Submit a contact form protected by reCAPTCHA
result = bot.submit_form(
    url="https://example.com/contact",
    form_data={
        "name": "John Doe",
        "email": "[email protected]",
        "message": "Inquiry about your service"
    },
    site_key="6Le-wvkS...",
    captcha_method="userrecaptcha"
)

print(f"Form submitted: {result.status_code}")

Ví dụ 2: bot đặt lịch nhiều bước

Luồng đặt lịch/booking thường có nhiều bước tuần tự, và CAPTCHA chỉ xuất hiện ở bước xác nhận cuối — không phải ngay từ đầu. Bot cần đi qua từng bước theo đúng thứ tự rồi mới gọi submit_form() ở bước cuối:

def appointment_booking_bot(date, time_slot, user_info):
    bot = CaptchaBot("YOUR_API_KEY")

    # Step 1: Load booking page
    page = bot.session.get("https://example.com/book")

    # Step 2: Select date and time
    resp = bot.session.post("https://example.com/book/select", data={
        "date": date,
        "time": time_slot
    })

    # Step 3: Fill personal info with CAPTCHA
    result = bot.submit_form(
        url="https://example.com/book/confirm",
        form_data={
            "name": user_info["name"],
            "email": user_info["email"],
            "phone": user_info["phone"],
            "date": date,
            "time": time_slot
        },
        site_key="6Le-wvkS...",
        captcha_method="userrecaptcha"
    )

    return result.status_code == 200

# Run
success = appointment_booking_bot(
    date="2025-02-15",
    time_slot="10:00",
    user_info={"name": "John Doe", "email": "[email protected]", "phone": "555-0100"}
)

Ví dụ 3: bot nhập dữ liệu với CAPTCHA hình ảnh

Cổng nội bộ (portal nhập liệu, hệ thống quản lý cũ) thường dùng CAPTCHA hình ảnh đơn giản thay vì reCAPTCHA. Bot tải ảnh về, mã hóa base64 rồi gửi trực tiếp cho CaptchaAI giải bằng method="base64" — không cần sitekey hay pageurl:

import base64

def data_entry_bot(entries, captcha_image_url):
    bot = CaptchaBot("YOUR_API_KEY")

    for entry in entries:
        # Load the form page
        page = bot.session.get("https://portal.example.com/entry")

        # Download and solve image CAPTCHA
        img = bot.session.get(captcha_image_url)
        img_b64 = base64.b64encode(img.content).decode()
        captcha_text = bot.solve("base64", body=img_b64)

        # Submit entry
        resp = bot.session.post("https://portal.example.com/entry", data={
            **entry,
            "captcha": captcha_text
        })

        logger.info(f"Entry submitted: {resp.status_code}")
        time.sleep(random.uniform(2, 5))

Framework bot bằng Node.js

Cùng logic gửi task/polling/dùng token như bản Python, viết lại cho stack Node.js — hữu ích khi bot chạy chung service với một backend Express/NestJS sẵn có:

const axios = require("axios");

class CaptchaBot {
  constructor(apiKey) {
    this.apiKey = apiKey;
  }

  async solve(method, params) {
    params.key = this.apiKey;
    params.method = method;

    const submit = await axios.get("https://ocr.captchaai.com/in.php", {
      params,
    });
    const taskId = submit.data.split("|")[1];

    while (true) {
      await new Promise((r) => setTimeout(r, 5000));
      const result = await axios.get("https://ocr.captchaai.com/res.php", {
        params: { key: this.apiKey, action: "get", id: taskId },
      });
      if (result.data === "CAPCHA_NOT_READY") continue;
      if (result.data.startsWith("OK|")) return result.data.split("|")[1];
      throw new Error(result.data);
    }
  }

  async submitForm(url, formData, siteKey, method = "userrecaptcha") {
    const token = await this.solve(method, {
      googlekey: siteKey,
      pageurl: url,
    });
    formData["g-recaptcha-response"] = token;

    return axios.post(url, new URLSearchParams(formData));
  }
}

// Usage
const bot = new CaptchaBot("YOUR_API_KEY");
const result = await bot.submitForm(
  "https://example.com/submit",
  { name: "John", email: "[email protected]" },
  "6Le-wvkS..."
);

Các lỗi thường gặp khi bot chạy thật

Framework ở trên chạy tốt trong demo, nhưng khi đưa vào production, bốn tình huống dưới đây là nguyên nhân phổ biến nhất khiến bot vẫn thất bại dù đã tích hợp CaptchaAI:

Vấn đề Cách xử lý
Token CAPTCHA bị từ chối khi submit Dùng token trong vòng 120 giây kể từ khi giải xong — token hết hạn nếu bot xử lý thêm bước trung gian quá lâu trước khi gửi form
Bot vẫn bị chặn dù token hợp lệ Kiểm tra lại các yếu tố khác của request: header trình duyệt đầy đủ (User-Agent, Accept-Language), cookie phiên hợp lệ, giãn thời gian giữa các bước thay vì gửi tức thời
Form yêu cầu thêm field ẩn ngoài CAPTCHA Kiểm tra HTML gốc của form để tìm field ẩn (thường là CSRF token) và gửi kèm cùng form_data
Bị giới hạn tần suất khi gửi nhiều request liên tiếp Giãn đều thời gian giữa các lần gửi và giới hạn số bot chạy song song phù hợp với quy mô hệ thống đích, thay vì dồn dập cùng lúc

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

CaptchaAI hỗ trợ những loại CAPTCHA nào cho bot tự động hóa?

CaptchaAI giải được reCAPTCHA v2/v3 (kể cả Enterprise), Cloudflare Turnstile, Cloudflare Challenge, GeeTest v3, CAPTCHA hình ảnh và BLS. CaptchaFox, Friendly Captcha và Lemin đang ở giai đoạn beta. CaptchaAI hiện không hỗ trợ hCaptcha và FunCaptcha (Arkose Labs).

Chạy hàng chục bot song song thì cần gói CaptchaAI nào?

Tùy số bot chạy đồng thời, không phải số CAPTCHA giải mỗi tháng — CaptchaAI tính phí theo thread, mỗi thread giải không giới hạn số CAPTCHA trong tháng. Đội chạy khoảng 10–15 bot song song thường vừa với STANDARD ($30/tháng, 15 thread); quy mô lớn hơn hợp với ADVANCE ($90/tháng, 50 thread) trở lên.

Nên dùng polling hay webhook cho bot chạy nền dài hạn?

Với bot chạy theo lịch (cron mỗi vài phút) như các ví dụ trong bài này, polling res.php đơn giản và đủ nhanh. Webhook hợp lý hơn khi có một service chạy liên tục, cần nhận token ngay khi có thay vì chờ vòng polling tiếp theo.

Bot gọi API CaptchaAI thất bại tạm thời (timeout, lỗi mạng) thì nên retry thế nào?

CAPCHA_NOT_READY không phải lỗi — đó là tín hiệu "chưa xong" trong vòng polling bình thường. Với lỗi thật sự (mất kết nối, HTTP 5xx), retry có giới hạn với backoff tăng dần (ví dụ 3 lần, giãn cách 5–10–20 giây) rồi mới coi là thất bại hẳn.

Token CaptchaAI giải một lần có dùng lại cho request khác được không?

Không. Token gắn với đúng pageurl/sitekey (hoặc url với Turnstile) tại thời điểm giải; trang đích thường từ chối token dùng lại. Bot chạy trên nhiều domain trong cùng một CaptchaBot vẫn cần gọi solve() riêng cho mỗi request.

Hướng dẫn liên quan

Os comentários estão desativados para este artigo.