API Eğitimleri

Başarısız CAPTCHA Görevleri için Teslim Edilmeyen Mektup Kuyruğu

CAPTCHA çözümü tüm yeniden denemelerden sonra başarısız olursa, siz yakalamadığınız sürece görev verileri kaybolur. Teslim edilemeyen görevler kuyruğu (DLQ), başarısız görevleri daha sonra yeniden denemek, analiz etmek veya uyarmak için saklar; böylece hiçbir iş sessizce bırakılmaz.


Görevler başarısız olduğunda

Bir CAPTCHA görevinin DLQ'da sonuçlanmasının yaygın nedenleri:

  • ERROR_CAPTCHA_UNSOLVABLE – Çözücü görevi tamamlayamadı
  • ERROR_NO_SLOT_AVAILABLE – Tüm çalışanlar meşgul, yeniden denemeler bitkin
  • Zaman aşımı – Çözücü son tarih içinde bir sonuç döndürmedi
  • Ağ hataları – Yoklama sırasında bağlantı kesildi

DLQ olmadan bu hatalar bir günlük satırı oluşturur ve unutulur.


Python: Yeniden denemeli bellek içi DLQ

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()}")

Beklenen çıktı:

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

DLQ size: 2

DLQ'dan yeniden deneniyor

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: Dosya kalıcılığına sahip DLQ

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()}`);
})();

DLQ analizi

Kalıpları bulmak için başarısız görevleri dışa aktarın ve analiz edin:

# 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}")

Bu verileri aşağıdaki amaçlarla kullanın:

  • Sürekli olarak başarısız olan site anahtarlarını belirleyin; parametrelerin doğru olup olmadığını kontrol edin
  • Belirli saatlerde nokta zaman aşımları API yüküyle ilişkilidir
  • Ağ hatalarını bulun – proxy sağlığını kontrol edin

Sorun giderme

Sorun Sebep Düzeltme
DLQ süresiz olarak büyüyor Yeniden denemeler işlenmiyor retry_dlq() ile periyodik DLQ tahliyesini planlayın
Aynı görev sonsuza kadar yeniden denendi Maksimum deneme sınırı yok Yeniden kuyruğa almadan önce task.attempts'yi kontrol edin
DLQ dosyası bozuk Eşzamanlı yazma Dosya kilitlemeyi kullanın veya Redis/database'ye geçin
Kilitlenme sırasında kaybedilen görevler Yalnızca bellek içi DLQ Dosya tabanlı veya Redis destekli DLQ kullanın

SSS

Bellek içi mi yoksa kalıcı bir DLQ mu kullanmalıyım?

Kısa süreli komut dosyaları için bellek içi kullanın. İşlemin yeniden başlatılmasının sıradaki görevleri kaybedeceği uzun süre çalışan hizmetler için dosya tabanlı veya Redis destekli kullanın.

Bir görevi ne zaman kalıcı olarak silmeliyim?

2-3 DLQ yeniden denemesinden sonra (orijinal yeniden denemelerin üstüne). Bir görev toplamda 6 defadan fazla başarısız olursa, parametreler muhtemelen yanlıştır; kaydı yapın ve devam edin.

Bunu devre kesici düzeniyle birleştirebilir miyim?

Evet. Devre kesici, bir kesinti sırasında isteklerin gönderilmesini önler ve DLQ, devre açılmadan önce başarısız olan tüm görevleri yakalar. GörmekDevre Kesici Modeli.


CaptchaAI ile başarısız bir CAPTCHA görevini bir daha asla kaybetmeyin

API anahtarınızı şu adresten alın:captchaai.com.


İlgili kılavuzlar

Bu makale için yorumlar devre dışı bırakılmıştır.