Kontrolsüz eşzamanlılık, istekleri olabildiğince hızlı gönderir. Bu, ERROR_TOO_MUCH_REQUESTS'ye, API bakiyesinin boşa harcanmasına ve öngörülemeyen maliyetlere yol açar. Bir jeton kümesi, "saniyede en fazla 20 gönderim" şeklinde kesin bir oran belirlemenize olanak tanırken, kapasite mevcut olduğunda yine de kısa patlamalara izin verir.
Token Kovası Nasıl Çalışır?
[Bucket] capacity=20, refill=10/sec
Time 0: ████████████████████ 20 tokens available
→ 15 requests consume 15 tokens
Time 0: █████ 5 tokens remain
Time 1s: ███████████████ 15 tokens (5 + 10 refilled)
→ 15 requests consume 15 tokens
Time 1s: (empty) 0 tokens
Time 2s: ██████████ 10 tokens (0 + 10 refilled)
→ Request waits if bucket is empty
Anahtar özellikler:
- Kapasite – maksimum seri çekim boyutu
- Yeniden dolum oranı – saniye başına sürekli istek sayısı
- İstekler paket boşaldığında bekler (reddetme yok, yalnızca azaltma)
Python Uygulaması
İş Parçacığı Güvenli Jeton Kovası
import time
import threading
class TokenBucket:
def __init__(self, capacity, refill_rate):
"""
Args:
capacity: Maximum tokens (burst size)
refill_rate: Tokens added per second
"""
self.capacity = capacity
self.refill_rate = refill_rate
self.tokens = capacity
self.last_refill = time.monotonic()
self.lock = threading.Lock()
def acquire(self, timeout=None):
"""Block until a token is available."""
deadline = time.monotonic() + timeout if timeout else float("inf")
while True:
with self.lock:
self._refill()
if self.tokens >= 1:
self.tokens -= 1
return True
# Check timeout
if time.monotonic() >= deadline:
return False
# Wait before retrying (avoid busy loop)
time.sleep(min(1.0 / self.refill_rate, 0.1))
def _refill(self):
now = time.monotonic()
elapsed = now - self.last_refill
new_tokens = elapsed * self.refill_rate
self.tokens = min(self.capacity, self.tokens + new_tokens)
self.last_refill = now
Hız Sınırlı CAPTCHA Çözücü
import os
import requests
from concurrent.futures import ThreadPoolExecutor, as_completed
API_KEY = os.environ["CAPTCHAAI_API_KEY"]
# Allow 10 submissions/sec with burst of 20
rate_limiter = TokenBucket(capacity=20, refill_rate=10)
def solve_captcha_rate_limited(sitekey, pageurl):
"""Solve with rate limiting on submission."""
# Wait for token before submitting
rate_limiter.acquire()
resp = requests.post("https://ocr.captchaai.com/in.php", data={
"key": API_KEY,
"method": "userrecaptcha",
"googlekey": sitekey,
"pageurl": pageurl,
"json": 1
})
data = resp.json()
if data.get("status") != 1:
raise RuntimeError(data.get("request"))
captcha_id = data["request"]
# Polling doesn't need rate limiting (separate concern)
for _ in range(60):
time.sleep(5)
result = requests.get("https://ocr.captchaai.com/res.php", params={
"key": API_KEY, "action": "get", "id": captcha_id, "json": 1
}).json()
if result.get("status") == 1:
return result["request"]
if result.get("request") != "CAPCHA_NOT_READY":
raise RuntimeError(result.get("request"))
raise TimeoutError("Solve timeout")
# Run 100 tasks through rate limiter
tasks = [
{"sitekey": "6Le-wvkSAAAAAPBMRTvw0Q4Muexq9bi0DJwx_mJ-",
"pageurl": f"https://example.com/p/{i}"}
for i in range(100)
]
with ThreadPoolExecutor(max_workers=30) as executor:
futures = {
executor.submit(
solve_captcha_rate_limited, t["sitekey"], t["pageurl"]
): t for t in tasks
}
for future in as_completed(futures):
task = futures[future]
try:
solution = future.result()
print(f"[OK] {task['pageurl']}")
except Exception as e:
print(f"[ERR] {task['pageurl']}: {e}")
JavaScript Uygulaması
Eşzamansız Token Paketi
class TokenBucket {
constructor(capacity, refillRate) {
this.capacity = capacity;
this.refillRate = refillRate; // tokens per second
this.tokens = capacity;
this.lastRefill = Date.now();
this.waitQueue = [];
}
_refill() {
const now = Date.now();
const elapsed = (now - this.lastRefill) / 1000;
this.tokens = Math.min(this.capacity, this.tokens + elapsed * this.refillRate);
this.lastRefill = now;
}
async acquire() {
this._refill();
if (this.tokens >= 1) {
this.tokens -= 1;
return;
}
// Wait until a token is available
const waitTime = ((1 - this.tokens) / this.refillRate) * 1000;
await new Promise((resolve) => setTimeout(resolve, waitTime));
this._refill();
this.tokens -= 1;
}
}
Hız Sınırlı Toplu Çözücü
const axios = require("axios");
const API_KEY = process.env.CAPTCHAAI_API_KEY;
const rateLimiter = new TokenBucket(20, 10); // 20 burst, 10/sec sustained
function sleep(ms) {
return new Promise((resolve) => setTimeout(resolve, ms));
}
async function solveCaptchaLimited(sitekey, pageurl) {
// Wait for rate limit token
await rateLimiter.acquire();
const submitResp = await axios.post(
"https://ocr.captchaai.com/in.php",
null,
{
params: {
key: API_KEY,
method: "userrecaptcha",
googlekey: sitekey,
pageurl: pageurl,
json: 1,
},
}
);
if (submitResp.data.status !== 1) {
throw new Error(submitResp.data.request);
}
const captchaId = submitResp.data.request;
for (let i = 0; i < 60; i++) {
await sleep(5000);
const result = await axios.get("https://ocr.captchaai.com/res.php", {
params: { key: API_KEY, action: "get", id: captchaId, json: 1 },
});
if (result.data.status === 1) return result.data.request;
if (result.data.request !== "CAPCHA_NOT_READY") {
throw new Error(result.data.request);
}
}
throw new Error("TIMEOUT");
}
// Solve 100 tasks — rate limiter ensures max 10 submissions/sec
async function batchSolve(tasks) {
const results = await Promise.allSettled(
tasks.map((t) => solveCaptchaLimited(t.sitekey, t.pageurl))
);
const solved = results.filter((r) => r.status === "fulfilled").length;
const failed = results.filter((r) => r.status === "rejected").length;
console.log(`Solved: ${solved}, Failed: ${failed}`);
}
Parametrelerin Seçilmesi
| İş yükü | Kapasite (patlama) | Yeniden dolum oranı (sürekli) |
|---|---|---|
| Hafif kazıma | 5 | 2/sec |
| Standart otomasyon | 20 | 10/sec |
| Yüksek hacimli boru hattı | 50 | 30/sec |
| Maksimum verim | 100 | 50/sec |
Temel kurallar:
- Kapasiteyi 2 × yeniden doldurma hızına ayarlayın (2 saniyelik patlamalara izin verir)
- İhtiyatlı başlayın, hata oranlarını izlerken artırın
- Yalnızca oran sınırı olan gönderimler; oylama hafiftir ve kendi kendini sınırlar
Token Kovası ve Diğer Algoritmalar
| Algoritma | Davranış | Şunun için en iyisi: |
|---|---|---|
| Jeton paketi | Patlama payı ile yumuşak hız | CAPTCHA API çağrıları |
| Sızdıran kova | Sabit çıkış hızı, patlama yok | Katı oran gereksinimleri |
| Sabit pencere | Zaman penceresi başına sayım, kenar patlamaları | Basit sayaçlar |
| Sürgülü pencere | Devam eden süreyi sayın | Doğru oran uygulaması |
Token kovası en iyi varsayılan seçenektir; sürdürülebilir bir oran uygularken doğal patlamalara izin verir (kazıyıcı aynı anda 20 CAPTCHA bulur).
Sorun giderme
| Sorun | Sebep | Düzeltme |
|---|---|---|
| İstekler hâlâ kısıtlanıyor | Hız sınırlayıcı API'nin izin verdiğinden daha yükseğe ayarlandı | CaptchaAI'nin limitlerine uyacak şekilde daha düşük yeniden dolum oranı |
| İsteklerde yüksek gecikme | Jetonlar tükendi, yeniden doldurulmayı bekliyor | Patlama senaryoları için kapasiteyi artırın |
| Bellek büyüyor | Bekleme kuyruğu birikiyor | Maksimum kuyruk boyutunu ayarlayın; fazla istekleri reddet |
| Hız sınırlayıcı işlemler arasında paylaşılmıyor | Yalnızca bellek içi | Dağıtılmış hız sınırlaması için Redis tabanlı jeton grubunu kullanın |
SSS
Gönderimlere, oylamaya veya her ikisine de oran sınırı koymalı mıyım?
Yalnızca oran sınırı gönderimleri. Yoklama istekleri hafiftir ve time.sleep(5) aracılığıyla kendi kendine kısılır. Aşırı sınırlayıcı yoklama artışları gecikmeyi hiçbir fayda sağlamadan çözer.
Hız sınırlamasına rağmen ERROR_TOO_MUCH_REQUESTS'yi nasıl halledebilirim?
Hız sınırınız çok yüksek ayarlanmış. Doldurma oranını düşürün. Ayrıca birden fazla işlemin aynı API anahtarını paylaşıp paylaşmadığını, yani tüm işlemler genelindeki toplam ücreti kontrol edin.
CAPTCHA türüne göre hız sınırlayıcı kullanabilir miyim?
Evet; farklı CAPTCHA türleri için ayrı jeton paketleri oluşturun. Bu, yüksek hacimli reCAPTCHA v2 görevlerinin Turnstile gönderimlerini yetersiz hale getirmesini önler.
İlgili Makaleler
Sonraki Adımlar
Hız kontrollü CAPTCHA çözümü oluşturun —CaptchaAI API anahtarınızı alınve sürdürülebilir talep oranlarının uygulanması.
İlgili kılavuzlar: