CAPTCHA çözümünü otomatikleştirdiğinizde asıl risk çözüm hızı değil, kontrolsüz istek hacmidir: tek bir döngü hatası ya da koordinasyonsuz bir ekip, siz fark etmeden bütçenizi tüketebilir. Çözüm, isteği sunucuya bırakmadan önce kendi tarafınızda sınırlamaktır. Bu rehber, CaptchaAI ile çalışan üç istemci tarafı hız sınırlama yöntemini çalışır kodla gösterir: token bucket, sliding window ve bütçe tabanlı sınırlayıcı. CaptchaAI planları thread tabanlıdır (ör. BASIC $15/ay, 5 thread); amaç eşzamanlılığı artırmak değil, istek akışınızı öngörülebilir tutmaktır.
Kendi Tarafınızda Sınırlama Ne Zaman İşe Yarar?
Sunucu tarafı eşzamanlılığı yönetse de kontrolü istemcide tutmanız gereken üç tipik neden vardır:
- Maliyeti sabitlemek: Bir döngü hatası ya da beklenmedik hacim artışı aylık harcamanızı sessizce şişirebilir; istemci tarafı sınır buna kesin bir tavan koyar.
- Hedef sitenin hızına uymak: CAPTCHA'sını çözdüğünüz sitenin kendi istek sınırları vardır; bu eşiklerin altında kalmak iş akışınızı kararlı tutar.
- API anahtarını adil paylaştırmak: Aynı anahtarı birden fazla ekip veya iş kullandığında, her birine düşen payı istemcide bölebilirsiniz.
Aşağıdaki tablo, sınır olan ve olmayan durumları karşılaştırır:
| Senaryo | Sınır yok | Sınır var |
|---|---|---|
| Bir hata sonsuz çözüm döngüsü yaratıyor | Bütçeyi hızla tüketir | Belirlenen eşikte durur |
| Birden fazla ekip aynı API anahtarını paylaşıyor | Harcama koordinasyonsuz büyür | Ekip başına adil pay |
| Hedef site 100 req/dk üzerinde yasaklıyor | Hesaplar engellenir | Eşiğin altında kalır |
| Aylık bütçe $50 ile sınırlı | Bir öğleden sonrada aşılabilir | Kesin üst sınır uygulanır |
Yöntem 1: Token Bucket ile Ani Yükleri Yumuşatma
Token bucket, ortalama bir hızı korurken kısa ani yüklere izin verir. Kova sabit hızda dolar; her istek bir token harcar, kova boşalınca istek bekler. Ani trafiği tolere etmesi gereken iş akışları için idealdir.
Python ile token bucket sınırlayıcı
# 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")
rate dakika başına ortalama isteği, capacity ise izin verilen en büyük ani yükü belirler; ikisini iş yükünüze göre ayarlayın.
Token bucket'ı şu durumlarda tercih edin:
- Trafiğiniz düzenli değil, ani yükler halinde geliyorsa (ör. bir kuyruğun bir anda boşaltılması).
- Ortalama hızı korurken kısa süreli yoğunlukları kaybetmeden işlemek istiyorsanız.
- İzin verdiğiniz ani yük payını tek bir
capacitydeğeriyle ayarlamak istiyorsanız.
Yöntem 2: Sliding Window ile Sabit Pencere Sayımı
Sliding window (kayan pencere), sabit bir zaman penceresi içindeki istek sayısını takip eder. Token bucket'tan daha basittir; ani yük payı yoktur ama "5 dakikada en fazla 20 istek" gibi net kurallar için doğru araçtır.
JavaScript ile sliding window sınırlayıcı
// 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');
}
maxRequests ve windowMs dışında ayar yoktur; bu sadelik, ani yük payına ihtiyaç duymadığınız düzenli iş yüklerinde bir avantaja dönüşür.
Yöntem 3: Bütçe Tabanlı Sınırlayıcı
İstek hızı yerine doğrudan parayı sınırlamak istiyorsanız günlük bir bütçe belirleyin ve limit dolduğunda durun. Aşağıdaki cost_per_solve bir tahmindir; CaptchaAI thread tabanlı faturalandırdığından bu değer, aylık plan ücretinizi beklenen çözüm hacmine böldüğünüz etkin birim maliyettir.
# 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
Üretimde daily_spend değerini bir dosyaya veya veritabanına yazın; aksi halde her yeniden başlatma bütçeyi baştan açar.
Hızı ve Bütçeyi Birlikte Katmanlama
Üretimde tek bir yöntem genelde yetmez: token bucket anlık hızı düzgün tutar ama aylık toplam harcamayı görmez; bütçe sınırlayıcı harcamayı bilir ama ani yükleri yumuşatmaz. İkisini üst üste koyarak her iki sınırı da aynı anda uygulayabilirsiniz. Pratik bir kurulum şöyle işler:
- Önce token bucket'ın
acquireçağrısıyla hız sınırını bekleyin. - Token alındıktan sonra
budget.can_solve()ile bütçeyi kontrol edin; bütçe dolmuşsa isteği hiç göndermeyin. - Çözüm başarıyla döndüğünde
budget.record_solve()ile harcamayı işleyin.
Bu sıralama, saniye başına istek hızını ve günlük parasal tavanı tek bir akışta korur. USD cinsinden sabit aylık plan ücretini beklenen çözüm hacmine bölüp bütçeye girdiğinizde, kur dalgalanmasından bağımsız ve öngörülebilir bir maliyet tavanı elde edersiniz.
Hangi Yöntemi Seçmeliyim?
| Yöntem | En uygun olduğu durum | Karmaşıklık |
|---|---|---|
| token bucket | Ani yüklere pay bırakırken düzgün hız kontrolü | Orta |
| sliding window | Zaman penceresi başına basit istek sayımı | Düşük |
| bütçe sınırlayıcı | Günlük, haftalık veya aylık maliyet kontrolü | Düşük |
| birleşik (hız + bütçe) | Üretim sistemleri | Orta |
Çoğu üretim sistemi token bucket ile bütçe sınırlayıcıyı birlikte kullanır: biri hızı, diğeri aylık tavanı korur.
Üretime Almadan Önce
Örnek sınırlayıcılar durumu yalnızca bellekte tutar; gerçek sistemlerde birkaç noktaya dikkat edin:
- Kalıcılık:
daily_spendgibi sayaçları bir dosyaya, Redis'e ya da veritabanına yazın; aksi halde her yeniden başlatma sınırı sıfırlar. - Dağıtık çalışma: Birden fazla worker aynı sınırı paylaşacaksa, sayacı tüm süreçlerin eriştiği ortak bir depoda tutun; süreç başına ayrı sayaç, toplam sınırı sessizce katlar.
- Gözlemlenebilirlik: Kaç isteğin sınıra takıldığını loglayın. Sürekli bekleyen istekler, sınırın gerçek talebe göre çok düşük ayarlandığının işaretidir.
- Yalnızca gönderimi sınırlayın: Sorgulama (
res.php) istekleri yeni görev yaratmaz ve ek maliyet doğurmaz; sınırı yalnızca gönderim (in.php) isteklerine uygulayın.
Sorun Giderme
| Sorun | Sebep | Düzeltme |
|---|---|---|
| Tüm istekler kuyruğa alınıyor, hiçbiri çalışmıyor | Hız, talebe göre çok düşük | Oranı veya pencere boyutunu artırın |
| Bütçe sınırlayıcı gün ortasında sıfırlanıyor | Sistem saati değişti veya süreç yeniden başladı | Günlük harcamayı dosyaya ya da veritabanına kalıcı yazın |
| Token bucket bir anda boşalıyor | Kapasite iş akışı için çok küçük | capacity parametresini artırın |
| Sınırlayıcı sorgulama isteklerini de engelliyor | Sınır, sorgulamaya da uygulanmış | Yalnızca gönderme (in.php) isteklerini sınırlayın |
SSS
Token bucket mı yoksa sliding window mı kullanmalıyım?
Trafiğiniz düzensiz ve ani yükler içeriyorsa token bucket'ı seçin; ortalama hızı korurken bu yükleri emer. Kural "X dakikada en fazla N istek" kadar basitse sliding window daha az kodla aynı işi görür.
cost_per_solve değerini neye göre ayarlamalıyım?
CaptchaAI thread tabanlı faturalandırır (ör. BASIC $15/ay, 5 thread), yani çözüm başına ücret yoktur. Aylık plan ücretinizi tahmini çözüm hacminize bölerek etkin birim maliyeti girin.
Hız sınırını birden fazla worker arasında nasıl paylaşırım?
Durumu tek süreçte tutan bu örnekler dağıtık çalışmaz. Redis destekli bir sınırlayıcı kullanın: rate-limiter-flexible (Node.js) veya redis tabanlı bir sayaç (Python), sınırı tüm worker'lar arasında atomik olarak paylaştırır.
CaptchaAI zaten eşzamanlılığı yönetiyorsa neden kendim sınırlayayım?
Sunucu tarafı ölçeği yönetir ama bütçenizi bilmez. İstemci tarafı sınır; bir hatanın bütçeyi tüketmesini, ekiplerin çakışmasını veya hedef sitenin sizi engellemesini önler.
Hız sınırına takılan istekleri nasıl ele almalıyım?
acquire zaman aşımına uğradığında isteği hemen düşürmek yerine kısa bir kuyruğa alın ya da üstel geri çekilme (exponential backoff) ile yeniden deneyin. Böylece geçici yoğunlukta istek kaybetmez, sınırın altına iner inmez işleme devam edersiniz.
İlgili Makaleler
Sonraki Adımlar
İstek hızınızı ve bütçenizi bugün kontrol altına alın — CaptchaAI API anahtarınızı alın.
İlgili kılavuzlar: