solvethree in einer Scrapy-Downloader-Middleware verwenden
Verwenden Sie eine asynchrone Downloader-Middleware, um nur Anfragen zu lösen, die Ihr Spider ausdrücklich markiert. Führen Sie das synchrone solvethree-SDK in einem Worker-Thread aus und geben Sie anschließend einen FormRequest mit dem Token, dem Proxy und der zurückgegebenen Browseridentität zurück.
Das Beispiel verarbeitet einen konfigurierten reCAPTCHA-Enterprise-Formularendpunkt. Es erkennt keine Challenges und ermittelt nicht, wie eine beliebige Website ihr Token erwartet.
Auf dieser Seite
Ziel vor dem Aktivieren der Middleware konfigurieren
- Verwenden Sie Scrapy 2.19+, Python 3.10+ und das offizielle solvethree-Python-SDK. Das SDK ist synchron; es bietet keinen nativen asynchronen Client.
- Erstellen Sie in der Konsole ein aktives Websiteprofil für Ihren Workspace. Durch das Senden eines Hostnamens und einer Aktion wird keines erstellt. Siehe Einrichtung eines Websiteprofils.
- Setzen Sie TARGET_URL auf die exakte URL zum Absenden des Formulars, SOLVETHREE_PROXY auf den für diese Anwendungsanfrage verwendeten Proxy und SOLVETHREE_API_KEY auf Ihren Workspace-Schlüssel. Bewahren Sie den Schlüssel serverseitig auf.
- Aktivieren Sie AsyncioSelectorReactor und registrieren Sie die Middleware mit Priorität 740, wie unten gezeigt. Dadurch wird sie vor HttpProxyMiddleware mit Priorität 750 platziert.
Nur ausdrücklich markierte Anfragen lösen
# middlewares.py; Scrapy 2.19+, Python 3.10+, official solvethree SDK.
import asyncio
import os
from urllib.parse import urlsplit
from scrapy.http import FormRequest
from solvethree import Solvethree
class CaptchaMiddleware:
async def process_request(self, request):
if not request.meta.get("solvethree_form") or request.meta.get("solvethree_applied"):
return None
target = os.environ["TARGET_URL"]
if request.url != target:
raise ValueError("Only the configured form target may use this middleware")
proxy = os.environ["SOLVETHREE_PROXY"]
def solve():
return Solvethree(os.environ["SOLVETHREE_API_KEY"]).solve({
"site": urlsplit(target).hostname, "action": "login", "proxy": proxy,
"requestId": request.meta["solvethree_request_id"],
}, timeout=180)
result = await asyncio.to_thread(solve)
solution = result["solution"]
fields = dict(request.meta["solvethree_fields"])
fields["g-recaptcha-response"] = solution["token"]
meta = {**request.meta, "proxy": proxy, "solvethree_applied": True,
"dont_retry": True, "dont_redirect": True}
return FormRequest(target, formdata=fields, callback=request.callback,
errback=request.errback, headers={"User-Agent": solution["userAgent"],
"sec-ch-ua": solution["secChUa"]}, meta=meta, dont_filter=True)
# settings.py:
# TWISTED_REACTOR = "twisted.internet.asyncioreactor.AsyncioSelectorReactor"
# DOWNLOADER_MIDDLEWARES = {"myproject.middlewares.CaptchaMiddleware": 740}
# The spider first loads its form/CSRF data with the same proxy and cookiejar.
# Then yield a Request(TARGET_URL, callback=your_result_handler, meta={
# "solvethree_form": True, "solvethree_request_id": one_saved_logical_job_id,
# "solvethree_fields": {"csrf": token_from_the_form, "email": "your-test-value"},
# "cookiejar": your_cookiejar_id,
# })
# Inspect the final response in your_result_handler; a ready task is not that response.Die Methode process_request der Middleware nimmt nur request entgegen, ohne das veraltete Argument spider. Nicht markierte Anfragen werden unverändert durchgereicht. Eine markierte Anfrage muss exakt mit TARGET_URL übereinstimmen; bei einer Abweichung wird ein Fehler ausgelöst, statt ein Token an einen anderen Endpunkt zu senden.
asyncio.to_thread hält die Netzwerkaufrufe und das Polling des synchronen SDKs vom Event-Loop-Thread fern. process_request lediglich als async zu deklarieren, würde dafür nicht ausreichen. Das SDK erstellt eine Aufgabe und wartet auf ein fertiges Ergebnis oder löst eine Ausnahme aus; anschließend erstellt die Middleware die Formularübermittlung.
An das tatsächlich von Ihrer Anwendung übermittelte Formular anpassen
- 1.
Richtige Aktion und richtiges Token-Feld festlegen
Das Beispiel verwendet die Aktion login und trägt solution.token in g-recaptcha-response ein. Passen Sie diese Werte an die Integration des Ziels an. Das Feld site der Aufgabe wird aus dem Hostnamen von TARGET_URL abgeleitet; reCAPTCHA-Aufgaben nehmen keine Felder type oder url entgegen. Wenn recaptchaType weggelassen wird, wird enterprise-v3 ausgewählt.
- 2.
Vorhandene Formularfelder bereitstellen
Der Spider muss solvethree_fields mit den erforderlichen Feldern des Endpunkts einschließlich seines aktuellen CSRF-Werts befüllen. Die Middleware kopiert diese Felder und fügt das Token hinzu; sie lädt weder das Formular noch extrahiert sie versteckte Eingabefelder.
- 3.
Sitzung konsistent halten
Laden Sie das ursprüngliche Formular über denselben Proxy und mit derselben Browseridentität, die die Anwendung erfordert. Übergeben Sie seine cookiejar-ID in den Metadaten der markierten Anfrage. Der zurückgegebene FormRequest behält dieses cookiejar bei und verwendet solution.userAgent sowie solution.secChUa, aber das Beispiel bereitet die vorherige Sitzung weder vor noch repariert es sie.
- 4.
Antwort der Anwendung behandeln
Geben Sie einen Callback an, der prüft, ob das Formular erfolgreich abgesendet wurde, und einen Errback für fehlgeschlagene Anfragen. Eine fertige Aufgabe bedeutet, dass eine Lösung generiert wurde, nicht, dass die Website die nachfolgende Anfrage akzeptiert hat.
Dieses Beispiel verwendet bewusst einen einzigen Proxy zum Lösen und Übermitteln. Ersetzen Sie ihn nach dem Lösen nicht durch einen anderen Proxy. Prüfen Sie außerdem jede benutzerdefinierte Downloader-Middleware, die User-Agent oder Client Hints umschreibt: Sie darf die mit der Lösung zurückgegebene Identität nicht überschreiben.
Erneutes Lösen bei Wiederholungsversuchen verhindern
Speichern Sie solvethree_request_id, bevor Sie die markierte Anfrage per yield übergeben, und behalten Sie den Wert für diesen logischen Lösungsversuch bei. Eine requestId akzeptiert 1–64 ASCII-Buchstaben, Ziffern, Unterstriche oder Bindestriche. Durch ihre Wiederverwendung mit identischen Aufgabeneingaben wird die vorhandene Aufgabe wiederhergestellt; wenn Sie diese Eingaben bei gleichbleibender ID ändern, entsteht ein Konflikt.
Der zurückgegebene FormRequest setzt solvethree_applied, damit er keinen weiteren Lösungsversuch auslöst. Außerdem setzt er dont_retry und dont_redirect und verhindert so automatische Wiederholungen und Weiterleitungen für diese Übermittlung. Diese Flags verhindern nicht, dass Ihr eigener Callback oder Job-Runner eine weitere Anfrage startet; treffen Sie diese Entscheidung daher ausdrücklich.
- Beim Aufruf zum Lösen tritt ein Timeout auf.
Prüfen Sie, ob bereits eine Aufgabe erstellt wurde. Ein Verbindungs-Timeout beweist nicht, dass die Erstellung fehlgeschlagen ist.
Probiere Folgendes: Rufen Sie die bekannte Aufgabe ab oder stellen Sie sie mit der gespeicherten requestId und identischen Aufgabeneingaben wieder her, bevor Sie einen neuen logischen Lösungsvorgang erstellen.
- Beim Lösen wird eine Ausnahme ausgelöst, statt ein Ergebnis zurückzugeben.
Unterscheiden Sie zwischen einem HTTP-Anfragefehler und einem endgültigen Aufgabenfehler. Prüfen Sie bei einer fehlgeschlagenen Aufgabe errorCode und error.
Probiere Folgendes: Behandeln Sie den Fehler, statt dieselbe markierte Anfrage wiederholt per yield zurückzugeben. Korrigieren Sie ungültige Eingaben vor einem erneuten Versuch; fehlgeschlagene Aufgaben dürfen nicht weiter abgefragt werden.
- Die Website lehnt das übermittelte Formular ab.
Prüfen Sie zuerst das ausgehende Token-Feld, die CSRF-Felder, Cookies, den Proxy und die Browseridentität.
Probiere Folgendes: Korrigieren Sie die Anwendungsanfrage, bevor Sie für einen weiteren Lösungsvorgang bezahlen. Das Feld muss solution.token enthalten, nicht die Aufgaben-ID oder ein veraltetes Token.
Quellen und API-Referenz
Führe deinen ersten Task aus.
Starte mit $5 Workspace-Guthaben.