So lösen Sie Captchas in undetected-chromedriver (Python)

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

undetected-chromedriver patcht Chrome, sodass die Automatisierungs-Flags nicht mehr durchsickern. Damit kommen Sie auf die Seite. An einer reCAPTCHA-Checkbox kommen Sie damit nicht vorbei, denn ein Widget ist keine Fingerprint-Prüfung, sondern eine Token-Anforderung. Ein Captcha in undetected-chromedriver muss weiterhin gelöst und die Antwort ins DOM eingefügt werden.

Vier Schritte: den gepatchten Driver starten, den Sitekey von der Seite lesen, lokal lösen, das Token dorthin schreiben, wo die Seite es erwartet. Hier ist alles in Python.

Was undetected-chromedriver leistet und was nicht

SignalVom Driver abgedeckt
navigator.webdriver und die verräterischen CDP-MerkmaleJa
Gepatchte Binärdatei, damit der Driver nicht als solcher erkannt wirdJa
Eine reCAPTCHA-v2-Checkbox in einem Login-FormularNein
Eine unsichtbare v2- oder v3-Challenge, die die Seite auslöstNein
Ein Turnstile-WidgetNein

Die Unterscheidung ist wichtig, weil der übliche Rat bei einem blockierten Scraper “mehr Stealth” lautet. Wenn ein Widget auf dem Bildschirm steht, entfernt es kein noch so guter Stealth-Modus. Sie brauchen ein Token.

Was Sie brauchen

  • Chrome ist installiert und CapSkip läuft auf 127.0.0.1:8080. Die Einrichtungsanleitung -Seite erklärt die App.
  • Python 3.10 oder neuer.
  • Drei Pakete.
# the patched driver, selenium itself, and the local solver
pip install undetected-chromedriver selenium capskip

Schritt 1: Den gepatchten Driver starten

Importieren Sie es als uc und bauen Sie den Browser genauso wie mit reinem Selenium. Die Options kommen von uc.ChromeOptions(), nicht von Selenium, weil die Bibliothek sie unterwegs patcht:

# 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")

Stapeln Sie darauf kein weiteres Stealth-Plugin. Zwei Patcher, die sich um dieselben Eigenschaften streiten, sind selbst schon ein Erkennungssignal und ein häufiger Grund dafür, dass ein Setup, das früher funktioniert hat, plötzlich nicht mehr läuft.

Schritt 2: Den Sitekey von der Seite lesen

Der Sitekey ist ein öffentliches Attribut am Widget-Element. Lesen Sie ihn aus dem laufenden DOM, statt ihn fest im Code zu hinterlegen, denn viele Seiten rotieren die Keys pro Umgebung:

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)

Verwenden driver.current_url statt der URL, die Sie angefordert haben. Wenn die Seite Sie auf einen Challenge-Pfad weitergeleitet hat, muss der Solver die Seite kennen, auf der Sie tatsächlich gelandet sind.

Schritt 3: Lokal lösen

CapSkip läuft auf Ihrem eigenen Rechner, das Lösen ist also ein Aufruf an localhost. Kein Konto, keine Abrechnung pro Lösung, nichts verlässt den Rechner außer dem Sitekey und der Seiten-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

Varianten sind Optionen und keine unterschiedlichen Methoden. Ergänzen Sie invisible=1 für ein unsichtbares v2-Widget, version="v3" mit einem action für v3 und enterprise=1 für das Enterprise-Produkt.

Schritt 4: Das Token einfügen und den Callback auslösen

Das Token muss in der versteckten g-recaptcha-response -Textarea landen. Das allein genügt für ein einfaches Formular-Submit, weil das Feld mit dem Rest des Formulars gesendet wird:

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

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

Bei Single-Page-Apps ist das anders. Sie lesen die Textarea nie, sondern warten darauf, dass der eigene Callback des Widgets ihnen das Token übergibt. Der Funktionsname steht am Element, Sie können ihn also direkt aufrufen:

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)

Passiert nach dem Einfügen nichts und gibt es kein data-callback, verdrahtet die Seite den Callback in JavaScript statt im Markup. Die reCAPTCHA-v2-Callback-Löser -Seite erklärt, wie Sie ihn in diesem Fall finden.

Turnstile im selben Driver

Cloudflare Turnstile funktioniert genauso, nur mit zwei anderen Namen. Das Antwortfeld heißt cf-turnstile-response, und es ist ein Input statt einer Textarea:

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

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

