तेज़ captcha solving: अपनी pipeline में latency कैसे कम करें
तेज़ captcha solver वह है जिसे आप सही पल पर, parallel में, बिना requests बर्बाद किए बुला सकें। Scarnox का solve call token तैयार होने पर लौटता है, इसलिए उसकी अवधि captcha के प्रकार, target site और इस समय के load पर निर्भर करती है। यह guide कोई तय समय नहीं वादा करती। यह दिखाती है कि आपके अपने code में आप क्या नियंत्रित करते हैं, उसे कैसे मापें, और कई solves एक साथ कैसे चलाएँ, ताकि जो समय आप खर्च करें वह ठीक से खर्च हो।
Solve समय क्या तय करता है
तीन चीज़ें मायने रखती हैं, और उनमें से केवल एक आपके हाथ में है:
- Captcha खुद। कुछ challenge प्रकार दूसरों से ज़्यादा समय लेते हैं। यह site के captcha की विशेषता है, आपके code की नहीं।
- Solver पर load। व्यस्त समय में एक अकेली call धीमी हो सकती है। Retry logic को इसे संभालना चाहिए, न कि call को जल्दी छोड़ना चाहिए।
- आपकी अपनी pipeline। Token से पहले solve करना, हर request को क्रम से चलाना और असंबंधित काम का इंतज़ार करना, ये सब समय जोड़ते हैं जिसे आप हटा सकते हैं।
अपनी मेहनत तीसरी चीज़ पर लगाएँ। वही वह हिस्सा है जिसे आप माप और बदल सकते हैं।
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: कारण और समाधान में है।
बाकी रास्ते को छोटा रखें
- हर site के लिए एक HTTP session रखें, ताकि हर request पर फिर से connect न करना पड़े।
- Solve और post के बीच धीमा parsing या database का काम न करें।
- अपनी बाकी requests पर एक समझदार timeout रखें। Solve call लगभग 185 सेकंड लेती है, क्योंकि वह token तैयार होने तक रुकती है। आपकी बाकी calls उससे काफ़ी छोटी होनी चाहिए।
- Proxy केवल तभी भेजें जब task को उसकी ज़रूरत हो। Proxy task types में
proxyfieldhttp://user:pass@host:portफ़ॉर्मेट में लेता है, पर अकेले proxy जोड़ना गति बढ़ाने का तरीका नहीं है।
जो खराब नहीं होता उसे दोबारा इस्तेमाल करें
कुछ काम solves के बीच सुरक्षित रूप से साझा हो सकते हैं। इन्हें hot path से बाहर रखें:
- Sitekeys। Sitekey एक बार हर page template से पढ़ें और स्टोर करें। वह token की तरह expire नहीं होती। उसे केवल तब दोबारा पढ़ें जब form फ़ेल होने लगे।
- HTTP connections। Keep-alive वाला session हर call पर नया TLS handshake बचाता है। हर thread या worker के लिए एक session बनाएँ, हर request के लिए नहीं।
- Parsed configuration। Target list, proxy list और settings को start-up पर एक बार लोड करें, solve function के भीतर files न पढ़ें।
ये बदलाव बहुत कम लागत के हैं, और हर 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 में है।