Captcha token expired: कारण और इसे कैसे ठीक करें
Captcha token एक अल्पकालिक प्रमाण है कि challenge पास हुआ था। Scarnox के PopularCaptcha tokens जारी होने के लगभग दो मिनट बाद expire हो जाते हैं। अगर आप उस window के बाद token submit करते हैं, तो site form को reject कर देती है, अक्सर यह संदेश दिखाकर कि captcha expire हो गया है या अमान्य है। समाधान लगभग हमेशा समय का मामला होता है: solve को submit के जितना हो सके पास रखें, हर token एक बार इस्तेमाल करें, और retry तभी करें जब पक्का हो कि पहला प्रयास स्वीकार नहीं हुआ।
Tokens क्यों expire होते हैं
Token स्थायी credential नहीं है। Site जानना चाहती है कि कोई इंसान (या उसकी ओर से काम करने वाला solver) challenge हाल ही में पूरा कर चुका है, इसलिए वह token को छोटी उम्र देती है। घड़ी token जारी होने पर शुरू होती है, न कि जब आप पहली बार API call करते हैं। Solve और submit के बीच जो भी होता है, वह दो मिनट में से खर्च होता है।
आम कारण
- बहुत पहले solve करना। Tokens का batch पहले से बनाकर बाद के लिए रखना सबसे आम कारण है। जब तक token इस्तेमाल होता है, वह पुराना हो चुका होता है।
- Solve और submit के बीच धीमा code। लंबा database write, queue, या form post से पहले रखा गया
time.sleeptoken को उसकी window से आगे धकेल सकता है। - Token दोबारा इस्तेमाल करना। जो token पहले ही स्वीकार हो चुका है, या जिसे किसी विफल प्रयास ने इस्तेमाल कर लिया, वह फिर काम नहीं करेगा। हर token को एक बार इस्तेमाल होने वाला मानें।
- Page दोबारा लोड करना। अगर solve के बाद page refresh हो जाए, तो form नई challenge जारी कर सकता है और आपके पास का token अमान्य हो सकता है।
समाधान: submit से ठीक पहले solve करें
सबसे सरल भरोसेमंद पैटर्न है solve और submit को एक कदम बनाना। Token माँगें, उसे form में डालें, form post करें, और बीच में कुछ धीमा न करें:
import requests
API_KEY = "scarnox_YOURAPIKEY"
CREATE_URL = "https://api.scarnox.com/api/tasks/create"
def fresh_token(sitekey: str, page_url: str) -> str:
r = requests.post(
CREATE_URL,
headers={"Authorization": f"Bearer {API_KEY}"},
json={
"captcha_type": "PopularCaptchaTaskProxyless",
"site_key": sitekey,
"site_url": page_url,
},
timeout=185, # token तैयार होने तक call रुकती है
)
data = r.json()
if data.get("errorId") != 0:
raise RuntimeError(f"{data.get('errorCode')}: {data.get('errorDescription')}")
return data["solution"]["token"]
def submit_form(page_url: str, sitekey: str, form: dict) -> requests.Response:
token = fresh_token(sitekey, page_url) # post से ठीक पहले solve करें
return requests.post(
page_url,
data={**form, "h-captcha-response": token, "g-recaptcha-response": token},
timeout=30,
)
ध्यान दें कि submit_form token को cache या queue में नहीं रखता। वह एक माँगता है, उसे post करता है, और आगे बढ़ जाता है। विफल solves का चार्ज नहीं लगता, इसलिए विफल request की solve-side पर कोई कीमत नहीं।
सुरक्षित रूप से retry करें
कुछ sites expire हुए token को साफ़ response से reject करती हैं। दूसरी sites एक सामान्य page लौटाती हैं जिसमें अंदर एक error संदेश होता है, इसलिए अकेला status code कुछ नहीं बताता। जिस response को site expire हुए token के लिए असल में लौटाती है, उसे देखें और अपनी जाँच उसी पर बनाएँ। Retry loop ऐसा दिख सकता है:
def submit_with_retry(page_url: str, sitekey: str, form: dict, attempts: int = 2):
for _ in range(attempts):
resp = submit_form(page_url, sitekey, form)
if resp.status_code < 400 and "captcha" not in resp.text.lower():
return resp # स्वीकार हुआ, इस site के response के अनुसार
raise RuntimeError("captcha token rejected after retries")
ऐसे forms पर retry सावधानी से करें जो कुछ बनाते हैं। अगर पहला प्रयास सचमुच स्वीकार हो गया था, पर आपके code ने response गलत पढ़ा, तो retry एक duplicate account, order या message बना सकता है। केवल तभी retry करें जब आप पक्के हों कि पहली post स्वीकार नहीं हुई, और जाँच उसी site के लिए विशिष्ट बनाएँ जिस पर आप काम कर रहे हैं।
समय को ईमानदार रखें
- Tokens का loop बनाकर उन्हें बाद में इस्तेमाल करने के लिए solve न करें। हर submit के लिए solve करें।
- Solve और post के बीच का काम न्यूनतम रखें।
- Solve request पर लगभग 185 सेकंड का timeout रखें, क्योंकि call token तैयार होने तक रुकती है। आपकी अपनी form post पर अलग timer token की उम्र से काफ़ी छोटा होना चाहिए।
- तेज़ pipeline चाहिए तो captcha solving की गति देखें, जो बिना tokens स्टोर किए parallel solves कवर करती है।
आम गलतियाँ
- Tokens को dictionary या Redis में बाद के लिए cache करना। यह cache तब तक हानिरहित लगता है जब तक कोई token उसकी window के बाद इस्तेमाल न हो और हर submit फ़ेल होने लगे।
- Session में एक बार solve करना। लंबे समय तक चलने वाला session भी हर form post के लिए नया token चाहता है, क्योंकि हर post अपनी challenge जाँच चला सकता है।
- Solve और submit के बीच सोना। Solve के बाद रखा गया rate limiter या जानबूझकर का विराम token की उम्र खर्च करता है। किसी भी pacing को solve से पहले रखें।
- हर विफलता को एक जैसा मानना। आपकी तरफ़ का timeout, reject हुआ token और site की error तीनों को अलग-अलग संभालने की ज़रूरत है। उन्हें अलग-अलग लॉग करें।
पर्याप्त लॉग रखें ताकि कारण पता चले
जब submit विफल हो, तो token जारी होने का समय, form post होने का समय, HTTP status और response के पहले कुछ सौ अक्षर रिकॉर्ड करें। इन चार मानों से आप एक नज़र में बता सकते हैं कि token expire हुआ या site ने किसी और कारण से reject किया। साझा logs में पूरा token न लिखें, क्योंकि एक वैध token उस एक challenge के लिए credential है।
अगर अब भी विफल हो तो क्या जाँचें
- Token मिलने और form post के बीच का समय प्रिंट करें।
- पक्का करें कि
site_urlउस page से मेल खाता है जिस पर captcha दिखता है। - पक्का करें कि sitekey मौजूदा page से पढ़ी गई है, पुरानी copy से नहीं।
- Form field के नाम जाँचें। PopularCaptcha tokens
h-captcha-responseमें जाते हैं, और अक्सरg-recaptcha-responseमें भी।
सभी error responses और हर एक को संभालने का पूरा तरीका captcha solver error handling में है।