So lösen Sie Captchas in hrequests (Python-TLS-Client)

hrequests captcha - How to Solve CAPTCHAs in hrequests (Python TLS Client)

Ein Captcha-Solve mit hrequests ist kurz, denn hrequests ist nicht der Teil, der das Captcha liest. Es schickt Anfragen über einen Go-TLS-Client, sodass Ihr Handshake wie ein echter Chrome oder Firefox aussieht, und das bringt Sie an der Prüfung vorbei, die zuschlägt, bevor überhaupt eine Challenge gezeichnet wird. Zeichnet die Website trotzdem eine, brauchen Sie etwas, das aus einem sitekey ein Token macht. Worauf es dazwischen ankommt: Das Token muss über dieselbe Session zurückgehen, die die Seite geholt hat, nicht über eine frische.

Was Sie brauchen

  • Python 3.10 oder neuer, mit installiertem hrequests. Fügen Sie das Browser-Extra nur hinzu, wenn Sie wirklich rendern müssen.
  • CapSkip, das auf einem Windows-Rechner läuft. Local-Modus, wenn das Skript auf diesem Rechner läuft, Server-Modus, wenn es woanders läuft.
  • Der sitekey und die Seiten-URL. Schritt 1 holt den sitekey aus der Seite, statt ihn fest zu verdrahten.
  • Ein Proxy, falls dem Ziel neben Ihrem Handshake auch Ihre IP wichtig ist. hrequests nimmt ihn als URL-String entgegen.
# pip install capskip
pip install -U hrequests capskip

# Only if you need the browser. It downloads a browser build.
pip install -U hrequests[all]
python -m hrequests install

Zwei verschiedene Blockaden, zwei verschiedene Werkzeuge

Hier lohnt sich Deutlichkeit, weil die beiden ständig verwechselt werden. hrequests repliziert Browser-TLS-Fingerprints und erzeugt dazu passende Header. Es sieht sich kein Bild an und es erzeugt kein reCAPTCHA-Token. CapSkip erzeugt Tokens und rührt Ihren TLS-Fingerprint nicht an. Blockiert zu werden, bevor überhaupt eine Challenge erscheint, ist ein Handshake-Problem, und die Anleitung zu TLS-Fingerprinting in Python ist die Aufarbeitung dafür. Dass Ihnen eine Challenge gezeigt wird, darum geht es im Rest dieser Seite.

Ein Detail aus der hrequests-Dokumentation sollten Sie kennen, bevor Sie einen Browser wählen. Beim Anlegen einer Session gibt es ein Argument browser, das firefox oder chrome annimmt, und der Fließtext der README widerspricht ihrer Parametertabelle darin, welchen Wert Sie standardmäßig bekommen. Übergeben Sie ihn explizit, dann verschwindet die Mehrdeutigkeit.

Schritt 1: die Seite holen und den sitekey auslesen

Verwenden Sie eine Session statt eines nackten get, denn die Session sammelt die Cookies, und über sie senden Sie später das Token zurück. hrequests liefert einen schnellen HTML-Parser auf der Response mit, sodass Sie den sitekey aus dem Markup lesen können, statt ihn zu raten.

# pip install hrequests
import hrequests

SITE = "https://example.com/page-with-recaptcha"

# Name the browser. Headers are generated to match it and the OS.
session = hrequests.Session(browser="chrome", os="win")

resp = session.get(SITE)

# The parser is selectolax under the hood, so this is cheap.
widget = resp.html.find(".g-recaptcha")
sitekey = widget.attrs["data-sitekey"]

print(resp.status_code, sitekey)

Steht das Widget nicht im ursprünglichen HTML, wird es per JavaScript eingefügt und Sie brauchen ein Rendering. Springen Sie aber zuerst zum Browser-Abschnitt weiter unten, bevor Sie danach greifen, denn die meisten reCAPTCHA- und Turnstile-Widgets stehen im ausgelieferten Markup, und Rendering kostet Sie einen Browser-Prozess für nichts.

Schritt 2: mit CapSkip lösen

Ein Aufruf. Das SDK übermittelt die Challenge und fragt die Antwort ab, beginnend bei 250 Millisekunden und mit wachsendem Abstand, weshalb es eine handgeschriebene Schleife gegen die rohe API meist schlägt.

# pip install capskip
from capskip import CapSkip

# 127.0.0.1 only if this script runs on the solver machine.
solver = CapSkip(host="127.0.0.1", port=8080)

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

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