Damit ist ein in ein Formular eingebettetes Widget abgedeckt. Eine ganzseitige Interstitial-Challenge braucht zwei zusätzliche Werte und den User Agent, mit dem gelöst wurde, wie die Turnstile-Löser -Seite erklärt.

Vollständiges lauffähiges Beispiel

# 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

Lösen und Absenden in einem Durchlauf. Ein reCAPTCHA-Token wird etwa zwei Minuten lang akzeptiert; ein Skript, das löst, dann dreißig Sekunden lang etwas anderes erledigt und danach absendet, ist also in Ordnung. Eines, das Tokens für später in die Warteschlange legt, nicht.

Häufige Fehler

Was Sie sehenUrsacheBeheben
This version of ChromeDriver only supports Chrome version NDer gepatchte Driver hat die falsche Chrome-Hauptversion erratenÜbergeben Sie sie explizit: uc.Chrome(version_main=N) wobei N Ihre installierte Chrome-Hauptversion ist
OSError: [WinError 6] The handle is invalid beim BeendenDer Driver wurde von der Garbage Collection eingesammelt, bevor er heruntergefahren warRufen Sie driver.quit() in einem finally-Block auf und belassen Sie use_subprocess=True
NoSuchElementException beim Suchen nach [data-sitekey]Das Widget steckt in einem iframe oder wurde noch nicht gerendertWarten Sie wie oben darauf. Lesen Sie bei einem iframe den Sitekey stattdessen aus dem src -Query-String des iframe
ERROR_GOOGLEKEYEin leerer oder abgeschnittener Sitekey ist beim Solver angekommenGeben Sie ihn vor dem Lösen aus. Siehe ERROR_GOOGLEKEY beheben
NetworkExceptionCapSkip läuft nicht, oder der Port weicht abStarten Sie die App und prüfen Sie den Port in ihren Einstellungen
Token eingefügt, Formular wird trotzdem abgelehntDie Seite verwendet einen Callback und liest die Textarea nieRufen Sie data-callback mit dem Token aufrufen

Jeder Fehlercode und jeder Parameter ist aufgeführt in der API-Dokumentation.

Häufig gestellte Fragen

Löst undetected-chromedriver Captchas von allein?

Nein. Es verbirgt die Automatisierungssignale, die einen Browser auffällig machen. Ein gerendertes Widget erwartet trotzdem ein gültiges Token, Sie lösen es also und fügen das Ergebnis ein. Die beiden Aufgaben ergänzen sich, sie sind keine Alternativen.

Kann ich es headless betreiben?

Ja, mit uc.Chrome(headless=True), was die eigenen Headless-Patches der Bibliothek anwendet statt des Selenium-Flags. Rechnen Sie mit mehr Challenges als im Headed-Modus. Das Einfügen des Tokens selbst funktioniert in beiden Fällen gleich.

Brauche ich einen Proxy für das Lösen?

Nur wenn der Browser bereits über einen läuft. Übergeben Sie denselben als proxy={"type": "HTTPS", "uri": "user:pass@host:port"} , damit Lösung und Absenden denselben Netzwerkpfad teilen. Proxys gelten für reCAPTCHA, Turnstile und GeeTest, nie für Bild-Captchas.

Funktioniert das auch mit reinem Selenium?

Ja. Die Schritte 2 bis 4 sind gewöhnliche WebDriver-Aufrufe, sie laufen also unverändert mit Standard-Selenium, mit Selenium Grid und mit Remote-Drivern. Nur Schritt 1 ist spezifisch für die gepatchte Bibliothek.

Zusammenfassung

Überlassen Sie undetected-chromedriver den Fingerprint und kümmern Sie sich selbst um das Widget. Warten Sie auf [data-sitekey], lösen Sie gegen localhost, schreiben Sie das Token in g-recaptcha-response, und rufen Sie data-callback auf, wenn die Seite einen deklariert. Beenden Sie den Driver in einem finally -Block, damit die gepatchte Binärdatei nicht hängen bleibt.

Den größeren Selenium-Funktionsumfang finden Sie auf der Selenium-Captcha-Löser -Seite, die vollständige Methodenliste auf der Python-Captcha-Löser -Seite, und Captcha-Lösen für Web Scraping beschreibt den Betrieb im großen Maßstab. CapSkip ist ein lokaler Captcha-Löser, sodass jede der obigen Lösungen auf Ihrem eigenen Rechner stattfindet.