Hướng Dẫn API

Hàng đợi thư chết cho các tác vụ CAPTCHA không thành công

Khi giải CAPTCHA không thành công sau tất cả các lần thử lại, dữ liệu tác vụ sẽ bị mất trừ khi bạn chụp được nó. Hàng đợi thư chết (DLQ) lưu trữ các tác vụ không thành công để thử lại, phân tích hoặc cảnh báo sau này — do đó, không có công việc nào bị âm thầm bỏ qua.


Khi nhiệm vụ thất bại

Những lý do phổ biến khiến tác vụ CAPTCHA kết thúc trong DLQ:

  • ERROR_CAPTCHA_UNSOLVABLE — Người giải không thể hoàn thành thử thách
  • ERROR_NO_SLOT_AVAILABLE – Tất cả công nhân đều bận rộn, thử lại đều kiệt sức
  • Hết thời gian - Bộ giải không trả về kết quả trong thời hạn
  • Lỗi mạng - Kết nối bị rớt trong quá trình bỏ phiếu

Nếu không có DLQ, những lỗi này sẽ tạo ra dòng nhật ký và bị lãng quên.


Python: DLQ trong bộ nhớ có thử lại

import time
import json
import requests
from collections import deque
from dataclasses import dataclass, asdict
from typing import Optional

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

@dataclass
class FailedTask:
    sitekey: str
    page_url: str
    error: str
    attempts: int
    timestamp: float
    task_id: Optional[str] = None

class DeadLetterQueue:
    def __init__(self, max_size=1000, max_retries=3):
        self._queue = deque(maxlen=max_size)
        self.max_retries = max_retries

    def push(self, task: FailedTask):
        self._queue.append(task)
        print(f"[dlq] Added: {task.error} (attempts: {task.attempts})")

    def pop(self) -> Optional[FailedTask]:
        return self._queue.popleft() if self._queue else None

    def size(self) -> int:
        return len(self._queue)

    def peek_all(self) -> list:
        return [asdict(t) for t in self._queue]

    def export_json(self, path: str):
        with open(path, "w") as f:
            json.dump(self.peek_all(), f, indent=2)
        print(f"[dlq] Exported {self.size()} tasks to {path}")

dlq = DeadLetterQueue(max_retries=3)

def solve_captcha(sitekey, page_url, max_retries=3):
    for attempt in range(max_retries + 1):
        try:
            resp = requests.post(SUBMIT_URL, data={
                "key": API_KEY,
                "method": "userrecaptcha",
                "googlekey": sitekey,
                "pageurl": page_url,
                "json": "1",
            }, timeout=15)
            data = resp.json()
            if data["status"] != 1:
                raise Exception(data["request"])

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

                if poll["status"] == 1:
                    return poll["request"]
                if poll["request"] != "CAPCHA_NOT_READY":
                    raise Exception(poll["request"])

            raise TimeoutError(f"Task {task_id} timed out")

        except Exception as e:
            if attempt == max_retries:
                dlq.push(FailedTask(
                    sitekey=sitekey,
                    page_url=page_url,
                    error=str(e),
                    attempts=attempt + 1,
                    timestamp=time.time(),
                ))
                return None
            time.sleep(2 ** attempt)

    return None

# Process a batch
urls = [f"https://example.com/page/{i}" for i in range(5)]
for url in urls:
    token = solve_captcha("6Le-SITEKEY", url)
    if token:
        print(f"Solved: {token[:40]}...")

print(f"\nDLQ size: {dlq.size()}")

Sản lượng dự kiến:

Solved: 03AGdBq26ZfPxL...
Solved: 03AGdBq27AbCdE...
[dlq] Added: ERROR_CAPTCHA_UNSOLVABLE (attempts: 4)
Solved: 03AGdBq28FgHiJ...
[dlq] Added: Task 71823460 timed out (attempts: 4)

DLQ size: 2

Đang thử lại từ DLQ

def retry_dlq(dlq: DeadLetterQueue, max_retries=2):
    retried = 0
    recovered = 0

    while dlq.size() > 0:
        task = dlq.pop()
        if task.attempts >= dlq.max_retries + max_retries:
            print(f"[dlq] Permanently failed: {task.sitekey} — {task.error}")
            continue

        retried += 1
        token = solve_captcha(
            task.sitekey, task.page_url, max_retries=max_retries
        )
        if token:
            recovered += 1
            print(f"[dlq-retry] Recovered: {token[:40]}...")

    print(f"[dlq] Retried: {retried}, Recovered: {recovered}")

# Run DLQ retry after main batch
retry_dlq(dlq)

JavaScript: DLQ với tính bền vững của tệp

const fs = require('fs');
const axios = require('axios');

const API_KEY = 'YOUR_API_KEY';
const DLQ_FILE = './captcha-dlq.json';

class DeadLetterQueue {
  constructor(maxRetries = 3) {
    this.maxRetries = maxRetries;
    this.queue = this._load();
  }

  push(task) {
    this.queue.push({
      ...task,
      timestamp: Date.now(),
    });
    this._save();
    console.log(`[dlq] Added: ${task.error} (attempts: ${task.attempts})`);
  }

