Playwright में ALTCHA कैसे हल करें और hidden फ़ील्ड कैसे भरें

Playwright में ALTCHA हल करने के लिए आप विजेट से यह काम कभी नहीं करवाते। ALTCHA पहचान नहीं, proof of work है: साइट एक हैशिंग समस्या देती है और जो भी उसका सही जवाब देता है उसे अंदर जाने दिया जाता है, और CPU का समय ही उसकी कीमत है। यहाँ न कुछ देखने को होता है, न क्लिक करने को, इसलिए ब्राउज़र बाकी flow के लिए है, कैप्चा के लिए नहीं। पेज ने जो challenge पहले ही माँग लिया है उसे पकड़ें, उसे अपनी ही मशीन पर मिलीसेकंड में हैश करें, फिर जवाब उस फ़ील्ड में लिख दें जिसे फ़ॉर्म सबमिट करता है। यह गाइड यही काम Playwright for Python में करती है।
आपको क्या चाहिए
- CapSkip 1.2.6 या उसके बाद का वर्शन, किसी Windows मशीन पर चलता हुआ। ALTCHA सपोर्ट उसी रिलीज़ में आया था, इसलिए पुराने बिल्ड में कॉल करने के लिए कोई मेथड ही नहीं है।
- Python 3.10 या उससे नया, जिसमें Playwright और CapSkip पैकेज इंस्टॉल हों और कम से कम एक ब्राउज़र डाउनलोड किया गया हो।
- उस पेज का URL जिस पर विजेट लगा है। आपको sitekey की ज़रूरत नहीं, क्योंकि ALTCHA में sitekey होता ही नहीं।
- सॉल्वर का एक पता। Local मोड सिर्फ़ उसी डिवाइस के लिए 127.0.0.1 पर जवाब देता है, और Server मोड आपके नेटवर्क पते या पब्लिक IP पर सुनता है ताकि कोई कंटेनर, कोई CI रनर या कोई दूसरी मशीन उसी API के ज़रिए उस तक पहुँच सके। Step 4 में बताया गया है कि कौन-सा लागू होता है, और दोनों एक ही जगह मिलते हैं: कनेक्शन सेटिंग्स.
# pip install playwright capskip pip install playwright capskip playwright install chromium
Step 1: पेज खुला रहते हुए challenge पकड़ें
बाकी सब कुछ इसी एक वैल्यू पर टिका है। challenge एक छोटा JSON डॉक्यूमेंट होता है जिसमें एक algorithm, एक challenge हैश, एक salt, एक सिग्नेचर और एक अधिकतम संख्या होती है, और साइट उस पर साइन करती है। किसी Playwright रन के भीतर से इसे हासिल करने के दो तरीके हैं, और कौन-सा चलेगा यह इस पर निर्भर करता है कि पेज कैसे बना है।
विजेट से endpoint पढ़ें
विजेट एलिमेंट खुद बताता है कि वह किस endpoint से पूछेगा। एट्रिब्यूट का अंदाज़ा मत लगाइए, क्योंकि विजेट की पीढ़ियों के बीच यह बदल चुका है।
| Widget पीढ़ी | वह attribute जो challenge का नाम बताता है |
|---|---|
| v1 और v2 | endpoint के लिए challengeurl, और जब challenge इनलाइन हो तब अलग challengejson attribute |
| v3 और उसके बाद | challenge, और वही एक एट्रिब्यूट या तो URL लेता है या challenge डेटा |
# pip install playwright capskip
from playwright.sync_api import sync_playwright
PAGE_URL = "https://example.com/signup"
with sync_playwright() as p:
browser = p.chromium.launch(headless=True)
page = browser.new_page()
page.goto(PAGE_URL)
# v1 and v2 use challengeurl; v3 and later use challenge.
widget = page.locator("altcha-widget")
endpoint = widget.get_attribute("challengeurl")
if not endpoint:
endpoint = widget.get_attribute("challenge")विजेट के type एट्रिब्यूट पर मौजूद तीनों इंटरैक्शन स्टाइल, native, checkbox और switch, पूरी तरह विज़ुअल हैं। ये एक ही payload भेजते हैं और यह फ़र्क़ सॉल्वर तक कभी पहुँचता ही नहीं, इसलिए आपको यह पता लगाने की ज़रूरत नहीं कि आप किसे देख रहे हैं। अलग से मौजूद display एट्रिब्यूट भी इसी तरह सिर्फ़ विज़ुअल है। ALTCHA इन सबका ब्यौरा यहाँ देता है: अपनी खुद की विजेट गाइड.
या फिर वह रिस्पॉन्स पकड़ें जो पेज पहले ही ले चुका है
attribute पढ़ लेना हमेशा काफ़ी नहीं होता। कोई v3 widget उस attribute में URL के बजाय challenge डेटा रख सकता है, इसलिए जब value ब्रेस से शुरू हो तो उसे JSON के रूप में parse करें, और पूरी तरह JavaScript से configure हुआ widget markup में पढ़ने लायक़ कुछ छोड़ता ही नहीं। network response पकड़ लेना इस दूसरी सूरत को सँभाल लेता है, और वह आपको पॉइंटर नहीं, पूरा document देता है। जो भी चीज़ fetch शुरू करती है, उससे पहले wait तैयार कर लें, वरना request तब चली जाएगी जब कोई सुन ही नहीं रहा होगा।
# Filter out the widget's own script: its URL also contains
# altcha, and it loads before the challenge is ever requested.
is_challenge = lambda r: ("altcha" in r.url
and "json" in r.headers.get("content-type", ""))
# This fires during navigation only when the widget carries
# auto="onload". Otherwise wrap the click that triggers it.
with page.expect_response(is_challenge) as caught:
page.goto(PAGE_URL)
challenge = caught.value.json()
print(challenge["algorithm"], challenge["maxnumber"])उस शेप पर भरोसा करने से पहले विजेट का auto एट्रिब्यूट देख लें। यही तय करता है कि वेरिफ़िकेशन कब शुरू होगा, और सिर्फ़ onload वैल्यू नेविगेशन के दौरान रिक्वेस्ट भेजती है। अगर यह छोड़ दिया गया हो, या onfocus या onsubmit पर सेट हो, तो जब तक कोई फ़ॉर्म को छूता नहीं तब तक कुछ भी fetch नहीं होता, इसलिए wait को goto के आसपास नहीं, बल्कि विजेट पर होने वाले क्लिक के आसपास तैयार करें।
पूरे URL के बजाय किसी सबस्ट्रिंग पर मैच करें, लेकिन अकेले altcha शब्द पर कभी नहीं। पाथ हर साइट पर अलग होता है और अक्सर उसमें cache-busting क्वेरी स्ट्रिंग भी लगी होती है, इसलिए पूरा मिलान करना एक वजह है कि यह कभी चलता ही नहीं, और दूसरी वजह है बहुत ढीला मैच करना: विजेट स्क्रिप्ट आम तौर पर ऐसे ही पाथ से आती है जिसमें altcha होता है, वह सबसे पहले लोड होती है, और तब wait ऐसे JavaScript पर पूरा हो जाता है जिसे कोई JSON पार्सर स्वीकार नहीं करेगा। Playwright इस पैटर्न को यहाँ कवर करता है: अपनी नेटवर्क गाइड.
Step 2: challenge को ALTCHA के उस एकमात्र मेथड को सौंपें
सिर्फ़ एक मेथड, जिसका पूरा ब्यौरा ALTCHA सॉल्वर पेजपर दिया गया है, और यह challenge को दोनों में से किसी भी रूप में लेता है। endpoint पास करें तो सॉल्वर खुद challenge ले आता है। डॉक्यूमेंट पास करें तो कोई रिक्वेस्ट बाहर जाती ही नहीं।
from capskip import CapSkip solver = CapSkip(host="127.0.0.1", port=8080) # The document from step 1, so nothing is fetched twice. result = solver.altcha(url=PAGE_URL, challenge_json=challenge) # Or hand over the endpoint and let CapSkip fetch it. # result = solver.altcha(url=PAGE_URL, challenge_url=endpoint) print(result["token"]) # base64 payload for the form field print(result["number"]) # the counter that satisfied it
जब ब्राउज़र उसे पहले ही देख चुका हो, तो inline डॉक्यूमेंट को प्राथमिकता दें। यही वह एक जगह है जहाँ ब्राउज़र चलाने से सलाह बदल जाती है। जो challenge आपके ब्राउज़र सेशन को जारी हुआ है, साइट आपको उसी पर परखेगी, इसलिए सॉल्वर को ठीक वही डॉक्यूमेंट देने से दोनों एक-दूसरे के साथ बने रहते हैं। किसी endpoint से दूसरा challenge लाना ग़लत नहीं है, लेकिन इसका मतलब है कि पेज के पास अब एक challenge है जबकि आप किसी दूसरे का जवाब दे रहे हैं, और ऐसी साइट पर जो challenge को सेशन से बाँधती है, जवाब मेल नहीं खाएगा। यह ऑप्शन एक डिक्शनरी लेता है, जिसे आपके लिए सीरियलाइज़ कर दिया जाता है, या अगर आपके पास पहले से है तो एक JSON स्ट्रिंग।
उस नतीजे में दो कीज़ सिर्फ़ ALTCHA के लिए होती हैं। token की में वह base64 payload होता है जो फ़ॉर्म को चाहिए, और number की में वह काउंटर होता है जिसने challenge हल किया। code की में टोकन वाली ही स्ट्रिंग होती है, इसलिए दोनों में से कोई भी चलेगा, लेकिन token की का नाम उसी फ़ील्ड पर है जिसमें वह जाता है। GeeTest की कीज़ और Turnstile का यूज़र एजेंट यहाँ मौजूद नहीं होते।
solver किन algorithm को कवर करता है
लेगेसी स्कीम SHA-1, SHA-256, SHA-384 और SHA-512 के साथ कवर है, और proof-of-work v2 PBKDF2 तथा iterative SHA के साथ। PBKDF2 वही डिफ़ॉल्ट है जिसकी सिफ़ारिश खुद ALTCHA करता है, इसलिए ज़्यादातर लाइव साइटें यही इस्तेमाल करती हैं।
Argon2id और scrypt अपवाद हैं, और इन्हें आज़माया नहीं जाता बल्कि मना कर दिया जाता है: इनमें से किसी की माँग करने वाला challenge करीब एक तिहाई सेकंड में ERROR_CAPTCHA_UNSOLVABLE बनकर लौटता है और उसे कभी दोबारा नहीं आज़माया जाता, क्योंकि मेमरी-हार्ड फ़ंक्शन ऐसी चीज़ नहीं जिसे retry ठीक कर दे। इस type पर वह नतीजा किसी अपठनीय इमेज की नहीं, बल्कि algorithm की ओर इशारा करता है, और इस error code के लिए मौजूद है अपनी एक अलग गाइड.
Step 3: टोकन को विजेट के hidden फ़ील्ड में लिखें
विजेट अपना payload एक hidden इनपुट में सबमिट करता है, जिसका नाम उसके अपने name एट्रिब्यूट से आता है और डिफ़ॉल्ट रूप से altcha होता है। मान लेने के बजाय उस एट्रिब्यूट को पढ़ें, ठीक वैसे ही जैसे आपने challenge वाला पढ़ा था। ब्राउज़र रन में यह फ़ील्ड आप खुद भरते हैं, क्योंकि विजेट ने कुछ वेरिफ़ाई नहीं किया और वह कुछ भरकर नहीं रखेगा।
# Walk up from the submit button so the field lands in the
# form that actually posts, not in the first form on the page.
SET_ALTCHA_FIELD = """({name, token}) => {
const button = document.querySelector('button[type=submit]');
const form = button ? button.form : document.querySelector('form');
let field = form.querySelector('[name=' + name + ']');
if (!field) {
field = document.createElement('input');
field.type = 'hidden';
field.name = name;
form.appendChild(field);
}
field.value = token;
}"""
field_name = widget.get_attribute("name") or "altcha"
page.evaluate(SET_ALTCHA_FIELD, {"name": field_name, "token": result["token"]})
page.click("button[type=submit]")सही फ़ॉर्म चुनें। साइनअप पेज पर अक्सर कई फ़ॉर्म होते हैं, और अगर सबमिट बटन किसी दूसरे फ़ॉर्म का है और आप फ़ील्ड पेज के पहले फ़ॉर्म में जोड़ देते हैं, तो सर्वर को वैल्यू दिखती ही नहीं। स्निपेट ठीक इसी वजह से सबमिट बटन से ऊपर की ओर चलता है।
स्ट्रिंग को जैसी है वैसी ही आगे भेजें। टोकन एक JSON डॉक्यूमेंट का base64 है जिसके फ़ील्ड सर्वर के HMAC सिग्नेचर के दायरे में आते हैं, इसलिए सफ़ाई जैसी दिखने वाली हर चीज़ उसे तोड़ देती है: व्हाइटस्पेस हटाना, डिकोड करके दोबारा एनकोड करना, या कीज़ को किसी और क्रम में रखकर JSON दोबारा बनाना। कुछ इंटीग्रेशन payload को फ़ॉर्म फ़ील्ड के बजाय किसी JSON बॉडी फ़ील्ड से पढ़ते हैं, और विजेट को इस तरह भी कॉन्फ़िगर किया जा सकता है कि वह इसे कुकी में दे, इसलिए देखें कि पेज का अपना सबमिट क्या भेजता है और वही दोहराएँ।
एक चीज़ जो ब्राउज़र जोड़ता है और सादा HTTP क्लाइंट नहीं: पेज फ़ॉर्म पर अपनी खुद की स्क्रिप्ट चला सकता है। अगर सबमिट बटन डिसेबल्ड ही रहता है, तो पेज फ़ील्ड पढ़ने के बजाय यह सुनने का इंतज़ार कर रहा है कि विजेट सफल हुआ। यहाँ दो ईमानदार जवाब हैं, और आप कौन-सा चुनेंगे यह इस पर निर्भर है कि पेज का कितना हिस्सा आप बनाए रखना चाहते हैं। या तो आप पता लगाएँ कि पेज किस चीज़ को सुनता है और उसे पूरा कर दें, या बटन छोड़कर फ़ॉर्म के फ़ील्ड सीधे ब्राउज़र की कुकीज़ के साथ पोस्ट कर दें, जो आम तौर पर छोटा रास्ता है और हमेशा ज़्यादा टिकाऊ।
Step 4: Playwright के CI पर चले जाने के बाद सॉल्वर कहाँ चलता है
ऊपर के सैंपल 127.0.0.1 इस्तेमाल करते हैं, क्योंकि जब तक आपकी स्क्रिप्ट और CapSkip एक ही मशीन पर हैं तब तक यही सही है। सॉल्वर को आपका Python कोड कॉल करता है, न ब्राउज़र और न पेज, इसलिए पता क्या होगा यह इस बात से तय होता है कि टेस्ट प्रोसेस कहाँ चल रही है। Playwright में इसे भूल जाना आसान है, क्योंकि ब्राउज़र तो अक्सर पहले से ही कहीं और होता है।
उसी प्रोसेस को आधिकारिक Playwright Docker इमेज में या किसी CI रनर पर ले जाइए और लूपबैक अब कंटेनर की ओर इशारा करेगा, जहाँ कोई सुन नहीं रहा, इसलिए पहला ही solve NetworkException उठाएगा। CapSkip को Server मोड पर बदल दें और वह इसके बजाय आपके नेटवर्क पते या पब्लिक IP पर सुनेगा, और कंटेनर उसी HTTP API के ज़रिए जुड़ जाएगा। जब रास्ता इंटरनेट से होकर जाता है तो स्टैटिक पब्लिक IP की सलाह दी जाती है, साथ में ऐसा फ़ायरवॉल नियम जो सिर्फ़ उन्हीं पतों को इजाज़त दे जिनकी आप उम्मीद करते हैं। Server मोड सिर्फ़ यह बदलता है कि सॉल्वर कहाँ सुनता है, और कुछ नहीं: हार्डवेयर अब भी आपका ही है और वह अब भी बिना मीटर के है।
| Python प्रोसेस कहाँ चलती है | कौन-सा कनेक्शन मोड |
|---|---|
| CapSkip मशीन पर, किसी लोकल ब्राउज़र को चलाते हुए | Local mode। 127.0.0.1 सचमुच सही है |
| उसी नेटवर्क पर किसी दूसरी मशीन पर | Server मोड, उस मशीन के प्राइवेट पते पर |
| किसी Playwright कंटेनर, CI रनर या VPS में | स्टैटिक पब्लिक IP और एक फ़ायरवॉल नियम के साथ Server mode |
| लोकल रूप से, लेकिन किसी रिमोट ब्राउज़र से जुड़कर | Local मोड। ब्राउज़र कभी सॉल्वर से बात नहीं करता |
होस्ट और पोर्ट को एनवायरनमेंट से पढ़ें ताकि एक ही स्क्रिप्ट दोनों जगह चले। अगर आप इन्हें पास नहीं करना चाहते, तो क्लाइंट CAPSKIP_HOST, CAPSKIP_PORT और CAPSKIP_API_KEY खुद भी उठा लेता है।
प्रॉक्सी को लेकर ALTCHA से जुड़ी एक बात। यहाँ प्रॉक्सी सपोर्टेड है, लेकिन इसका इस्तेमाल सिर्फ़ challenge लाने के लिए होता है। इससे होकर भेजने लायक कोई ब्राउज़र सेशन है ही नहीं, इसलिए proof of work पर इसका कोई असर नहीं पड़ता, और जब आप challenge डॉक्यूमेंट inline पास करते हैं तब यह कुछ भी नहीं करता।
पूरा चलने वाला उदाहरण
import os
from capskip import CapSkip, ApiException, NetworkException, TimeoutException
from playwright.sync_api import sync_playwright
PAGE_URL = "https://example.com/signup"
SET_ALTCHA_FIELD = """({name, token}) => {
const button = document.querySelector('button[type=submit]');
const form = button ? button.form : document.querySelector('form');
let field = form.querySelector('[name=' + name + ']');
if (!field) {
field = document.createElement('input');
field.type = 'hidden';
field.name = name;
form.appendChild(field);
}
field.value = token;
}"""
solver = CapSkip(
host=os.environ.get("CAPSKIP_HOST", "127.0.0.1"),
port=int(os.environ.get("CAPSKIP_PORT", 8080)),
)
def is_challenge(r):
return "altcha" in r.url and "json" in r.headers.get("content-type", "")
with sync_playwright() as p:
page = p.chromium.launch(headless=True).new_page()
# Catch, solve and submit with nothing slow in between.
with page.expect_response(is_challenge) as caught:
page.goto(PAGE_URL)
try:
result = solver.altcha(url=PAGE_URL, challenge_json=caught.value.json())
except ApiException:
raise SystemExit("refused: Argon2id, scrypt, or an expired challenge")
except NetworkException:
raise SystemExit("solver unreachable: check host and connection mode")
except TimeoutException:
raise SystemExit("no answer inside defaultTimeout")
field_name = page.locator("altcha-widget").get_attribute("name") or "altcha"
page.fill("input[name=email]", "someone@example.com")
page.evaluate(SET_ALTCHA_FIELD, {"name": field_name, "token": result["token"]})
page.click("button[type=submit]")चारों exception CapSkipError से निकले हैं, इसलिए उसी एक को पकड़ने पर SDK जितनी भी विफलताएँ उठा सकता है, वे सब एक ही ब्लॉक में सँभल जाती हैं। जब जवाब अलग-अलग हो तो ऊपर की तरह खास exception पकड़ें, और जब अलग न हो तो CapSkipError।
बाकी types भी उसी क्लाइंट से इसी तरह काम करते हैं। reCAPTCHA और Turnstile एक sitekey और पेज URL लेते हैं, GeeTest एक gt वैल्यू, एक challenge और पेज URL लेता है, और इमेज हल करने के लिए फ़ाइल पाथ, URL या base64 चाहिए। पैकेज जितने भी मेथड देता है, उन सबकी सूची Python कैप्चा सॉल्वर पेजपर है, और ब्राउज़र वाली पूरी कहानी यहाँ है: Playwright कैप्चा सॉल्वर पेज.
आम errors और उनका मतलब
| आप जो देखते हैं | कारण | फिक्स |
|---|---|---|
| दोनों विजेट एट्रिब्यूट None लौटाते हैं | widget पूरी तरह JavaScript से configure हुआ था, इसलिए दोनों में से कोई नाम markup में है ही नहीं | इसके बजाय response पकड़ें, जो markup पर निर्भर नहीं करता |
| get_attribute 30 सेकंड तक अटकता है और फिर exception उठाता है | विजेट एलिमेंट कभी आया ही नहीं, इसलिए लोकेटर अपना डिफ़ॉल्ट टाइमआउट पूरा करके रुका | सेलेक्टर को रेंडर हुए पेज के सामने जाँचें, फिर रिस्पॉन्स पकड़ने पर लौट आएँ |
| रिस्पॉन्स वाला wait टाइमआउट हो जाता है | विजेट का auto एट्रिब्यूट onload पर सेट नहीं है, इसलिए कुछ कभी fetch हुआ ही नहीं, या फिर wait नेविगेशन के बाद तैयार किया गया | जो चीज़ fetch को ट्रिगर करती है उसे लपेटें, और कॉन्टेक्स्ट मैनेजर उससे पहले खोलें |
| पकड़े गए रिस्पॉन्स पर JSON पार्स एरर | wait विजेट की अपनी स्क्रिप्ट पर पूरा हो गया, जिसके URL में भी altcha है | फ़िल्टर में JSON कॉन्टेंट टाइप जोड़ें |
| अभी-अभी पकड़े गए challenge पर ApiException | inline challenge तब तक एक्सपायर हो चुका था, इसलिए सॉल्वर ने उसे हैश करने के बजाय मना कर दिया | एक ही साँस में दोबारा पकड़ें और हल करें, या endpoint पास करें ताकि सॉल्वर खुद दोबारा ले आए |
| सिर्फ़ एक वेरिफ़िकेशन फ़ेलियर, जबकि आपका लॉग दिखाता है कि टोकन हल हो चुका था | solve और सबमिट के बीच challenge एक्सपायर हो गया | पकड़ना, हल करना और सबमिट करना, बीच में कुछ भी धीमा रखे बिना |
| ApiException के अंदर ERROR_CAPTCHA_UNSOLVABLE, करीब एक तिहाई सेकंड में | challenge Argon2id या scrypt इस्तेमाल करता है | दोबारा कोशिश करने जैसा कुछ नहीं। वे दोनों जानबूझकर मना किए जाते हैं |
| पहले solve पर एक NetworkException | CapSkip चल नहीं रहा, या स्क्रिप्ट किसी कंटेनर में है और लूपबैक की ओर इशारा कर रही है | CapSkip शुरू करें, फिर Local मोड और Server मोड में से चुनें |
| फ़ॉर्म पोस्ट तो होता है, लेकिन सर्वर कहता है कि altcha वैल्यू गायब है | hidden फ़ील्ड पेज के किसी दूसरे फ़ॉर्म में जोड़ दिया गया | उसी फ़ॉर्म को क्वेरी करें जिसका सबमिट बटन है |
| 120 सेकंड बताने वाला TimeoutException | सॉल्वर ने डिफ़ॉल्ट पोलिंग टाइमआउट के अंदर जवाब नहीं दिया | देख लें कि सॉल्वर चल रहा है और भरा हुआ नहीं है। सीमा बढ़ाने से वही जवाब बस देर से मिलेगा |
| सबमिट बटन कभी इनेबल होता ही नहीं | पेज इसे इस पर रोके रखता है कि उसकी अपनी स्क्रिप्ट विजेट को सफल होते देखे | फ़ॉर्म फ़ील्ड सीधे पोस्ट करें, या पेज जो सुनता है उसे पूरा कर दें |
| कॉल पर एक ValidationException | challenge का कोई भी ऑप्शन दिया ही नहीं गया, या ऐसा ऑप्शन पास हुआ जो ALTCHA लेता ही नहीं | endpoint दें या डॉक्यूमेंट दें, और बाकी सब हटा दें |
FAQ
क्या ALTCHA हल करने के लिए मुझे ब्राउज़र चाहिए ही?
नहीं। ALTCHA एक हैशिंग समस्या है, इसलिए इसे CPU से हल किया जाता है और जवाब में कोई ब्राउज़र शामिल नहीं होता। अगर आपने Playwright सिर्फ़ कैप्चा की वजह से खोला था, तो उसे बंद कर दें: challenge किसी HTTP क्लाइंट से लाएँ और टोकन वापस पोस्ट कर दें, जिसे प्लेन Python वाली गाइड पूरे विस्तार से समझाती है। Playwright तब अपनी जगह बनाता है जब बाकी flow के लिए एक असली पेज चाहिए, जैसे कुकीज़ सेट करने वाला लॉगिन, कई चरणों वाला फ़ॉर्म, या ऐसी साइट जो अपना markup स्क्रिप्ट में रेंडर करती है।
क्या Playwright, Docker या GitHub Actions से सॉल्वर तक पहुँच सकता है?
हाँ, Server मोड के ज़रिए। CapSkip को कनेक्शन सेटिंग्स में लूपबैक से बदलकर अपने नेटवर्क पते या पब्लिक IP पर ले आएँ, फिर होस्ट एनवायरनमेंट वेरिएबल को उसी की ओर कर दें। इसके बाद कंटेनर, रनर और सॉल्वर वही HTTP API बोलते हैं जो वे एक ही मशीन पर बोलते। जब रास्ता इंटरनेट से होकर जाए तो स्टैटिक पब्लिक IP इस्तेमाल करें और उसे फ़ायरवॉल नियम से सीमित रखें। सॉल्वर दोनों ही हालात में आपके अपने हार्डवेयर पर रहता है, इसलिए लाइसेंस या solve की संख्या में कुछ नहीं बदलता।
ALTCHA टोकन कितनी देर तक वैध रहता है?
ज़्यादा देर नहीं, और यह साइट तय करती है। कुछ विंडो दो मिनट के अंदर ही बंद हो जाती हैं। जब कोई एक्सपायर होती है तो साइट जवाब को एक सादे वेरिफ़िकेशन फ़ेलियर के साथ ठुकरा देती है, जो हूबहू ग़लत जवाब जैसा दिखता है, और रिस्पॉन्स में कुछ भी नहीं बताता कि दोनों में से क्या हुआ। इसलिए challenge पहले से जमा मत कीजिए, ब्राउज़र के तीन और पेज घूमने तक टोकन को किसी वेरिएबल में मत रोकिए, और किसी व्यक्ति के फ़ॉर्म भरते रहने के दौरान तो कभी मत रोकिए। एक ताज़ा solve मिलीसेकंड का काम है, जो यह पता लगाने से सस्ता है कि बासी टोकन क्यों फ़ेल हुआ।
क्या Playwright के अपने टाइमआउट solve को बीच में काट देंगे?
नहीं, क्योंकि solve कोई Playwright कॉल है ही नहीं। डिफ़ॉल्ट 30 सेकंड के ऐक्शन और नेविगेशन टाइमआउट क्लिक, wait और पेज लोड पर लागू होते हैं, और आपका सॉल्वर कॉल उनमें से दो के बीच बैठा सादा Python है। जो सीमा लागू होती है वह क्लाइंट का अपना 120 सेकंड का डिफ़ॉल्ट पोलिंग टाइमआउट है, जिसे ALTCHA लंबे reCAPTCHA वाले के बजाय इस्तेमाल करता है, क्योंकि यह CPU का काम है, ब्राउज़र सेशन नहीं। इसके बजाय पूरे टेस्ट के इर्द-गिर्द लगी किसी सीमा पर नज़र रखें, जैसे प्रति-टेस्ट प्लगइन टाइमआउट या CI जॉब की सीमा।
संक्षेप में
विजेट ने जो challenge माँगा था उसे पकड़ें, चाहे एट्रिब्यूट से या रिस्पॉन्स से, उस डॉक्यूमेंट को पेज URL के साथ ALTCHA के उस एकमात्र मेथड को दें, और टोकन को उस फ़ॉर्म के एक hidden फ़ील्ड में लिखें जो सचमुच सबमिट होता है, और जिसका नाम विजेट के अपने name एट्रिब्यूट से आता है। रास्ते में टोकन को छुएँ नहीं। पकड़ना, हल करना और सबमिट करना, तीनों पास-पास रखें, क्योंकि विंडो दो मिनट के अंदर बंद हो सकती है और एक्सपायर हुआ challenge ग़लत जवाब से अलग पहचाना ही नहीं जा सकता। जैसे ही स्क्रिप्ट सॉल्वर के साथ एक ही मशीन साझा करना बंद करे, Server मोड पर चले जाएँ।
- यह type क्या है और कैसे काम करता है: ALTCHA सॉल्वर पेज.
- वही काम, बिना ब्राउज़र के: प्लेन Python में ALTCHA हल करना.
एक आख़िरी बात, जो बदल देती है कि आप retry कैसे डिज़ाइन करेंगे। चूँकि लोकल captcha सॉल्वर तक पहुँचने का यह रास्ता proof of work उसी मशीन पर निकालता है जो पहले से आपकी है, इसलिए फेंके गए किसी challenge की कीमत आपके अपने CPU के कुछ मिलीसेकंड के अलावा कुछ नहीं होती, और आप बासी टोकन को लंबे रन तक सँभालते रहने के बजाय पेज दोबारा लोड करके नया challenge लेने का ख़र्च आसानी से उठा सकते हैं।
