Scarnox · Blog

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:

Ç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

Süresi dolmayan şeyleri yeniden kullanın

Bazı işler çözümler arasında güvenle paylaşılabilir. Bunları sıcak yoldan uzak tutun:

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.

Sonraki adımlar