Jeder andere Typ, den CapSkip unterstützt, hat dieselbe Form. Setzen Sie invisible oder enterprise auf 1, oder version auf v3 mit einem action-Namen. Turnstile und GeeTest haben eigene Methoden, und bei Turnstile lohnt es sich, die Hinweise zu lesen, denn eine Challenge-Seite braucht zwei zusätzliche Werte und den User-Agent, der mit dem Token zurückkommt. Diese zusätzlichen Werte werden behandelt auf die Cloudflare-Turnstile-Löser-Seite. Jeder Parameter für jeden Typ ist aufgeführt in der CapSkip-API-Dokumentation.

Schritt 3: das Token über dieselbe Session senden

Das ist der Schritt, den Leute falsch machen, und der ganze Grund, hrequests statt eines schlichten HTTP-Clients zu verwenden. Die Session, die die Seite geholt hat, hat einen TLS-Fingerprint, einen generierten Header-Satz und alle Cookies, die die Website ausgegeben hat. Senden Sie das Token über genau diese Session, dann sieht die Übermittlung so aus, als käme sie vom selben Client. Senden Sie es über eine frische Session oder, noch schlimmer, über die Standardbibliothek, dann ändert sich der Handshake mitten im Ablauf, und das ist selbst schon ein Signal.

# Same session object, so the fingerprint, headers and cookies
# are the ones the site already saw on the GET.
posted = session.post(
    SITE,
    data={
        "username": "YOUR_USERNAME",
        "g-recaptcha-response": token,
    },
    timeout=30,
)

print(posted.status_code)
session.close()

Tun Sie es sofort. Ein reCAPTCHA-Token ist etwa zwei Minuten gültig, alles, was zwischen der Lösung und dem Senden liegt, verbraucht also dieses Budget. Der Fehlerfall sieht aus wie ein Token, das grundlos abgelehnt wurde, und er ist an anderer Stelle ausführlich beschrieben, falls Sie darauf stoßen.

Der Timeout für Anfragen liegt in hrequests standardmäßig bei 30 Sekunden. Das reicht hier, denn er deckt den Formular-POST ab und nicht die Lösung. Die Lösung hat ihre eigene Obergrenze im SDK: 120 Sekunden für Bild-Captchas und 300 für reCAPTCHA, Turnstile und GeeTest.

Den Löser auf einer anderen Maschine betreiben

Das Argument host oben ist das Einzige, was sich ändert, wenn Skript und Löser nicht mehr denselben Rechner teilen. CapSkip hat zwei Verbindungsmodi. Der Local-Modus bindet an 127.0.0.1 und bedient nur dieses Gerät. Der Server-Modus bindet an Ihre Netzwerkadresse oder öffentliche IP, sodass ein Scraper auf einem anderen Rechner, einem VPS oder in einem Container denselben Windows-Rechner über die API erreichen kann. Beide finden Sie unter Verbindungseinstellungen, und eine statische öffentliche IP ist es wert, wenn der Aufrufer außerhalb Ihres Netzwerks sitzt. Der Server-Modus ändert nur, auf welcher Adresse der Löser lauscht: dieselbe Hardware, derselbe Rechner, dasselbe unbegrenzte Lösen ohne Gebühren pro Lösung.

import os
from capskip import CapSkip

# Same script on a laptop and on a scraping box. The env var
# decides; CAPSKIP_HOST and CAPSKIP_PORT are read by the SDK too.
solver = CapSkip(
    host=os.environ.get("CAPSKIP_HOST", "127.0.0.1"),
    port=8080,
)

Proxys sind hier ein Wort wert, denn hrequests und CapSkip nehmen sie getrennt entgegen. Der Proxy, den Sie hrequests geben, entscheidet, woher Ihr Seitenabruf kommt. Der Proxy, den Sie dem Löser geben, entscheidet, von wo aus die Challenge gelöst wird, und CapSkip akzeptiert einen für reCAPTCHA, Turnstile und GeeTest, aber nicht für Bild-Captchas. Dass beide zusammenpassen, ist auf Websites wichtig, die ein Token an eine Adresse binden, und die Begründung dafür steht in der Anleitung zur Captcha-Proxy-Rotation.

Wann Sie den Browser wirklich brauchen, und die Falle darin

hrequests kann eine Response mit einem render-Aufruf an einen echten Browser übergeben, und der Reiz daran ist, dass die Cookies in beide Richtungen mitgehen: Die Browser-Session erbt die Cookies der Session, und beim Schließen der Seite werden die neuen zurückgeführt. Das ist wirklich nützlich für einen Ablauf, der irgendwo klicken muss.

