Hướng Dẫn Thực Hành

Thông lượng giải CAPTCHA: Cách xử lý 10.000 tác vụ mỗi giờ

Xử lý 10.000 CAPTCHA mỗi giờ không phải bài toán tốc độ — CaptchaAI không cần giải nhanh hơn mức trung bình 15 giây. Vấn đề là duy trì đủ request chạy song song.

Bài viết đi thẳng vào công thức concurrency, kiến trúc hàng đợi, code Python/Node.js và bảng tham số theo ba mức rủi ro bằng CaptchaAI.

Công thức tính số request đồng thời cần thiết

Một lần giải reCAPTCHA v2 mất trung bình 15 giây. Chạy tuần tự bạn chỉ đạt 240 giải/giờ; để chạm 10.000 giải/giờ, bạn cần khoảng 42 request đồng thời.

Cách chạy Request đồng thời Thông lượng
Tuần tự 1 240 giải/giờ
Song song ~42 10.000 giải/giờ

Điểm mấu chốt: chồng đủ request lên nhau, không phải chờ CaptchaAI trả kết quả nhanh hơn.

Chọn mức cấu hình theo khẩu vị rủi ro

Chọn một trong ba mức cấu hình trước khi build. Mức Cân bằng dùng 50 request đồng thời — điểm khởi đầu hợp lý cho hầu hết đội automation.

Tham số Bảo thủ Cân bằng Quyết liệt
MAX_CONCURRENT 20 50 100
INITIAL_WAIT 15 giây 12 giây 10 giây
POLL_INTERVAL 7 giây 5 giây 3 giây
MAX_POLL_ATTEMPTS 30 25 20
Thông lượng dự kiến ~4.800/giờ ~10.000/giờ ~18.000/giờ

Bắt đầu ở mức Bảo thủ, tăng dần MAX_CONCURRENT đến khi thấy lợi nhuận giảm dần.

Kiến trúc pipeline

Một pipeline thông lượng cao gồm bốn khối tách biệt, giao tiếp qua hàng đợi thay vì gọi tuần tự:

┌──────────┐     ┌────────────┐     ┌─────────────┐     ┌──────────┐
│  Task     │────▶│  Submit    │────▶│  CaptchaAI  │────▶│  Result  │
│  Queue    │     │  Workers   │     │  API        │     │  Store   │
│  (Redis)  │     │  (async)   │     │             │     │  (DB)    │
└──────────┘     └────────────┘     └─────────────┘     └──────────┘
                       │                    ▲
                       │    ┌──────────┐    │
                       └───▶│  Poll    │────┘
                            │  Workers │
                            └──────────┘

Thành phần:

  1. Task queue (Redis) — giữ task CAPTCHA đang chờ, kèm sitekey và pageurl
  2. Submit worker — gửi task tới API CaptchaAI đồng thời
  3. Poll worker — kiểm tra kết quả theo khoảng thời gian tối ưu (polling)
  4. Result store — lưu token ngay khi có kết quả

Ví dụ thực tế: đồng bộ catalog thương mại điện tử

Một tình huống quen thuộc với đội automation ở TP.HCM và Hà Nội: đồng bộ trang sản phẩm khi sàn thương mại điện tử đổi CAPTCHA trên form đăng nhập hoặc trang giá. Kiến trúc trên áp dụng y hệt.

Với vài nghìn SKU cần refresh trong một cửa sổ bảo trì ngắn, 10.000 CAPTCHA/giờ đủ để một team QA nhỏ xử lý xong trong một ca thay vì kéo dài qua đêm.

Code Python: pipeline async

Bản triển khai async dưới đây dùng aiohttp với connection pooling và semaphore giới hạn concurrency:

# high_throughput_solver.py
import os
import asyncio
import time
import aiohttp

API_KEY = os.environ.get("CAPTCHAAI_KEY", "YOUR_API_KEY")
BASE_URL = "https://ocr.captchaai.com"
MAX_CONCURRENT = 50  # Max simultaneous solves
POLL_INTERVAL = 5    # Seconds between polls
INITIAL_WAIT = 12    # Seconds before first poll

