undetected-chromedriver में कैप्चा कैसे संभालें (Python)

undetected-chromedriver captcha - How to Handle CAPTCHA in undetected-chromedriver (Python)

undetected-chromedriver Chrome को patch करता है ताकि automation flags लीक होना बंद हो जाएँ। इससे आप पेज तक पहुँच जाते हैं। इससे आप reCAPTCHA checkbox पार नहीं कर पाते, क्योंकि widget कोई fingerprint जाँच नहीं है, वह एक token की माँग है। undetected-chromedriver वाले कैप्चा को भी हल करना पड़ता है और जवाब DOM में इंजेक्ट करना पड़ता है।

चार चरण: patched driver शुरू करें, पेज से sitekey पढ़ें, लोकल रूप से हल करें, और token वहाँ रखें जहाँ पेज को उसकी उम्मीद है। यह सब Python में नीचे दिया गया है।

undetected-chromedriver क्या करता है और क्या नहीं

सिग्नलdriver इसे संभालता है
navigator.webdriver और CDP के संकेतहां
patched binary, ताकि driver की पहचान driver के रूप में न होहां
login फ़ॉर्म पर reCAPTCHA v2 checkboxनहीं
पेज द्वारा चलाया गया invisible v2 या v3 challengeनहीं
एक Turnstile widgetनहीं

यह फ़र्क़ इसलिए मायने रखता है क्योंकि ब्लॉक हुए scraper के लिए आम सलाह होती है “stealth जोड़ दो”। अगर widget स्क्रीन पर है, तो कितनी भी stealth उसे हटा नहीं सकती। आपको एक token चाहिए।

आपको क्या चाहिए

  • Chrome इंस्टॉल हो, और CapSkip यहाँ चल रहा हो: 127.0.0.1:8080। यह सेटअप गाइड पेज ऐप के बारे में बताता है।
  • Python 3.10 या उससे नया।
  • तीन पैकेज।
# the patched driver, selenium itself, and the local solver
pip install undetected-chromedriver selenium capskip

चरण 1: patched driver शुरू करें

इसे uc के रूप में import करें और browser को उसी तरह बनाएँ जैसे आप सादे Selenium के साथ बनाते हैं। Options इससे आते हैं: uc.ChromeOptions(), Selenium के नहीं, क्योंकि library उन्हें बीच रास्ते में patch कर देती है:

# pip install undetected-chromedriver
import undetected_chromedriver as uc

options = uc.ChromeOptions()
options.add_argument("--window-size=1280,800")

# use_subprocess keeps the patched binary alive long enough
# to shut down cleanly on Windows.
driver = uc.Chrome(options=options, use_subprocess=True)

driver.get("https://example.com/login")

इसके ऊपर कोई और stealth plugin न चढ़ाएँ। एक ही properties पर लड़ते दो patchers ख़ुद में एक detection सिग्नल हैं, और यही आम वजह है कि पहले काम करने वाला setup अचानक बंद हो जाता है।

चरण 2: पेज से sitekey पढ़ें

sitekey widget element पर एक सार्वजनिक attribute है। उसे hardcode करने के बजाय live DOM से पढ़ें, क्योंकि कई साइटें हर environment के लिए keys बदलती रहती हैं:

from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

# The widget is injected by script, so wait for it.
widget = WebDriverWait(driver, 20).until(
    EC.presence_of_element_located((By.CSS_SELECTOR, "[data-sitekey]"))
)

sitekey = widget.get_attribute("data-sitekey")
page_url = driver.current_url

print(sitekey)

उपयोग करें driver.current_url का इस्तेमाल करें, न कि उस URL का जो आपने माँगा था। अगर साइट ने आपको किसी challenge path पर redirect कर दिया, तो solver को उसी पेज के बारे में बताना होगा जिस पर आप असल में पहुँचे हैं।

चरण 3: उसे लोकल रूप से हल करें

CapSkip आपकी अपनी मशीन पर चलता है, इसलिए हल करना localhost पर एक call भर है। कोई खाता नहीं, कोई प्रति-हल बिलिंग नहीं, sitekey और पेज URL के अलावा कुछ भी मशीन से बाहर नहीं जाता:

# pip install capskip
from capskip import CapSkip