Hier ist der Teil, der Leute einen Nachmittag kostet. Die Firefox-Engine in hrequests ist Camoufox, direkt aus dem Camoufox-Python-Paket gestartet, und Camoufox führt Seitenskripte in einem isolierten Scope aus. Ein isolierter Scope kann das DOM lesen, aber nicht verändern, der naheliegende Schritt, per Skript das Token in die Response-Textarea zu schreiben, bewirkt also überhaupt nichts, und zwar stillschweigend. hrequests stellt ein schlichtes evaluate bereit, das ein Skript und ein Argument annimmt, ohne jede Möglichkeit, die Main World anzufordern.

Der Ausweg: hrequests reicht seine zusätzlichen Keyword-Argumente direkt an Camoufox weiter, damit steht Ihnen der eigene Schalter von Camoufox zur Verfügung. Schalten Sie die Main-World-Auswertung beim Start ein und stellen Sie dem Skript dann das Präfix voran.

import hrequests

# The kwargs go through to Camoufox. Without main_world_eval the
# write below is discarded and nothing tells you.
page = hrequests.BrowserSession(headless=True, main_world_eval=True)
page.goto(SITE)

SCRIPT = (
    "mw:(t) => { "
    "document.getElementById('g-recaptcha-response').value = t; }"
)

# The second argument arrives as t inside the function.
page.evaluate(SCRIPT, token)

page.click("#submit")
page.close()   # merges cookies back into the session

Zwei Wege, die ganze Frage zu umgehen. Nutzen Sie die Chrome-Engine, das sind gewöhnliche Playwright-Semantiken, um den Preis der Fingerprint-Rotation und der menschlichen Cursor-Emulation, die laut hrequests nur Firefox unterstützt. Oder machen Sie es wie Schritt 3 und injizieren Sie gar nicht: Nehmen Sie das Token zurück in die TLS-Session und senden Sie das Formular selbst ab. Für ein Login oder ein Suchformular ist das einfacher und schneller, und genau deshalb stellt diese Anleitung den Browser ans Ende. Wenn Sie Camoufox direkt statt über hrequests steuern, wird das Verhalten des isolierten Scopes samt seiner übrigen Folgen behandelt in der Camoufox-Captcha-Anleitung.

Mehrere gleichzeitig lösen

hrequests bietet Ihnen drei Wege, Anfragen zu überlappen, und CapSkip bietet Ihnen einen Weg, Lösungen zu überlappen. Sie lassen sich kombinieren, aber sie sind nicht dasselbe.

Was Sie überlappen wollenWelches Werkzeug das erledigt
Eine Handvoll Seitenabrufe, abgeschickt und später ausgelesenSetzen Sie nohup auf true und lesen Sie dann ein Attribut, wenn Sie es brauchen
Eine Liste von URLs in einem AufrufÜbergeben Sie die Liste direkt an die Request-Methode
Viele Anfragen mit einer Obergrenze für die ParallelitätBauen Sie ungesendete Anfragen und mappen Sie sie dann mit einer Größenbegrenzung
Mehrere Captcha-Lösungen gleichzeitigDer asynchrone Client des Python-SDK, der eine echte Implementierung ist und kein Alias

Die letzte Zeile lohnt das Nachlesen, denn Python ist das einzige CapSkip-SDK, in dem der Async-Client eine eigene Implementierung ist und nicht nur ein Name für dieselbe Klasse. Das Batching-Muster ist beschrieben in der Anleitung zum parallelen Lösen von Captchas mit Python. Die Wahl zwischen hrequests und einem gängigen Async-Client für die Abrufhälfte ist eine eigene Frage, und der Anleitung zu httpx und aiohttp legt die Abwägungen dar.

Häufige Fehler und was sie bedeuten

