Tutoriels

Limiter le débit de vos propres demandes de résolution de CAPTCHA

CaptchaAI gère une concurrence élevée, mais vous souhaiterez peut-être vous limiter vous-même. Raisons : contrôle des coûts, évitement des pics involontaires de bugs, partage équitable des ressources entre les équipes ou respect des limites de débit fixées par les sites cibles. Ce guide met en œuvre trois modèles de limitation de débit côté client pourCaptchaAI.

Pourquoi une limitation de débit côté client

Scénario Sans limite Avec limite
Un bug provoque une boucle de résolution infinie Brûle à travers l'équilibre S'arrête au plafond configuré
Plusieurs équipes partagent une clé API Dépenses non coordonnées Répartition équitable par équipe
Cibler les interdictions de sites à > 100 req/min Les comptes sont bloqués Reste sous le seuil
Le budget est de 50 $/month Pourrait dépasser en un après-midi Plafond strict appliqué

Modèle 1 : seau de jetons

Un compartiment de jetons permet des rafales tout en appliquant un taux moyen. Les jetons se réapprovisionnent à un taux fixe ; chaque requête consomme un jeton.

Compartiment de jetons Python

# token_bucket_solver.py
import os
import time
import threading
import requests

API_KEY = os.environ.get("CAPTCHAAI_KEY", "YOUR_API_KEY")

class TokenBucket:
    """Token bucket rate limiter."""

    def __init__(self, rate, capacity):
        """
        rate: tokens added per second
        capacity: max tokens (burst size)
        """
        self.rate = rate
        self.capacity = capacity
        self.tokens = capacity
        self.last_refill = time.monotonic()
        self.lock = threading.Lock()

    def acquire(self, timeout=30):
        """Wait for a token. Returns True if acquired, False on timeout."""
        deadline = time.monotonic() + timeout
        while True:
            with self.lock:
                self._refill()
                if self.tokens >= 1:
                    self.tokens -= 1
                    return True

            if time.monotonic() >= deadline:
                return False
            time.sleep(0.1)

    def _refill(self):
        now = time.monotonic()
        elapsed = now - self.last_refill
        self.tokens = min(self.capacity, self.tokens + elapsed * self.rate)
        self.last_refill = now

# Allow 10 solves/minute with burst of 5
limiter = TokenBucket(rate=10/60, capacity=5)

def solve_rate_limited(sitekey, pageurl):
    """Solve with rate limiting."""
    if not limiter.acquire(timeout=60):
        raise Exception("Rate limit: could not acquire token within 60s")

    session = requests.Session()
    resp = session.get("https://ocr.captchaai.com/in.php", params={
        "key": API_KEY,
        "method": "userrecaptcha",
        "googlekey": sitekey,
        "pageurl": pageurl,
        "json": "1",
    })
    result = resp.json()

    if result.get("status") != 1:
        raise Exception(f"Submit failed: {result.get('request')}")

    task_id = result["request"]
    time.sleep(15)

    for _ in range(25):
        poll = session.get("https://ocr.captchaai.com/res.php", params={
            "key": API_KEY, "action": "get",
            "id": task_id, "json": "1",
        })
        poll_result = poll.json()
        if poll_result.get("status") == 1:
            return poll_result["request"]
        if poll_result.get("request") != "CAPCHA_NOT_READY":
            raise Exception(f"Error: {poll_result.get('request')}")
        time.sleep(5)

    raise Exception("Timeout")

Modèle 2 : Comptoir à fenêtre coulissante

Suit le nombre de demandes dans une fenêtre de temps fixe. Plus simple que le compartiment à jetons mais pas de contrôle en rafale.

Fenêtre coulissante JavaScript

// sliding_window_solver.js
const axios = require('axios');

const API_KEY = process.env.CAPTCHAAI_KEY || 'YOUR_API_KEY';

class SlidingWindowLimiter {
  constructor(maxRequests, windowMs) {
    this.maxRequests = maxRequests;
    this.windowMs = windowMs;
    this.timestamps = [];
  }

  async acquire(timeoutMs = 60000) {
    const deadline = Date.now() + timeoutMs;

    while (Date.now() < deadline) {
      // Remove expired timestamps
      const cutoff = Date.now() - this.windowMs;
      this.timestamps = this.timestamps.filter(t => t > cutoff);

      if (this.timestamps.length < this.maxRequests) {
        this.timestamps.push(Date.now());
        return true;
      }

      // Wait until the oldest request exits the window
      const waitMs = Math.min(
        this.timestamps[0] + this.windowMs - Date.now() + 10,
        deadline - Date.now()
      );
      if (waitMs > 0) await new Promise(r => setTimeout(r, waitMs));
    }
    return false;
  }
}

