Tutorials

Xây dựng quy trình CAPTCHA của khách hàng bằng CaptchaAI

Khi bạn quản lý việc thu thập dữ liệu hoặc tự động hóa cho nhiều khách hàng, cuối cùng mọi dự án đều đạt được CAPTCHA. Thay vì viết mã giải quyết một lần cho mỗi dự án, hãy xây dựng một quy trình có thể tái sử dụng. Hướng dẫn này đi qua kiến ​​trúc.


Kiến trúc đường ống

┌──────────────┐    ┌───────────────┐    ┌──────────────┐
│  Client A    │──▶ │               │    │              │
│  Client B    │──▶ │  Task Queue   │──▶ │  CaptchaAI   │
│  Client C    │──▶ │               │    │  API         │
└──────────────┘    └───────────────┘    └──────────────┘
                           │                    │
                           ▼                    ▼
                    ┌───────────────┐    ┌──────────────┐
                    │  Result Store │◀── │  Polling      │
                    │  (Redis/DB)   │    │  Workers      │
                    └───────────────┘    └──────────────┘

Thành phần:

  1. Nhận nhiệm vụ - nhận yêu cầu giải quyết từ người dọn dẹp khách hàng
  2. Hàng đợi — đệm các tác vụ, thực thi các giới hạn đồng thời cho mỗi khách hàng
  3. Người giải quyết — gửi tới CaptchaAI và thăm dò kết quả
  4. Cửa hàng kết quả - giữ các mã thông báo đã được giải quyết để người tiêu dùng truy xuất

Đường dẫn Python

Lớp giải quyết cốt lõi

import requests
import time
from dataclasses import dataclass
from typing import Optional
from collections import deque
from threading import Lock

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

@dataclass
class SolveRequest:
    client_id: str
    method: str
    params: dict
    callback: Optional[callable] = None

@dataclass
class SolveResult:
    client_id: str
    task_id: str
    token: Optional[str] = None
    error: Optional[str] = None

class CaptchaPipeline:
    def __init__(self, api_key: str, max_concurrent: int = 10):
        self.api_key = api_key
        self.max_concurrent = max_concurrent
        self.queue = deque()
        self.active = {}
        self.lock = Lock()

    def enqueue(self, request: SolveRequest):
        with self.lock:
            self.queue.append(request)

    def submit_task(self, request: SolveRequest) -> Optional[str]:
        data = {
            "key": self.api_key,
            "method": request.method,
            "json": 1,
            **request.params
        }

        try:
            resp = requests.post(SUBMIT_URL, data=data, timeout=15)
            result = resp.json()

            if result.get("status") == 1:
                return result["request"]
            else:
                print(f"[{request.client_id}] Submit error: {result.get('error_text', result.get('request'))}")
                return None
        except requests.RequestException as e:
            print(f"[{request.client_id}] Network error: {e}")
            return None

    def poll_result(self, task_id: str, max_wait: int = 120) -> Optional[str]:
        elapsed = 0
        interval = 5
        while elapsed < max_wait:
            time.sleep(interval)
            elapsed += interval

            try:
                resp = requests.get(RESULT_URL, params={
                    "key": self.api_key,
                    "action": "get",
                    "id": task_id,
                    "json": 1
                }, timeout=10)
                result = resp.json()

                if result.get("status") == 1:
                    return result["request"]
                elif result.get("request") == "CAPCHA_NOT_READY":
                    continue
                else:
                    print(f"Poll error for {task_id}: {result.get('error_text', result.get('request'))}")
                    return None
            except requests.RequestException:
                continue

        return None

    def process_queue(self):
        while self.queue or self.active:
            # Fill active slots
            with self.lock:
                while self.queue and len(self.active) < self.max_concurrent:
                    request = self.queue.popleft()
                    task_id = self.submit_task(request)
                    if task_id:
                        self.active[task_id] = request

            # Poll active tasks
            completed = []
            for task_id, request in list(self.active.items()):
                token = self.poll_result(task_id, max_wait=10)
                if token:
                    result = SolveResult(
                        client_id=request.client_id,
                        task_id=task_id,
                        token=token
                    )
                    if request.callback:
                        request.callback(result)
                    completed.append(task_id)

            with self.lock:
                for task_id in completed:
                    del self.active[task_id]

Sử dụng nhiều khách hàng

pipeline = CaptchaPipeline(api_key="YOUR_API_KEY", max_concurrent=15)

# Client A — reCAPTCHA v2
pipeline.enqueue(SolveRequest(
    client_id="client_a",
    method="userrecaptcha",
    params={
        "googlekey": "6Le-SITEKEY-A",
        "pageurl": "https://client-a-staging.example.com/qa-form"
    },
    callback=lambda r: print(f"[{r.client_id}] Solved: {r.token[:40]}...")
))

# Client B — Turnstile
pipeline.enqueue(SolveRequest(
    client_id="client_b",
    method="turnstile",
    params={
        "sitekey": "0x4AAAA-SITEKEY-B",
        "pageurl": "https://client-b-target.com/login"
    },
    callback=lambda r: print(f"[{r.client_id}] Solved: {r.token[:40]}...")
))

pipeline.process_queue()

Đường dẫn Node.js

const axios = require("axios");

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

class CaptchaPipeline {
  constructor(apiKey, maxConcurrent = 10) {
    this.apiKey = apiKey;
    this.maxConcurrent = maxConcurrent;
    this.queue = [];
    this.activeCount = 0;
  }