solver = CapSkip(
    host="127.0.0.1",
    port=8080,
    recaptchaTimeout=300,   # seconds, also covers Turnstile
)

result = solver.recaptcha(sitekey=sitekey, url=page_url)

token = result["code"]   # the g-recaptcha-response value

वैरिएंट अलग-अलग मेथड नहीं, बल्कि विकल्प हैं। जोड़ें: invisible=1 invisible v2 widget के लिए, version="v3" एक के साथ action v3 के लिए, और enterprise=1 Enterprise प्रोडक्ट के लिए।

चरण 4: token इंजेक्ट करें और callback चलाएँ

token को छिपे हुए g-recaptcha-response textarea में पहुँचना चाहिए। सादे form submit के लिए इतना ही काफ़ी है, क्योंकि यह field बाक़ी फ़ॉर्म के साथ post हो जाता है:

driver.execute_script(
    "document.getElementById('g-recaptcha-response')"
    ".innerHTML = arguments[0];",
    token,
)

driver.find_element(By.CSS_SELECTOR, "button[type='submit']").click()

सिंगल-पेज ऐप्स अलग होते हैं। वे textarea कभी पढ़ते ही नहीं, वे widget के अपने callback का इंतज़ार करते हैं कि वह उन्हें token थमाए। function का नाम element पर घोषित होता है, इसलिए आप उसे सीधे call कर सकते हैं:

callback = widget.get_attribute("data-callback")

if callback:
    # Call the page's own handler with the token, exactly as
    # the widget would have done.
    driver.execute_script(f"{callback}(arguments[0]);", token)

अगर इंजेक्ट करने के बाद कुछ नहीं होता और element पर नहीं है कोई data-callback, तो पेज callback को markup के बजाय JavaScript में जोड़ रहा है। ऐसे में उसे कैसे ढूँढें, यह reCAPTCHA v2 callback सॉल्वर पेज बताता है।

उसी driver में Turnstile

Cloudflare Turnstile भी इसी तरह काम करता है, बस दो नाम बदल जाते हैं। response field है cf-turnstile-response, और यह textarea नहीं बल्कि एक input है:

result = solver.turnstile(sitekey=sitekey, url=page_url)

driver.execute_script(
    "document.querySelector('[name=cf-turnstile-response]')"
    ".value = arguments[0];",
    result["code"],
)

यह फ़ॉर्म में लगे widget को कवर करता है। पूरे पेज वाले interstitial challenge के लिए दो अतिरिक्त वैल्यू और वह user agent चाहिए जिससे हल किया गया था, जिसे Turnstile सॉल्वर पेज समझाता है।

पूरा चलने वाला उदाहरण

# pip install undetected-chromedriver selenium capskip
import undetected_chromedriver as uc
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from capskip import (
    CapSkip, NetworkException, ApiException, TimeoutException,
)

URL = "https://example.com/login"

solver = CapSkip(host="127.0.0.1", port=8080)
driver = uc.Chrome(options=uc.ChromeOptions(), use_subprocess=True)

try:
    driver.get(URL)

    widget = WebDriverWait(driver, 20).until(
        EC.presence_of_element_located((By.CSS_SELECTOR, "[data-sitekey]"))
    )
    sitekey = widget.get_attribute("data-sitekey")

    result = solver.recaptcha(sitekey=sitekey, url=driver.current_url)

    driver.execute_script(
        "document.getElementById('g-recaptcha-response')"
        ".innerHTML = arguments[0];",
        result["code"],
    )

    callback = widget.get_attribute("data-callback")
    if callback:
        driver.execute_script(f"{callback}(arguments[0]);", result["code"])
    else:
        driver.find_element(By.CSS_SELECTOR, "button[type='submit']").click()

except NetworkException:
    print("CapSkip is not running on 127.0.0.1:8080")
except (ApiException, TimeoutException) as err:
    print(f"solve failed: {err}")
finally:
    driver.quit()   # always, or the patched binary lingers

हल और सबमिट एक ही रन में करें। reCAPTCHA token लगभग दो मिनट तक स्वीकार होता है, इसलिए ऐसी script ठीक है जो हल करती है, फिर तीस सेकंड का दूसरा काम करती है, फिर सबमिट करती है। लेकिन जो tokens को बाद के लिए queue कर देती है, वह ठीक नहीं।

