Selenium में ALTCHA कैसे हल करें, बिना नेटवर्क इंटरसेप्शन के

Selenium में ALTCHA हल करने के लिए आप widget के पूरा होने का इंतज़ार कभी नहीं करते। ALTCHA पहचान नहीं, proof of work है: साइट एक hashing problem थमा देती है, और client को अंदर जाने से पहले वह संख्या खोजनी होती है जो उसे पूरा करे। यहाँ न देखने को कुछ है और न क्लिक करने को, इसलिए ब्राउज़र बाकी flow के लिए है, कैप्चा के लिए नहीं। Playwright के response wait जैसा एक-कॉल वाला विकल्प Selenium में नहीं है, और यह उन गिने-चुने मौकों में से है जहाँ इसका कोई नुकसान नहीं होता: widget अपना challenge endpoint खुद एक attribute में बता देता है, और सॉल्वर को बस इतना ही चाहिए।
आपको क्या चाहिए
- CapSkip 1.2.6 या उसके बाद का वर्शन, किसी Windows मशीन पर चलता हुआ। ALTCHA सपोर्ट उसी रिलीज़ में आया था, इसलिए पुराने बिल्ड में कॉल करने के लिए कोई मेथड ही नहीं है।
- Python 3.10 या उससे नया, जिसमें Selenium और CapSkip पैकेज इंस्टॉल हों, साथ में उससे मेल खाता ब्राउज़र।
- उस पेज का URL जिस पर widget मौजूद है। यहाँ कोई sitekey नहीं होती, क्योंकि ALTCHA में sitekey होती ही नहीं।
- सॉल्वर के लिए एक पता। Local मोड 127.0.0.1 पर सिर्फ़ उसी डिवाइस को जवाब देता है, और Server मोड आपके नेटवर्क पते या पब्लिक IP पर सुनता है ताकि कोई Grid node, कोई CI runner या कोई दूसरी मशीन उसी API से उस तक पहुँच सके। कौन सा लागू होता है, यह Step 5 बताता है, और दोनों यहाँ मिलते हैं: कनेक्शन सेटिंग्स.
# pip install selenium capskip pip install selenium capskip
Step 1: widget से challenge endpoint पढ़ें
widget element उस endpoint का नाम बताता है जिससे वह अपना challenge माँगेगा। वह किस attribute में रखा है, यह widget की पीढ़ी पर निर्भर करता है, इसलिए अंदाज़ा लगाने के बजाय पेज सोर्स पढ़ें।
| Widget पीढ़ी | वह attribute जो challenge का नाम बताता है |
|---|---|
| v1 और v2 | endpoint के लिए challengeurl, और जब challenge इनलाइन हो तब अलग challengejson attribute |
| v3 और उसके बाद | challenge, और वही एक attribute या तो URL लेता है या खुद challenge डेटा |
यहाँ Selenium की दो आदतें मायने रखती हैं और दोनों ही ज़ाहिर नहीं हैं। Selenium किसी element के लिए अपने आप इंतज़ार नहीं करता, इसलिए पेज के DOM में widget डालने से पहले उसे खोजेंगे तो दोबारा कोशिश के बजाय NoSuchElementException मिलेगा। और सामान्य attribute कॉल एक मिश्रण है: वह पहले उसी नाम की JavaScript property आज़माता है और उसके बाद ही markup पर लौटता है। एक web component अपने ही attributes के लिए properties तय करता है, इसलिए जो वापस मिलता है वह आपके पढ़े जा सकने वाले HTML पर नहीं, बल्कि widget के build पर निर्भर करता है। DOM attribute कॉल में ऐसा कोई fallback नहीं है और वह वही लौटाता है जो markup में लिखा है, यानी वही जो आपको चाहिए। Python API रेफ़रेंस इस फ़र्क़ को यहाँ साफ़ करता है: WebElement पेज.
# pip install selenium capskip
from urllib.parse import urljoin
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
PAGE_URL = "https://example.com/signup"
driver = webdriver.Chrome()
driver.get(PAGE_URL)
# Nothing auto-waits in Selenium, so wait for the element.
widget = WebDriverWait(driver, 15).until(
EC.presence_of_element_located((By.CSS_SELECTOR, "altcha-widget"))
)
# v1 and v2 use challengeurl or challengejson; v3 uses challenge.
value = (widget.get_dom_attribute("challengeurl")
or widget.get_dom_attribute("challengejson")
or widget.get_dom_attribute("challenge"))
if value is None:
raise SystemExit("no challenge attribute on the widget")उन तीन में से दो attributes आपको पॉइंटर नहीं, बल्कि पूरा document देते हैं, इसलिए उसे URL मानने से पहले जाँच लें कि मिला क्या है। URL के लिए एक क़दम और ज़रूरी है: markup में आम तौर पर same-origin path होता है, जैसे शुरुआती स्लैश और एक फ़ोल्डर का नाम, और कोई HTTP client उसे अपने आप fetch नहीं कर सकता। पहले उसे पेज URL के सापेक्ष resolve करें।
import json
challenge, endpoint = None, None
if value.lstrip().startswith("{"):
# challengejson, or a v3 challenge holding the data inline.
challenge = json.loads(value)
else:
# A path in the markup becomes an absolute URL here.
endpoint = urljoin(PAGE_URL, value)widget के type attribute पर मौजूद तीनों इंटरैक्शन शैलियाँ, native, checkbox और switch, सिर्फ़ दिखावटी हैं और कभी सॉल्वर तक नहीं पहुँचतीं, और अलग से मौजूद display attribute भी उसी तरह सिर्फ़ दिखावटी है। ALTCHA इन सबका ब्योरा यहाँ देता है: अपनी खुद की विजेट गाइड.
Step 2: ब्राउज़र के सेशन से challenge लाएँ
जब भी endpoint सार्वजनिक हो, यह क़दम छोड़ा जा सकता है, और ऐसे endpoint कम नहीं हैं। URL CapSkip को थमा दें और वह challenge खुद ले आता है। यह क़दम इसलिए है क्योंकि कुछ साइटें challenge को उसी सेशन से बाँध देती हैं जिसने उसे माँगा था, और सॉल्वर आपकी मशीन से बिना किसी cookie के fetch करता है, इसलिए जो उसे मिलता है वह किसी का नहीं होता। फिर जवाब सही होता है और साइट तब भी उसे ठुकरा देती है।
इसका हल यह है कि challenge को ब्राउज़र के सेशन के भीतर fetch करें और पॉइंटर के बजाय पूरा document पास करें। Selenium के पास पहले से मौजूद cookies को किसी HTTP client में कॉपी करें, वही user agent साथ रखें, और खुद माँग लें।
import requests
if endpoint:
session = requests.Session()
for cookie in driver.get_cookies():
session.cookies.set(cookie["name"], cookie["value"],
domain=cookie["domain"])
session.headers["User-Agent"] = driver.execute_script(
"return navigator.userAgent")
# Referer matters on sites that check where the ask came from.
challenge = session.get(endpoint,
headers={"Referer": PAGE_URL}).json()उस लाइन पर JSON decode error काम की नाकामी है। इसका मतलब है कि endpoint ने HTML लौटाया, आम तौर पर कोई लॉगिन पेज या consent wall, जो बताता है कि request एक अजनबी की तरह गई थी और यह क़दम उठाना सही था। fetch के तुरंत बाद solve शुरू करें। खिड़की छोटी है और घड़ी तब चलने लगती है जब साइट challenge जारी करती है, तब नहीं जब आप उसे इस्तेमाल करने की फ़ुर्सत निकालते हैं।
Step 3: challenge को इकलौती ALTCHA method को सौंपें
सिर्फ़ एक मेथड, जिसका पूरा ब्यौरा ALTCHA सॉल्वर पेज, और यह challenge को दोनों में से किसी भी रूप में लेती है। document पास करें तो कोई request बाहर जाती ही नहीं। endpoint पास करें तो सॉल्वर उसे खुद ले आता है, और अगर job क़तार में इतनी देर पड़ी रही कि पहला challenge expire हो गया तो नया भी ले आता है।
from capskip import CapSkip solver = CapSkip(host="127.0.0.1", port=8080) # The document from step 2, 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
उस नतीजे में दो कीज़ सिर्फ़ 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 बनकर लौटता है और उसे कभी दोबारा नहीं आज़माया जाता, क्योंकि memory-hard function ऐसी चीज़ नहीं जिसे retry ठीक कर दे। इस टाइप पर वह नतीजा किसी न पढ़ी जाने वाली तस्वीर की नहीं, बल्कि एल्गोरिदम की ओर इशारा करता है, और इस error code के लिए मौजूद है: अपनी एक अलग गाइड.
Step 4: token को hidden field में लिखें
widget अपना payload एक hidden input में भेजता है जिसका नाम उसके अपने name attribute से आता है और डिफ़ॉल्ट रूप से altcha होता है। अंदाज़ा लगाने के बजाय उस attribute को पढ़ें, ठीक वैसे ही जैसे आपने challenge वाला पढ़ा था। इस रन में widget को किसी ने verify नहीं किया, इसलिए उस field को किसी ने भरा भी नहीं और आप उसे खुद भर रहे हैं।
Selenium किसी WebElement को सीधे script में पास कर सकता है, जिससे सही form खोजने का सबसे साफ़ रास्ता खुद बटन बन जाता है। submit बटन सौंप दें और उसकी form property पढ़ें: signup पेज पर अक्सर कई form होते हैं, और अगर बटन किसी और form का है और आप field पेज के पहले form में जोड़ देते हैं, तो सर्वर को वह value कभी दिखती ही नहीं।
SET_FIELD = """
const form = arguments[0].form || document.querySelector('form');
let field = form.querySelector('[name="' + arguments[1] + '"]');
if (!field) {
field = document.createElement('input');
field.type = 'hidden';
field.name = arguments[1];
form.appendChild(field);
}
field.value = arguments[2];
"""
button = driver.find_element(By.CSS_SELECTOR, "button[type=submit]")
field_name = widget.get_dom_attribute("name") or "altcha"
driver.execute_script(SET_FIELD, button, field_name, result["token"])
button.click()स्ट्रिंग को जैसी है वैसी ही आगे भेजें। टोकन एक JSON डॉक्यूमेंट का base64 है जिसके फ़ील्ड सर्वर के HMAC सिग्नेचर के दायरे में आते हैं, इसलिए सफ़ाई जैसी दिखने वाली हर चीज़ उसे तोड़ देती है: व्हाइटस्पेस हटाना, डिकोड करके दोबारा एनकोड करना, या कीज़ को किसी और क्रम में रखकर JSON दोबारा बनाना। कुछ इंटीग्रेशन payload को फ़ॉर्म फ़ील्ड के बजाय किसी JSON बॉडी फ़ील्ड से पढ़ते हैं, और विजेट को इस तरह भी कॉन्फ़िगर किया जा सकता है कि वह इसे कुकी में दे, इसलिए देखें कि पेज का अपना सबमिट क्या भेजता है और वही दोहराएँ।
अगर submit बटन कभी clickable बनता ही नहीं, तो पेज उसे field में value होने पर नहीं, बल्कि अपनी ही script के यह सुनने पर रोके हुए है कि widget कामयाब रहा। यहाँ दो ईमानदार जवाब हैं। पता करें कि पेज किस चीज़ को सुन रहा है और उसे पूरा करें, या बटन छोड़ दें और form के fields को ब्राउज़र के पास पहले से मौजूद cookies के साथ सीधे post कर दें, जो आम तौर पर छोटा रास्ता है और हमेशा ज़्यादा टिकाऊ।
Step 5: जब आपकी script जगह बदले तो सॉल्वर कहाँ चलता है
सैंपल में 127.0.0.1 इसलिए है क्योंकि जब तक आपकी script और CapSkip एक ही मशीन पर हैं, वही सही है। सॉल्वर को आपका Python कोड बुलाता है, न ब्राउज़र और न पेज, इसलिए पता इस बात पर निर्भर करता है कि टेस्ट प्रोसेस कहाँ चलती है, न कि Chrome कहाँ चलता है। Selenium में यह उल्टा समझ लेना आसान है, क्योंकि ब्राउज़र तो अक्सर पहले से ही कहीं और होता है।
| Python प्रोसेस कहाँ चलती है | कौन-सा कनेक्शन मोड |
|---|---|
| CapSkip मशीन पर, किसी लोकल ब्राउज़र को चलाते हुए | Local mode। 127.0.0.1 सचमुच सही है |
| आपकी मशीन पर, किसी रिमोट WebDriver या Grid node को चलाते हुए | Local मोड। ब्राउज़र कभी सॉल्वर से बात नहीं करता |
| उसी नेटवर्क पर किसी दूसरी मशीन पर | Server मोड, सॉल्वर मशीन के प्राइवेट पते पर |
| किसी container में, किसी CI runner पर या किसी VPS पर | स्टैटिक पब्लिक IP और एक फ़ायरवॉल नियम के साथ Server mode |
CapSkip को Server मोड पर कर दें और वह loopback के बजाय आपके नेटवर्क पते या पब्लिक IP पर सुनता है, और runner उसी HTTP API से जुड़ता है जिससे वह लोकल रूप से जुड़ता। जब रास्ता इंटरनेट से होकर जाए तो स्टैटिक पब्लिक IP की सलाह दी जाती है, साथ में ऐसा firewall नियम जो सिर्फ़ उन्हीं पतों को आने दे जिनकी आप उम्मीद करते हैं। Server मोड सिर्फ़ यह बदलता है कि सॉल्वर कहाँ सुनता है, और कुछ नहीं: हार्डवेयर अब भी आपका है और उस पर अब भी कोई मीटर नहीं चलता। टेस्ट को खुद Grid पर चलाने के अपने ही जाल हैं, जिन्हें अलग से यहाँ बताया गया है: Selenium Grid गाइड.
होस्ट और पोर्ट को एनवायरनमेंट से पढ़ें ताकि एक ही स्क्रिप्ट दोनों जगह चले। क्लाइंट CAPSKIP_HOST या CAPSKIP_PORT को अपने आप नहीं पढ़ता, इसलिए इन्हें constructor को पास करें, जैसा नीचे दिया गया पूरा उदाहरण करता है।
प्रॉक्सी को लेकर ALTCHA से जुड़ी एक बात। यहाँ प्रॉक्सी सपोर्टेड है, लेकिन इसका इस्तेमाल सिर्फ़ challenge लाने के लिए होता है। इससे होकर भेजने लायक कोई ब्राउज़र सेशन है ही नहीं, इसलिए proof of work पर इसका कोई असर नहीं पड़ता, और जब आप challenge डॉक्यूमेंट inline पास करते हैं तब यह कुछ भी नहीं करता।
पूरा चलने वाला उदाहरण
import json, os, requests
from urllib.parse import urljoin
from capskip import CapSkip, ApiException, NetworkException, TimeoutException
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
PAGE_URL = "https://example.com/signup"
SET_FIELD = """
const form = arguments[0].form || document.querySelector('form');
let field = form.querySelector('[name="' + arguments[1] + '"]');
if (!field) {
field = document.createElement('input');
field.type = 'hidden';
field.name = arguments[1];
form.appendChild(field);
}
field.value = arguments[2];
"""
solver = CapSkip(
host=os.environ.get("CAPSKIP_HOST", "127.0.0.1"),
port=int(os.environ.get("CAPSKIP_PORT", 8080)),
)
driver = webdriver.Chrome()
try:
driver.get(PAGE_URL)
widget = WebDriverWait(driver, 15).until(
EC.presence_of_element_located((By.CSS_SELECTOR, "altcha-widget"))
)
value = (widget.get_dom_attribute("challengeurl")
or widget.get_dom_attribute("challengejson")
or widget.get_dom_attribute("challenge"))
if value is None:
raise SystemExit("no challenge attribute on the widget")
if value.lstrip().startswith("{"):
challenge = json.loads(value)
else:
endpoint = urljoin(PAGE_URL, value)
session = requests.Session()
for cookie in driver.get_cookies():
session.cookies.set(cookie["name"], cookie["value"],
domain=cookie["domain"])
session.headers["User-Agent"] = driver.execute_script(
"return navigator.userAgent")
challenge = session.get(endpoint,
headers={"Referer": PAGE_URL}).json()
try:
result = solver.altcha(url=PAGE_URL, challenge_json=challenge)
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")
button = driver.find_element(By.CSS_SELECTOR, "button[type=submit]")
field_name = widget.get_dom_attribute("name") or "altcha"
driver.find_element(By.NAME, "email").send_keys("[email protected]")
driver.execute_script(SET_FIELD, button, field_name, result["token"])
button.click()
finally:
driver.quit()चारों exceptions CapSkipError से निकलते हैं, इसलिए उसी एक को catch कर लेने से SDK की हर नाकामी एक ही ब्लॉक में सँभल जाती है। जब प्रतिक्रिया अलग हो तो ऊपर की तरह विशिष्ट exception catch करें, और जब अलग न हो तो CapSkipError। ध्यान रखें कि आप कौन सा TimeoutException catch कर रहे हैं: CapSkip वाला और Selenium का अपना, दोनों का नाम एक ही है, इसलिए अगर दोनों दायरे में हों तो किसी एक को alias के साथ import करें।
बाकी types भी उसी क्लाइंट से इसी तरह काम करते हैं। reCAPTCHA और Turnstile एक sitekey और पेज URL लेते हैं, GeeTest एक gt वैल्यू, एक challenge और पेज URL लेता है, और इमेज हल करने के लिए फ़ाइल पाथ, URL या base64 चाहिए। पैकेज जितने भी मेथड देता है, उन सबकी सूची Python कैप्चा सॉल्वर पेजपर है, और ब्राउज़र वाली पूरी कहानी यहाँ है: Selenium कैप्चा सॉल्वर पेज.
आम errors और उनका मतलब
| आप जो देखते हैं | कारण | फिक्स |
|---|---|---|
| widget पर NoSuchElementException | element अभी DOM में डाला ही नहीं गया था, जो तब होता है जब markup script बनाती है, और Selenium अपने आप इंतज़ार नहीं करता | lookup को element के मौजूद होने की explicit wait में लपेट दें |
| तीनों attribute reads None लौटाते हैं | widget पूरी तरह JavaScript से configure हुआ था, इसलिए तीनों में से कोई नाम markup में है ही नहीं | configuration को पेज की अपनी script से पढ़ें, या network पैनल में दिखने वाले endpoint पर लौट आएँ |
| attribute की value खाली, जबकि पेज सोर्स में वह साफ़ मौजूद है | सामान्य attribute कॉल ने वह property लौटाई जो web component तय करता है, और वह खाली है | DOM attribute कॉल इस्तेमाल करें, जो markup पढ़ता है और जिसमें property वाला fallback नहीं है |
| HTTP client से MissingSchema, जो स्लैश से शुरू होने वाली किसी value का नाम लेता है | markup में same-origin path है, और DOM attribute कॉल उसे हूबहू वैसे ही लौटाता है जैसे वह लिखा है | fetch करने से पहले और सॉल्वर को देने से पहले उसे पेज URL के सापेक्ष resolve करें |
| attribute की value ब्रेस से शुरू होती है | challengejson attribute, या कोई v3 widget जो URL के बजाय document को inline लिए हुए है | उसे JSON के रूप में parse करें और inline challenge के तौर पर पास करें |
| endpoint fetch करने पर JSON decode error | endpoint ने HTML लौटाया, यानी request ब्राउज़र के सेशन के बिना पहुँची | fetch करने से पहले cookies और user agent कॉपी कर लें |
| अभी-अभी पकड़े गए challenge पर ApiException | inline challenge तब तक एक्सपायर हो चुका था, इसलिए सॉल्वर ने उसे हैश करने के बजाय मना कर दिया | fetch और solve एक ही साँस में करें, या endpoint पास करें ताकि सॉल्वर दोबारा ला सके, बशर्ते वह endpoint सेशन से बँधा न हो |
| ApiException के अंदर ERROR_CAPTCHA_UNSOLVABLE, करीब एक तिहाई सेकंड में | challenge Argon2id या scrypt इस्तेमाल करता है | दोबारा कोशिश करने जैसा कुछ नहीं। वे दोनों जानबूझकर मना किए जाते हैं |
| सिर्फ़ एक वेरिफ़िकेशन फ़ेलियर, जबकि आपका लॉग दिखाता है कि टोकन हल हो चुका था | solve और सबमिट के बीच challenge एक्सपायर हो गया | पकड़ना, हल करना और सबमिट करना, बीच में कुछ भी धीमा रखे बिना |
| पहले solve पर एक NetworkException | CapSkip चल नहीं रहा, या स्क्रिप्ट किसी कंटेनर में है और लूपबैक की ओर इशारा कर रही है | CapSkip शुरू करें, फिर Local मोड और Server मोड में से चुनें |
| 120 सेकंड बताने वाला TimeoutException | सॉल्वर ने डिफ़ॉल्ट polling timeout के भीतर जवाब नहीं दिया, जो ALTCHA पर लंबे reCAPTCHA वाले के बजाय लागू होता है | देख लें कि सॉल्वर चल रहा है और भरा हुआ नहीं है। सीमा बढ़ाने से वही जवाब बस देर से मिलेगा |
| फ़ॉर्म पोस्ट तो होता है, लेकिन सर्वर कहता है कि altcha वैल्यू गायब है | hidden फ़ील्ड पेज के किसी दूसरे फ़ॉर्म में जोड़ दिया गया | submit बटन से form property पढ़ें, जैसा snippet करता है |
| submit बटन disabled ही रहता है | पेज इसे इस पर रोके रखता है कि उसकी अपनी स्क्रिप्ट विजेट को सफल होते देखे | फ़ॉर्म फ़ील्ड सीधे पोस्ट करें, या पेज जो सुनता है उसे पूरा कर दें |
| कॉल पर एक ValidationException | challenge का कोई भी ऑप्शन दिया ही नहीं गया, या ऐसा ऑप्शन पास हुआ जो ALTCHA लेता ही नहीं | endpoint दें या डॉक्यूमेंट दें, और बाकी सब हटा दें |
FAQ
क्या ALTCHA हल करने के लिए मुझे ब्राउज़र चाहिए ही?
नहीं। ALTCHA एक hashing problem है, इसलिए उसका जवाब CPU से निकलता है और जवाब में कोई ब्राउज़र शामिल नहीं होता। अगर आपने Selenium सिर्फ़ कैप्चा की वजह से खोला था, तो उसे बंद कर दें: किसी HTTP client से challenge लाएँ और token वापस post कर दें, यह पूरा तरीक़ा प्लेन Python वाली गाइड में क़दम दर क़दम बताया गया है। Selenium अपनी जगह तब बनाता है जब बाकी flow को एक असली पेज चाहिए होता है, जैसे कोई लॉगिन जो cookies सेट करता है, कोई multi-step form, या ऐसा markup जो script चलने के बाद ही बनता है।
widget का attribute खाली क्यों लौटता है?
क्योंकि सामान्य attribute कॉल एक मिश्रण है। element अगर कोई property तय करता है तो वह JavaScript property लौटाता है और उसके बाद ही markup पर लौटता है, और एक web component अपने ही attributes के लिए properties तय करता है, इसलिए पेज सोर्स में दिखने वाली value पर खाली property भारी पड़ जाती है। DOM attribute कॉल में ऐसा कोई fallback नहीं है और वह वही लौटाता है जो markup में लिखा है। दूसरी वजह यह है कि आपके सामने जो पीढ़ी है उसके लिए आप गलत नाम पढ़ रहे हैं, इसलिए attribute को गायब मानने से पहले तीनों आज़मा लें।
क्या कोई CI runner या container सॉल्वर तक पहुँच सकता है?
हाँ, Server मोड से। कनेक्शन सेटिंग्स में CapSkip को loopback से हटाकर अपने नेटवर्क पते या पब्लिक IP पर कर दें, फिर host environment variable को उसी पर सेट करें। इसके बाद runner और सॉल्वर वही HTTP API बोलते हैं जो वे एक ही मशीन पर बोलते। जब रास्ता इंटरनेट से होकर जाए तो स्टैटिक पब्लिक IP इस्तेमाल करें और उसे firewall नियम से सीमित रखें। रिमोट Grid node अलग सवाल है और उसके लिए आम तौर पर कुछ करने की ज़रूरत ही नहीं पड़ती, क्योंकि ब्राउज़र को node चलाता है जबकि आपकी script, जो असल में सॉल्वर को बुलाती है, वहीं रहती है जहाँ आपने उसे शुरू किया था।
क्या Selenium के अपने timeouts solve को बीच में काट देंगे?
नहीं, क्योंकि solve कोई WebDriver कमांड नहीं है। implicit wait, page load timeout और script timeout, ये सब उन कॉल पर लागू होते हैं जो Selenium ब्राउज़र को भेजता है, और आपका सॉल्वर कॉल उनमें से दो के बीच बैठा सामान्य Python है। जो सीमा लागू होती है वह क्लाइंट का 120 सेकंड का डिफ़ॉल्ट polling timeout है, जो ALTCHA पर लंबे reCAPTCHA वाले के बजाय इसलिए लागू होता है क्योंकि यह CPU का काम है, ब्राउज़र सेशन का नहीं। इसके बजाय पूरे टेस्ट के इर्द-गिर्द लिपटी किसी सीमा पर नज़र रखें, जैसे प्रति-टेस्ट plugin timeout या CI job की सीमा।
संक्षेप में
widget का इंतज़ार करें, DOM attribute कॉल से उसका challenge attribute पढ़ें, किसी path को पेज URL के सापेक्ष resolve करें, और अगर साइट उस endpoint को सेशन से बाँधती है तो उसे ब्राउज़र के सेशन के भीतर fetch करें। document या URL को पेज URL के साथ उस इकलौती ALTCHA method को दें, फिर token को उस hidden field में लिखें जिसका नाम widget के अपने name attribute से आता है, और वह भी उसी form में जिसका submit बटन है। रास्ते में token को छुएँ नहीं। fetch, solve और submit को पास-पास रखें, क्योंकि खिड़की दो मिनट के अंदर बंद हो सकती है और expire हो चुका challenge बिल्कुल गलत जवाब जैसा दिखता है।
- यह type क्या है और कैसे काम करता है: ALTCHA सॉल्वर पेज.
- बिल्कुल यही काम, बिना किसी ब्राउज़र के: प्लेन Python में ALTCHA हल करना.
आख़िरी बात, जो आपके retry के डिज़ाइन को बदल देती है। क्योंकि इस रास्ते से मिलने वाला असीमित कैप्चा सॉल्वर proof of work उसी हार्डवेयर पर करता है जो पहले से आपका है, इसलिए फेंका गया challenge आपको अपने ही CPU के चंद milliseconds के अलावा कुछ नहीं पड़ता, और नया challenge लेने के लिए पेज दोबारा लोड कर देना हमेशा उस बासी token को लंबे टेस्ट भर घसीटने से सस्ता रहता है।