  enqueue(clientId, method, params) {
    return new Promise((resolve, reject) => {
      this.queue.push({ clientId, method, params, resolve, reject });
      this._processNext();
    });
  }

  async _processNext() {
    if (this.activeCount >= this.maxConcurrent || this.queue.length === 0) return;

    this.activeCount++;
    const task = this.queue.shift();

    try {
      const token = await this._solve(task);
      task.resolve({ clientId: task.clientId, token });
    } catch (err) {
      task.reject(err);
    } finally {
      this.activeCount--;
      this._processNext();
    }
  }

  async _solve(task) {
    const submitResp = await axios.post(SUBMIT_URL, null, {
      params: {
        key: this.apiKey,
        method: task.method,
        json: 1,
        ...task.params,
      },
      timeout: 15000,
    });

    if (submitResp.data.status !== 1) {
      throw new Error(submitResp.data.error_text || submitResp.data.request);
    }

    const taskId = submitResp.data.request;
    return this._poll(taskId);
  }

  async _poll(taskId, maxWait = 120000) {
    const interval = 5000;
    let elapsed = 0;

    while (elapsed < maxWait) {
      await new Promise((r) => setTimeout(r, interval));
      elapsed += interval;

      try {
        const resp = await axios.get(RESULT_URL, {
          params: {
            key: this.apiKey,
            action: "get",
            id: taskId,
            json: 1,
          },
          timeout: 10000,
        });

        if (resp.data.status === 1) return resp.data.request;
        if (resp.data.request !== "CAPCHA_NOT_READY") {
          throw new Error(resp.data.error_text || resp.data.request);
        }
      } catch (err) {
        if (err.response) throw err;
      }
    }

    throw new Error(`Timeout waiting for task ${taskId}`);
  }
}

// Usage
(async () => {
  const pipeline = new CaptchaPipeline("YOUR_API_KEY", 15);

  const results = await Promise.allSettled([
    pipeline.enqueue("client_a", "userrecaptcha", {
      googlekey: "6Le-SITEKEY-A",
      pageurl: "https://client-a-staging.example.com/qa-form",
    }),
    pipeline.enqueue("client_b", "turnstile", {
      sitekey: "0x4AAAA-SITEKEY-B",
      pageurl: "https://client-b-target.com/login",
    }),
  ]);

  results.forEach((r) => {
    if (r.status === "fulfilled") {
      console.log(`[${r.value.clientId}] Token: ${r.value.token.slice(0, 40)}...`);
    } else {
      console.error(`Failed: ${r.reason.message}`);
    }
  });
})();

Cấu hình cho mỗi khách hàng

Theo dõi cài đặt của mỗi khách hàng như proxy, tùy chọn người giải quyết và giới hạn tỷ lệ:

CLIENT_CONFIG = {
    "client_a": {
        "proxy": "host:port:user:pass",
        "proxytype": "HTTP",
        "max_concurrent": 5,
        "default_method": "userrecaptcha"
    },
    "client_b": {
        "proxy": None,
        "proxytype": None,
        "max_concurrent": 10,
        "default_method": "turnstile"
    }
}

def build_params(client_id, params):
    config = CLIENT_CONFIG.get(client_id, {})
    if config.get("proxy"):
        params["proxy"] = config["proxy"]
        params["proxytype"] = config["proxytype"]
    return params

Chiến lược xử lý lỗi

Lỗi phản hồi
ERROR_ZERO_BALANCE Dừng xếp hàng, cảnh báo tất cả khách hàng
ERROR_NO_SLOT_AVAILABLE Sắp xếp lại nhiệm vụ với độ trễ
ERROR_WRONG_CAPTCHA_ID Hủy, ghi lỗi
ERROR_CAPTCHA_UNSOLVABLE Thử lại một lần rồi thất bại
Hết thời gian chờ mạng Thử lại với thời gian chờ (tối đa 3 lần thử lại)

Khắc phục sự cố

Vấn đề Nguyên nhân Cách xử lý
Hàng đợi phát triển không giới hạn Các khe hoạt động đã đầy Tăng max_concurrent hoặc thêm công nhân
Gọi lại không kích hoạt Nhiệm vụ thất bại trong âm thầm Kiểm tra lỗi trả về trong vòng thăm dò ý kiến
Mã thông báo hỗn hợp giữa các khách hàng Kho kết quả được chia sẻ Kết quả chính của client_id + task_id
Lỗi giới hạn tỷ lệ (429) Quá nhiều lần gửi đồng thời Giảm đồng thời, thêm độ trễ gửi

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

Tôi nên chạy bao nhiêu tác vụ đồng thời cho mỗi khách hàng?

Bắt đầu với 5–10. Theo dõi thời gian giải quyết và tỷ lệ lỗi, sau đó điều chỉnh. CaptchaAI hỗ trợ tính đồng thời cao nhưng nhóm proxy của bạn có thể là nút cổ chai.

Tôi có nên sử dụng khóa API riêng cho mỗi khách hàng không?

Nó đơn giản hóa việc thanh toán. Sử dụng tham số CaptchaAI soft_id nếu bạn cần theo dõi bằng một phím.

Làm cách nào để xử lý hàng đợi qua đêm?

Duy trì hàng đợi (Redis hoặc cơ sở dữ liệu). Khi khởi động lại, hãy tải lại các tác vụ đang chờ xử lý và tiếp tục xử lý.


Xây dựng quy trình CAPTCHA của bạn với CaptchaAI

Bắt đầu xây dựng quy trình khách hàng tạicaptchaai.com.


Hướng dẫn liên quan

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