  pop() {
    const task = this.queue.shift();
    if (task) this._save();
    return task || null;
  }

  size() {
    return this.queue.length;
  }

  _load() {
    try {
      return JSON.parse(fs.readFileSync(DLQ_FILE, 'utf8'));
    } catch {
      return [];
    }
  }

  _save() {
    fs.writeFileSync(DLQ_FILE, JSON.stringify(this.queue, null, 2));
  }
}

const dlq = new DeadLetterQueue(3);

async function solveCaptcha(sitekey, pageurl, maxRetries = 3) {
  for (let attempt = 0; attempt <= maxRetries; attempt++) {
    try {
      const submit = await axios.post('https://ocr.captchaai.com/in.php', null, {
        params: { key: API_KEY, method: 'userrecaptcha', googlekey: sitekey, pageurl, json: 1 }
      });
      if (submit.data.status !== 1) throw new Error(submit.data.request);

      const taskId = submit.data.request;
      for (let i = 0; i < 24; i++) {
        await new Promise(r => setTimeout(r, 5000));
        const poll = await axios.get('https://ocr.captchaai.com/res.php', {
          params: { key: API_KEY, action: 'get', id: taskId, json: 1 }
        });
        if (poll.data.status === 1) return poll.data.request;
        if (poll.data.request !== 'CAPCHA_NOT_READY') throw new Error(poll.data.request);
      }
      throw new Error(`Task ${taskId} timed out`);
    } catch (err) {
      if (attempt === maxRetries) {
        dlq.push({ sitekey, pageurl, error: err.message, attempts: attempt + 1 });
        return null;
      }
      await new Promise(r => setTimeout(r, 2 ** attempt * 1000));
    }
  }
}

// Process tasks
(async () => {
  for (let i = 0; i < 5; i++) {
    const token = await solveCaptcha('6Le-SITEKEY', `https://example.com/page/${i}`);
    if (token) console.log(`Solved: ${token.substring(0, 40)}...`);
  }
  console.log(`DLQ size: ${dlq.size()}`);
})();

phân tích DLQ

Xuất và phân tích các tác vụ thất bại để tìm mẫu:

# Export DLQ for analysis
dlq.export_json("failed-tasks.json")

# Analyze error distribution
from collections import Counter
errors = Counter(t["error"] for t in dlq.peek_all())
for error, count in errors.most_common():
    print(f"  {error}: {count}")

Sử dụng dữ liệu này để:

  • Xác định các khóa trang web liên tục bị lỗi †' kiểm tra xem các tham số có chính xác không
  • Thời gian chờ tại chỗ trong những giờ cụ thể → tương quan với tải API
  • Tìm lỗi mạng †' kiểm tra tình trạng proxy

Chính sách phát lại thư chết

  • Giữ bối cảnh yêu cầu ban đầu, lý do thất bại và số lần thử lại cùng nhau để việc phát lại luôn an toàn và có thể gỡ lỗi.
  • Xác định lỗi nào có thể được phát lại tự động và lỗi nào phải chờ người vận hành xem xét.
  • Coi thông lượng phát lại, tuổi hàng đợi và tỷ lệ lỗi lặp lại là tín hiệu vận hành hạng nhất.

Khắc phục sự cố

Vấn đề Nguyên nhân Cách xử lý
DLQ phát triển vô hạn Không xử lý lần thử lại Lên lịch xả DLQ định kỳ với retry_dlq()
Nhiệm vụ tương tự được thử lại mãi mãi Không có giới hạn số lần thử tối đa Kiểm tra task.attempts trước khi xếp hàng lại
Tệp DLQ bị hỏng Viết đồng thời Sử dụng khóa tệp hoặc chuyển sang Redis/database
Mất nhiệm vụ khi gặp sự cố Chỉ DLQ trong bộ nhớ Sử dụng DLQ dựa trên tệp hoặc được Redis hỗ trợ

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

Tôi nên sử dụng DLQ trong bộ nhớ hay liên tục?

Sử dụng trong bộ nhớ cho các tập lệnh chạy ngắn. Sử dụng dựa trên tệp hoặc được Redis hỗ trợ cho các dịch vụ chạy lâu trong đó việc khởi động lại quy trình sẽ làm mất các tác vụ được xếp hàng đợi.

Khi nào tôi nên loại bỏ vĩnh viễn một nhiệm vụ?

Sau 2-3 lần thử lại DLQ (ngoài số lần thử lại ban đầu). Nếu một tác vụ thất bại tổng cộng hơn 6 lần, các tham số có thể sai - hãy ghi lại nó và tiếp tục.

Tôi có thể kết hợp điều này với mẫu ngắt mạch không?

Đúng. Bộ ngắt mạch ngăn chặn việc gửi yêu cầu trong thời gian ngừng hoạt động và DLQ ghi lại mọi tác vụ bị lỗi trước khi ngắt mạch. Nhìn thấyMẫu ngắt mạch.


Không bao giờ mất nhiệm vụ CAPTCHA thất bại nữa với CaptchaAI

Nhận khóa API của bạn tạicaptchaai.com.


Hướng dẫn liên quan

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