Scarnox · Blog

तेज़ captcha solving: अपनी pipeline में latency कैसे कम करें

तेज़ captcha solver वह है जिसे आप सही पल पर, parallel में, बिना requests बर्बाद किए बुला सकें। Scarnox का solve call token तैयार होने पर लौटता है, इसलिए उसकी अवधि captcha के प्रकार, target site और इस समय के load पर निर्भर करती है। यह guide कोई तय समय नहीं वादा करती। यह दिखाती है कि आपके अपने code में आप क्या नियंत्रित करते हैं, उसे कैसे मापें, और कई solves एक साथ कैसे चलाएँ, ताकि जो समय आप खर्च करें वह ठीक से खर्च हो।

Solve समय क्या तय करता है

तीन चीज़ें मायने रखती हैं, और उनमें से केवल एक आपके हाथ में है:

अपनी मेहनत तीसरी चीज़ पर लगाएँ। वही वह हिस्सा है जिसे आप माप और बदल सकते हैं।

Optimise करने से पहले मापें

Call को एक timer में लपेटें और नतीजा लॉग करें। आप solve समय और उसके आसपास आपके code का समय, दोनों जानना चाहते हैं:

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")

इसे उन pages पर चलाएँ जिनकी आपको परवाह है, उन समयों पर जब आप अपने jobs चलाते हैं। नतीजे रखें। वे बताते हैं कि कोई बदलाव सचमुच मदद कर रहा है या नहीं।

Solves को parallel में चलाएँ

Solves स्वतंत्र हैं। अगर आपके पास दस sitekeys हैं, तो हर एक के इंतज़ार में बारी-बारी से रुकना उस समय को बर्बाद करता है जिसे आप दूसरों पर लगा सकते थे। ज़्यादातर scripts के लिए thread pool काफ़ी है, क्योंकि हर solve एक HTTP request है जो ज़्यादातर समय इंतज़ार में बिताती है:

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)

# छोटे से शुरू करें। worker count तभी बढ़ाएँ जब errors कम रहें।
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 count बढ़ाने पर rate या capacity जैसी errors दिखें, तो उसे घटाएँ। Parallelism तभी मदद करता है जब server उसके साथ चल सके।

जल्दी solve न करें

सबसे तेज़ code वह है जो उस token का इंतज़ार नहीं करता जिसकी उसे अभी ज़रूरत नहीं। Tokens पहले से माँगकर स्टोर करना आम गलती है। Tokens जारी होने के लगभग दो मिनट बाद expire हो जाते हैं, इसलिए स्टोर किया हुआ token ज़रूरत के समय अक्सर पुराना होता है। Solve तब करें जब form post होने वाला हो। विस्तृत तर्क captcha token expired: कारण और समाधान में है।

बाकी रास्ते को छोटा रखें

जो खराब नहीं होता उसे दोबारा इस्तेमाल करें

कुछ काम solves के बीच सुरक्षित रूप से साझा हो सकते हैं। इन्हें hot path से बाहर रखें:

ये बदलाव बहुत कम लागत के हैं, और हर call में दिखने वाला overhead हटा देते हैं।

Median नहीं, tail मापें

औसत solve समय उन धीमी calls को छिपा देता है जो batch को रोकती हैं। हर solve का समय रिकॉर्ड करें, फिर median और 95वें percentile को देखें। जो pipeline अपने सबसे धीमे job के समय पर खत्म होती है, वह tail से सीमित है, इसलिए धीमी calls को retry करने के तरीके में छोटा बदलाव median में किसी भी बदलाव से ज़्यादा फ़र्क डाल सकता है:

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]))

हर बदलाव से पहले और बाद में सारांश की तुलना करें। अगर p95 मुश्किल से हिलता है, तो समय आपके code में कहीं और खर्च हो रहा है।

गति के साथ नतीजा भी जाँचें

तेज़ विफलता फिर भी विफलता है। जिन solves में error आता है उन्हें गिनें, और बढ़ती error दर को धीमे होने का संकेत मानें। विफल solves का चार्ज नहीं लगता, पर उन पर बिताया समय फिर भी आपकी pipeline का नुकसान है। पूरा retry पैटर्न captcha solver error handling में है।

अगले कदम