// Allow 20 solves per 5 minutes
const limiter = new SlidingWindowLimiter(20, 5 * 60 * 1000);

async function solveRateLimited(sitekey, pageurl) {
  const acquired = await limiter.acquire(60000);
  if (!acquired) throw new Error('Rate limit exceeded');

  const submit = await axios.get('https://ocr.captchaai.com/in.php', {
    params: {
      key: API_KEY, method: 'userrecaptcha',
      googlekey: sitekey, pageurl, json: '1',
    },
  });

  if (submit.data.status !== 1) throw new Error(submit.data.request);
  await new Promise(r => setTimeout(r, 15000));

  for (let i = 0; i < 25; i++) {
    const poll = await axios.get('https://ocr.captchaai.com/res.php', {
      params: { key: API_KEY, action: 'get', id: submit.data.request, json: '1' },
    });
    if (poll.data.status === 1) return poll.data.request;
    if (poll.data.request !== 'CAPCHA_NOT_READY') throw new Error(poll.data.request);
    await new Promise(r => setTimeout(r, 5000));
  }
  throw new Error('Timeout');
}

Modèle 3 : limiteur basé sur le budget

Définissez un budget de coûts quotidien et arrêtez-vous lorsqu'il est atteint :

# budget_limiter.py
import os
import time
from datetime import date

class BudgetLimiter:
    """Limit daily CAPTCHA spending."""

    def __init__(self, daily_budget, cost_per_solve=0.003):
        self.daily_budget = daily_budget
        self.cost_per_solve = cost_per_solve
        self.daily_spend = 0.0
        self.current_date = date.today()

    def can_solve(self):
        """Check if budget allows another solve."""
        if date.today() != self.current_date:
            self.daily_spend = 0.0
            self.current_date = date.today()

        return self.daily_spend + self.cost_per_solve <= self.daily_budget

    def record_solve(self):
        """Record a successful solve against the budget."""
        self.daily_spend += self.cost_per_solve

    @property
    def remaining_budget(self):
        return max(0, self.daily_budget - self.daily_spend)

    @property
    def remaining_solves(self):
        return int(self.remaining_budget / self.cost_per_solve)

# $5/day budget
budget = BudgetLimiter(daily_budget=5.00, cost_per_solve=0.003)

def solve_with_budget(sitekey, pageurl):
    if not budget.can_solve():
        raise Exception(
            f"Daily budget exhausted. Remaining: ${budget.remaining_budget:.2f}"
        )

    # ... solve logic ...
    token = "..."  # actual solve
    budget.record_solve()
    return token

Choisir un modèle

Modèle Idéal pour Complexité
Seau de jetons Contrôle du débit en douceur avec tolérance en rafale Moyen
Fenêtre coulissante Nombre de demandes simples par fenêtre horaire Faible
Limiteur de budget Contrôle des coûts par jour/week/month Faible
Combiné (tarif + budget) Systèmes de production Moyen

Dépannage

Problème Parce que Corriger
Toutes les requêtes sont en file d'attente, aucune n'est en cours d'exécution Tarif trop bas par rapport à la demande Augmenter le taux ou la taille de la fenêtre
Le limiteur de budget se réinitialise à midi Changement ou redémarrage de l'horloge système Conserver les dépenses quotidiennes dans un fichier ou une base de données
Le seau de jetons se vide en rafale Capacité trop petite pour le flux de travail Augmenter le paramètre de capacité
Le limiteur de débit bloque les demandes d'interrogation Limiteur appliqué également aux sondages Limitez uniquement les demandes de soumission, pas les sondages

FAQ

Dois-je limiter le taux de la demande de soumission ou de la demande de sondage ?

Limitez le débit uniquement à la demande submit (in.php). L'interrogation (res.php) devrait s'exécuter librement car elle ne crée pas de nouvelles tâches et ne coûte pas d'argent.

Comment partager les limites de taux entre plusieurs travailleurs ?

Utilisez la limitation de débit basée sur Redis. Des bibliothèques comme redis-rate-limiter (Python) ou rate-limiter-flexible (Node.js) prennent en charge la limitation de débit distribuée avec des opérations atomiques.

CaptchaAI peut-il m'indiquer mon taux d'utilisation actuel ?

Utilisez le point de terminaison du solde pour suivre les dépenses. Pour une utilisation détaillée, implémentez vos propres compteurs comme indiqué dans ce guide.

Articles connexes

Prochaines étapes

Contrôlez votre taux de résolution de CAPTCHA et votre budget -récupérez votre clé API CaptchaAI.

Guides associés :

  • Limites de débit et limitation
  • 10 000 tâches par heure
  • Vérification du solde et recharge automatique
Les commentaires sont désactivés pour cet article.