Hızlı captcha çözme: pipeline'ınızdaki gecikmeyi nasıl azaltırsınız
Hızlı bir captcha solver, doğru anda, paralel olarak ve boşa istek göndermeden çağırabildiğiniz bir solver'dır. Scarnox çözme çağrısı token hazır olduğunda döner; bu yüzden süresi captcha türüne, hedef siteye ve anlık yüke bağlıdır. Bu rehber sabit bir süre vaat etmez. Kendi kodunuzda neyi kontrol ettiğinizi, nasıl ölçeceğinizi ve birçok çözümü aynı anda nasıl çalıştıracağınızı gösterir; böylece harcadığınız zaman iyi değerlendirilir.
Çözme süresini neler belirler
Üç şey önemlidir ve bunlardan yalnızca biri sizin elinizdedir:
- Captcha'nın kendisi. Bazı doğrulama türleri diğerlerinden uzun sürer. Bu, kodunuzun değil sitenin captcha'sının bir özelliğidir.
- Solver üzerindeki yük. Yoğun bir dönem tek bir çağrıyı yavaşlatabilir. Retry mantığı bunu ele almalıdır; çağrıyı erken bırakmamalıdır.
- Kendi pipeline'ınız. Çok erken çözmek, her isteği sıraya koymak ve ilgisiz işi beklemek, kaldırabileceğiniz süreyi ekler.
Çabanızı üçüncü maddeye yöneltin. Ölçebildiğiniz ve değiştirebildiğiniz kısım odur.
Optimize etmeden önce ölçün
Çağrıyı bir zamanlayıcıyla sarın ve sonucu loglayın. Hem çözme süresini hem de kodunuzun çağrının etrafında harcadığı süreyi bilmek istersiniz:
import time
import requests
API_KEY = "scarnox_YOURAPIKEY"
URL = "https://api.scarnox.com/api/tasks/create"
def timed_solve(sitekey: str, page_url: str) -> dict:
started = time.perf_counter()
r = requests.post(
URL,
headers={"Authorization": f"Bearer {API_KEY}"},
json={
"captcha_type": "PopularCaptchaTaskProxyless",
"site_key": sitekey,
"site_url": page_url,
},
timeout=185,
)
elapsed = time.perf_counter() - started
data = r.json()
if data.get("errorId") != 0:
return {"ok": False, "error": data.get("errorCode"), "seconds": elapsed}
return {"ok": True, "token": data["solution"]["token"], "seconds": elapsed}
result = timed_solve("10000000-ffff-ffff-ffff-000000000001", "https://example.com/signup")
print(result["ok"], round(result["seconds"], 2), "s")
Bunu ilgilendiğiniz sayfalara, işlerinizi çalıştırdığınız saatlerde karşı çalıştırın. Sayıları saklayın. Bir değişikliğin gerçekten yardımcı olup olmadığını onlar gösterir.
Çözümleri paralel çalıştırın
Çözümler birbirinden bağımsızdır. On sitekey'iniz varsa her birini sırayla beklemek, diğerleri için kullanabileceğiniz zamanı harcar. Her çözüm, süresinin çoğunu beklemekle geçiren tek bir HTTP isteği olduğu için çoğu script için bir thread havuzu yeterlidir:
from concurrent.futures import ThreadPoolExecutor
jobs = [
("10000000-ffff-ffff-ffff-000000000001", "https://example.com/signup"),
("10000000-ffff-ffff-ffff-000000000001", "https://example.com/register"),
("10000000-ffff-ffff-ffff-000000000001", "https://example.com/contact"),
]
def run(job):
sitekey, page_url = job
return timed_solve(sitekey, page_url)
# Küçük başla. Worker sayısını yalnızca hatalar düşük kaldığı sürece artır.
with ThreadPoolExecutor(max_workers=5) as pool:
results = list(pool.map(run, jobs))
for r in results:
status = "ok" if r["ok"] else r["error"]
print(f"{r['seconds']:.2f} s {status}")
Worker sayısını artırdığınızda hız ya da kapasite sorununa benzeyen hatalar görürseniz sayıyı düşürün. Paralellik yalnızca sunucu ona yetişebildiğinde yardımcı olur.
Erken çözmeyin
En hızlı kod, henüz kullanmayacağı bir token için beklemeyen koddur. Token'ları önceden isteyip saklamak en yaygın hatadır. Token'lar verildikten yaklaşık iki dakika sonra süresi dolar; bu yüzden saklanan bir token, ihtiyaç duyduğunuzda çoğu zaman bayatlamıştır. Formu göndermek üzereyken çözün. Ayrıntılı gerekçe için captcha token süresi doldu: nedenler ve çözümler rehberine bakın.
Yolun geri kalanını kısa tutun
- Her site için tek bir HTTP oturumu kullanın; her istekte yeniden bağlanmayın.
- Çözme ile gönderim arasında yavaş ayrıştırma ya da veritabanı işi yapmayın.
- Kendi isteklerinizde makul bir zaman aşımı kullanın. Çözme çağrısı token hazır olana kadar bloke olduğu için yaklaşık 185 saniye kullanır. Diğer çağrılarınız çok daha kısa olmalıdır.
- Proxy'yi yalnızca görev bunu gerektirdiğinde gönderin. Proxy görev türleri
http://user:pass@host:portbiçiminde birproxyalanı alır; ama proxy eklemek tek başına bir hızlandırma değildir.
Süresi dolmayan şeyleri yeniden kullanın
Bazı işler çözümler arasında güvenle paylaşılabilir. Bunları sıcak yoldan uzak tutun:
- Sitekey'ler. Sitekey'i sayfa şablonu başına bir kez okuyup saklayın. Token gibi süresi dolmaz. Yalnızca form hata vermeye başladığında yeniden okuyun.
- HTTP bağlantıları. Keep-alive'lı bir oturum, her çağrıda yeni bir TLS el sıkışmasını önler. İstek başına bir tane değil, thread ya da worker başına bir oturum oluşturun.
- Ayrıştırılmış yapılandırma. Hedef listenizi, proxy listenizi ve ayarlarınızı açılışta bir kez yükleyin; çözme fonksiyonunun içinde dosya okumayın.
Bu değişikliklerin maliyeti düşüktür ve her çağrıda oluşan yükü ortadan kaldırır.
Ortalamayı değil kuyruğu ölçün
Ortalama çözme süresi, bir toplu işi tutan yavaş çağrıları gizler. Her çözme süresini kaydedin, sonra ortanca değere ve 95. yüzdelik dilime bakın. Bir pipeline en yavaş işinin süresinde biter ise darboğaz kuyruktur; bu yüzden yavaş çağrıları nasıl yeniden denediğinizde yapılan küçük bir değişiklik, ortancadaki herhangi bir değişiklikten daha önemli olabilir:
import statistics
def summarise(seconds: list[float]) -> str:
ordered = sorted(seconds)
p95 = ordered[int(0.95 * (len(ordered) - 1))]
return f"median {statistics.median(ordered):.2f} s, p95 {p95:.2f} s, n={len(ordered)}"
print(summarise([r["seconds"] for r in results]))
Her değişiklikten önce ve sonra özeti karşılaştırın. P95 neredeyse hiç değişmiyorsa, zaman kodunuzun başka bir yerinde harcanıyordur.
Hıza değil sonuca bakın
Hızlı bir başarısızlık yine de bir başarısızlıktır. Hata dönen çözümleri sayın ve hata oranı yükselirse bunu yavaşlamanız için bir sinyal olarak görün. Başarısız çözümler ücretlendirilmez, ama onlarda harcanan süre yine de pipeline'ınızın kaybettiği zamandır. Tam yeniden deneme kalıbı captcha solver hata yönetimi rehberinde yer alır.