semaphore = asyncio.Semaphore(MAX_CONCURRENT)
stats = {"submitted": 0, "solved": 0, "failed": 0, "start": 0}

async def solve_one(session, sitekey, pageurl, task_num):
    """Submit and poll a single CAPTCHA."""
    async with semaphore:
        try:
            # Submit
            async with session.get(f"{BASE_URL}/in.php", params={
                "key": API_KEY, "method": "userrecaptcha",
                "googlekey": sitekey, "pageurl": pageurl, "json": "1",
            }) as resp:
                result = await resp.json(content_type=None)

            if result.get("status") != 1:
                stats["failed"] += 1
                return None

            stats["submitted"] += 1
            task_id = result["request"]

            # Wait before first poll
            await asyncio.sleep(INITIAL_WAIT)

            # Poll
            for _ in range(25):
                async with session.get(f"{BASE_URL}/res.php", params={
                    "key": API_KEY, "action": "get",
                    "id": task_id, "json": "1",
                }) as resp:
                    poll_result = await resp.json(content_type=None)

                if poll_result.get("status") == 1:
                    stats["solved"] += 1
                    return poll_result["request"]

                if poll_result.get("request") != "CAPCHA_NOT_READY":
                    stats["failed"] += 1
                    return None

                await asyncio.sleep(POLL_INTERVAL)

            stats["failed"] += 1
            return None

        except Exception as e:
            stats["failed"] += 1
            return None

async def run_batch(tasks):
    """Process a batch of CAPTCHA tasks concurrently."""
    connector = aiohttp.TCPConnector(
        limit=MAX_CONCURRENT,
        keepalive_timeout=60,
    )
    async with aiohttp.ClientSession(connector=connector) as session:
        coros = [
            solve_one(session, task["sitekey"], task["pageurl"], i)
            for i, task in enumerate(tasks)
        ]
        results = await asyncio.gather(*coros)
    return results

async def main():
    # Generate test tasks (replace with your task source)
    tasks = [
        {
            "sitekey": "6Le-wvkSAAAAAPBMRTvw0Q4Muexq9bi0DJwx_mJ-",
            "pageurl": "https://www.google.com/recaptcha/api2/demo",
        }
        for _ in range(100)  # Start with 100 tasks
    ]

    stats["start"] = time.time()
    print(f"Processing {len(tasks)} tasks with {MAX_CONCURRENT} concurrent workers")

    results = await run_batch(tasks)
    elapsed = time.time() - stats["start"]

    print(f"\nCompleted in {elapsed:.0f}s")
    print(f"Submitted: {stats['submitted']}")
    print(f"Solved: {stats['solved']}")
    print(f"Failed: {stats['failed']}")
    print(f"Throughput: {stats['solved'] / (elapsed / 3600):.0f} solves/hour")

asyncio.run(main())

Code Node.js: xử lý đồng thời với axios

Phiên bản Node.js dùng axios cùng HTTPS agent keep-alive và hàng đợi giới hạn concurrency thủ công:

// high_throughput_solver.js
const axios = require('axios');
const https = require('https');

const API_KEY = process.env.CAPTCHAAI_KEY || 'YOUR_API_KEY';
const BASE = 'https://ocr.captchaai.com';
const MAX_CONCURRENT = 50;

const agent = new https.Agent({ keepAlive: true, maxSockets: MAX_CONCURRENT });
const api = axios.create({ baseURL: BASE, httpsAgent: agent, timeout: 30000 });

const stats = { submitted: 0, solved: 0, failed: 0 };

async function solveOne(sitekey, pageurl) {
  try {
    const submit = await api.get('/in.php', {
      params: { key: API_KEY, method: 'userrecaptcha', googlekey: sitekey, pageurl, json: '1' },
    });
    if (submit.data.status !== 1) { stats.failed++; return null; }
    stats.submitted++;

    await new Promise(r => setTimeout(r, 12000));

    for (let i = 0; i < 25; i++) {
      const poll = await api.get('/res.php', {
        params: { key: API_KEY, action: 'get', id: submit.data.request, json: '1' },
      });
      if (poll.data.status === 1) { stats.solved++; return poll.data.request; }
      if (poll.data.request !== 'CAPCHA_NOT_READY') { stats.failed++; return null; }
      await new Promise(r => setTimeout(r, 5000));
    }
    stats.failed++;
    return null;
  } catch { stats.failed++; return null; }
}

async function runWithConcurrency(tasks, limit) {
  const results = [];
  const executing = new Set();

  for (const task of tasks) {
    const p = solveOne(task.sitekey, task.pageurl).then(r => {
      executing.delete(p);
      return r;
    });
    executing.add(p);
    results.push(p);

    if (executing.size >= limit) {
      await Promise.race(executing);
    }
  }
  return Promise.all(results);
}

(async () => {
  const tasks = Array.from({ length: 100 }, () => ({
    sitekey: '6Le-wvkSAAAAAPBMRTvw0Q4Muexq9bi0DJwx_mJ-',
    pageurl: 'https://www.google.com/recaptcha/api2/demo',
  }));

  const start = Date.now();
  console.log(`Processing ${tasks.length} tasks, ${MAX_CONCURRENT} concurrent`);

  await runWithConcurrency(tasks, MAX_CONCURRENT);
  const elapsed = (Date.now() - start) / 1000;

  console.log(`\nDone in ${elapsed.toFixed(0)}s`);
  console.log(`Solved: ${stats.solved}, Failed: ${stats.failed}`);
  console.log(`Throughput: ${(stats.solved / (elapsed / 3600)).toFixed(0)} solves/hour`);

  agent.destroy();
})();

Giám sát thông lượng theo thời gian thực

Theo dõi bốn số liệu này khi chạy ở quy mô lớn:

Số liệu Mục tiêu / ngưỡng
Số lần giải mỗi phút ~167/phút
Tỷ lệ lỗi Dưới 5%, tăng đột biến thì giảm concurrency
Độ sâu hàng đợi Phình to → tăng worker; trống liên tục → thừa worker
Thời gian giải P90 Tăng dần → CaptchaAI có thể áp rate limit

Xử lý sự cố thường gặp

Vấn đề Nguyên nhân Cách xử lý
Thông lượng chững ở ~5.000/giờ Concurrency chưa đủ Tăng MAX_CONCURRENT lên 80–100
Tỷ lệ lỗi > 10% Quá tải API hoặc proxy kém ổn định Giảm concurrency, kiểm tra tình trạng proxy
Bộ nhớ tăng liên tục Task tích lũy không giới hạn Xử lý kết quả ngay khi có, không buffer
ERROR_NO_SLOT_AVAILABLE Hàng đợi CaptchaAI đầy Backoff và thử lại sau 5 giây

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

Với 10.000 giải/giờ, nên chọn plan CaptchaAI nào?

ADVANCE ($90/tháng, 50 thread) là điểm khởi đầu hợp lý, đúng bằng mức Cân bằng ở bảng trên. Cần biên độ an toàn hơn thì chọn PREMIUM ($170/tháng, 100 thread).

Nên dùng polling hay webhook khi chạy khối lượng lớn?

Polling như trong bài đủ dùng ở quy mô này. Webhook giảm round-trip nhưng cần endpoint public ổn định.

Vì sao tỷ lệ lỗi tăng khi tăng MAX_CONCURRENT?

Thường do proxy pool yếu hoặc chạm rate limit phía CaptchaAI. Tăng concurrency từng bước 20–30%.

Có thể chạy song song trên nhiều máy chủ không?

Có. Dùng hàng đợi dùng chung (Redis, RabbitMQ) và chạy cùng worker script trên nhiều máy — mỗi worker tự lấy task độc lập.

Bước tiếp theo

Triển khai pipeline thông lượng cao của bạn — lấy API key CaptchaAI và bắt đầu ở mức Bảo thủ.

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

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