आम errors

आप जो देखते हैंकारणफिक्स
This version of ChromeDriver only supports Chrome version Npatched driver ने Chrome के major version का ग़लत अंदाज़ा लगायाइसे साफ़ तौर पर भेजें: uc.Chrome(version_main=N) जहाँ N आपके इंस्टॉल किए गए Chrome का major version है
OSError: [WinError 6] The handle is invalid बाहर निकलते समयdriver बंद होने से पहले ही garbage collect हो गयाइसे driver.quit() को finally block में call करें, और यह चालू रखें: use_subprocess=True
NoSuchElementException को ढूँढते समय: [data-sitekey]widget किसी iframe में है, या अभी render नहीं हुआऊपर बताए तरीक़े से उसका इंतज़ार करें। iframe के मामले में, sitekey iframe के src query string से पढ़ें
ERROR_GOOGLEKEYsolver तक ख़ाली या कटी हुई sitekey पहुँचीहल करने से पहले उसे print करें। देखें ERROR_GOOGLEKEY ठीक करना
NetworkExceptionCapSkip चल नहीं रहा, या port अलग हैऐप शुरू करें और उसकी settings में port जाँचें
token इंजेक्ट हुआ, फिर भी फ़ॉर्म ने मना कर दियापेज callback इस्तेमाल करता है और textarea कभी पढ़ता ही नहींइसे data-callback को token के साथ call करें

हर error code और पैरामीटर यहाँ सूचीबद्ध है: API डॉक्युमेंटेशन.

अक्सर पूछे जाने वाले सवाल

क्या undetected-chromedriver ख़ुद कैप्चा हल करता है?

नहीं। यह उन automation संकेतों को छिपाता है जिनकी वजह से browser flag होता है। render हो चुका widget फिर भी एक वैध token माँगता है, इसलिए आप उसे हल करके नतीजा इंजेक्ट करते हैं। ये दोनों काम एक-दूसरे के पूरक हैं, विकल्प नहीं।

क्या मैं इसे headless चला सकता हूँ?

चला सकते हैं, इसके साथ uc.Chrome(headless=True), जो Selenium के flag के बजाय library के अपने headless patches लगाता है। headed mode के मुक़ाबले ज़्यादा challenges की उम्मीद रखें। token इंजेक्शन ख़ुद दोनों ही तरीक़ों में एक जैसा काम करता है।

क्या हल करने के लिए मुझे प्रॉक्सी चाहिए?

सिर्फ़ तब जब browser पहले से किसी प्रॉक्सी से होकर जा रहा हो। वही प्रॉक्सी proxy={"type": "HTTPS", "uri": "user:pass@host:port"} के रूप में भेजें, ताकि हल और सबमिट एक ही network path साझा करें। प्रॉक्सी reCAPTCHA, Turnstile और GeeTest पर लागू होती हैं, image कैप्चा पर कभी नहीं।

क्या यह सादे Selenium के साथ भी काम करता है?

हाँ। चरण 2 से 4 सामान्य WebDriver calls हैं, इसलिए वे standard Selenium, Selenium Grid और remote drivers पर बिना बदलाव चलते हैं। सिर्फ़ चरण 1 उस patched library के लिए ख़ास है।

सारांश

fingerprint को undetected-chromedriver संभालने दें, और widget ख़ुद संभालें। इसका इंतज़ार करें: [data-sitekey], localhost पर हल करें, token इसमें लिखें: g-recaptcha-response, और data-callback को call करें, जब पेज कोई घोषित करे। driver को finally block में बंद करें ताकि patched binary पीछे न रह जाए।

Selenium का बड़ा हिस्सा Selenium कैप्चा सॉल्वर पेज पर है, पूरी मेथड सूची Python कैप्चा सॉल्वर पेज पर है, और वेब स्क्रैपिंग के लिए कैप्चा हल करना इसे बड़े पैमाने पर चलाने के बारे में बताता है। CapSkip है एक लोकल captcha सॉल्वर, इसलिए ऊपर का हर हल आपकी अपनी मशीन पर होता है।