Was Sie sehenUrsacheBeheben
NetworkException aus dem SDKCapSkip läuft nicht oder ist von diesem Rechner aus nicht erreichbarStarten Sie es, oder wechseln Sie in den Server-Modus und setzen Sie host
Das Token wird geschrieben, aber das Widget bleibt ungelöstDer isolierte Scope von Camoufox hat den Schreibvorgang im DOM verworfenStarten Sie mit eingeschalteter Main-World-Auswertung und stellen Sie dem Skript das Präfix voran
MissingLibraryException bei einem render-Aufrufhrequests wurde ohne das Browser-Extra installiertInstallieren Sie das Extra und führen Sie dann den Installationsbefehl der Bibliothek aus
Ein korrektes Token wird von der Website abgelehntDas Senden lief über eine andere Session oder einen anderen ClientSenden Sie über die Session, die die Seite geholt hat
Ein korrektes Token wird nach einer langen Pause abgelehntEs ist abgelaufen, bevor es übermittelt wurdeLösen und übermitteln Sie direkt hintereinander, ohne etwas dazwischen
ERROR_GOOGLEKEY in der AntwortDer aus der Seite geparste sitekey ist nicht der im WidgetLesen Sie das Attribut data-sitekey statt eines Script-Tags
TimeoutException nach 300 SekundenDer sitekey und die Seiten-URL sind nicht das Paar dieses Widgets, deshalb läuft die Lösung bis zur Obergrenze von 300 SekundenPrüfen Sie, ob der sitekey und die Seiten-URL das Paar sind, das das Widget tatsächlich verwendet
Die Browser-Session wird nie freigegebenEine ohne Kontextmanager erzeugte Seite wurde nicht geschlossenNutzen Sie die with-Form, oder rufen Sie close in einem finally-Block auf

FAQ

Löst hrequests Captchas von allein?

Nein. Es repliziert Browser-TLS-Fingerprints und erzeugt dazu passende Header, was viele Blockaden verhindert, bevor überhaupt eine Challenge gezeichnet wird, und es kann in einer gerenderten Seite menschliche Mausbewegungen und Tastatureingaben nachahmen. Nichts davon liest ein verzerrtes Bild oder erzeugt ein reCAPTCHA-Token. Das sind eigene Probleme, und sie brauchen einen Löser.

Brauche ich das Browser-Extra überhaupt?

Nur, wenn Sie rendern müssen. Das Extra zieht den Browser-Stack nach sich, braucht danach einen eigenen Installationsbefehl und ist ein großer Download. Für den üblichen Ablauf, also Seite holen, sitekey lesen, lösen, Formular senden, reicht die schlichte Installation, und das Ganze läuft als HTTP-Anfragen. Fügen Sie das Extra hinzu, wenn das Widget wirklich nicht im ausgelieferten Markup steht oder wenn sich das Formular nur über echte Klicks absenden lässt.

Als welcher Browser soll sich die Session ausgeben?

Als der, den Sie ausdrücklich benennen. hrequests akzeptiert firefox oder chrome und erzeugt dazu passende Header, und es hält die Header-Version bewusst nicht mit der TLS-Version im Gleichschritt, mit der Begründung, dass Erkennungssysteme die beiden selten korrelieren und die zusätzliche Streuung nach mehr Clients aussieht. Zum Rendern empfiehlt die Bibliothek Firefox, weil Chrome dort weder Fingerprint-Rotation noch die menschliche Cursor-Emulation unterstützt.

Kann der Löser auf einem anderen Rechner laufen als der Scraper?

Ja, und das ist der Normalfall, sobald das Scraping vom Laptop wegzieht. Versetzen Sie CapSkip in den Server-Modus, damit es auf Ihrer Netzwerkadresse oder einer öffentlichen IP statt auf der Loopback-Adresse lauscht, und richten Sie dann das Argument host darauf. Eine statische öffentliche IP ist empfehlenswert, wenn der Aufrufer außerhalb Ihres Netzwerks sitzt. Es ist derselbe Windows-Rechner, der dasselbe unbegrenzte Lösen erledigt; nur die Adresse ändert sich.

Die Kurzfassung

Holen Sie die Seite mit einer benannten Session, damit Fingerprint und Cookies stabil bleiben. Lesen Sie den sitekey mit dem eingebauten Parser aus der Response. Lösen Sie ihn mit einem einzigen SDK-Aufruf. Senden Sie das Token sofort über dieselbe Session zurück, und greifen Sie nur dann zu einem gerenderten Browser, wenn das Widget nicht im Markup steht. Wenn Sie doch rendern, denken Sie daran, dass die Firefox-Engine Camoufox ist und dass ein Schreibvorgang im DOM aus einem isolierten Scope ohne Fehlermeldung verschwindet, schalten Sie also die Main-World-Auswertung ein oder lassen Sie die Injektion ganz weg.

Eines sollten Sie wissen, bevor Sie einen Scraper skalieren, der häufig auf Challenges trifft: CapSkip erledigt Captcha-Umgehung auf Hardware, die Ihnen bereits gehört, und rechnet nie pro Lösung ab, sodass ein Lauf mit zehn Challenges und ein Lauf mit zehntausend genau gleich viel kosten.