So lösen Sie Friendly Captcha in Python anhand des Script-Tags

solve friendly captcha in python - How to Solve Friendly Captcha in Python From the Script Tag

Um Friendly Captcha in Python zu lösen, lesen Sie das Attribut data-sitekey am Element frc-captcha aus, suchen das Script-Tag, das das Widget lädt, unterscheiden anhand dieses Skripts v1 von v2 und übergeben sitekey, Seiten-URL, Version und die vollständige Adresse des Skripts an die Methode friendly_captcha von CapSkip. Sie erhalten einen Token zurück, den Sie bei v1 in frc-captcha-solution und bei v2 in frc-captcha-response senden. Entscheidend ist das Script-Tag. Friendly Captcha liefert unter einem Namen und mit einem gemeinsamen sitekey-Format zwei voneinander unabhängige Protokolle aus, und wer das falsche löst, bekommt einen gültig aussehenden Token, der stillschweigend abgelehnt wird. CapSkip hat Friendly Captcha in Version 1.4.0 hinzugefügt. Dieser Leitfaden behandelt das Auslesen der Seite, den Aufruf, das Absenden und das gleichzeitige Ausführen vieler Lösevorgänge mit AsyncCapSkip.

Was Sie brauchen

  • CapSkip 1.4.0 oder neuer auf einem Windows-Rechner. Mit diesem Release kam Friendly Captcha dazu, zusammen mit CaptchaFox und Capy Puzzle.
  • Python 3.10 oder neuer und Version 1.3.0 oder neuer des Pakets capskip, das erste Release mit friendly_captcha. Die Beispiele verwenden außerdem requests, um die Seite abzurufen und das Formular zu senden.
  • Die URL der Seite, die das Widget anzeigt. Der sitekey, die Skriptadresse und der Feldname stammen alle aus dem HTML dieser Seite, und Schritt 1 zeigt, wo sie stehen.
  • Eine Adresse für den Solver. Der Local-Modus antwortet auf 127.0.0.1 nur für dieses Gerät; der Server-Modus lauscht auf Ihrer Netzwerkadresse oder öffentlichen IP, damit ein Skript auf einem anderen Rechner ihn über die API aufrufen kann. Beide finden Sie unter Verbindungseinstellungen, und Schritt 4 erklärt, wann Sie wechseln sollten.
# pip install capskip requests
pip install "capskip>=1.3.0" requests

Behalten Sie die Anführungszeichen bei. In cmd ist ein Größer-als-Zeichen ohne Anführungszeichen eine Umleitung: pip installiert dann ohne jede Versionsprüfung, was es unter capskip findet, und schreibt seine Ausgabe in eine Datei namens 1.3.0. PowerShell reicht das Argument unverändert durch, aber die Anführungszeichen funktionieren in jeder Shell.

Schritt 1: Das Widget und sein Script-Tag auslesen

Beide Versionen rendern dasselbe Element, ein div mit der Klasse frc-captcha und einem Attribut data-sitekey. Das Element liefert Ihnen also den sitekey, aber nichts über das Protokoll. Die Version steckt im Script-Tag, das das Widget lädt, denn v1 und v2 sind verschiedene Pakete mit unterschiedlichen Dateinamen:

<!-- v2: the @friendlycaptcha/sdk package -->
<div class="frc-captcha" data-sitekey="YOUR_SITEKEY"></div>
<script type="module" src="https://cdn.jsdelivr.net/npm/@friendlycaptcha/sdk/site.min.js" async defer></script>
<script nomodule src="https://cdn.jsdelivr.net/npm/@friendlycaptcha/sdk/site.compat.min.js" async defer></script>

<!-- v1: the friendly-challenge package -->
<div class="frc-captcha" data-sitekey="YOUR_SITEKEY"></div>
<script type="module" src="https://cdn.jsdelivr.net/npm/friendly-challenge/widget.module.min.js" async defer></script>
<script nomodule src="https://cdn.jsdelivr.net/npm/friendly-challenge/widget.min.js" async defer></script>

Die meisten Websites legen in diesem Pfad eine Versionsnummer fest, was hier nichts ändert. Die Standardbibliothek von Python reicht aus, um all das auszulesen. Dieser Parser behält die Attribute des Widget-Elements und die Adresse jedes Skripts, das kein nomodule-Fallback ist, aufgelöst gegen die Seiten-URL:

# pip install capskip requests
from html.parser import HTMLParser
from urllib.parse import urljoin

import requests


class FriendlyPage(HTMLParser):
    """Collects the frc-captcha element and the page's script tags."""

    def __init__(self, page_url):
        super().__init__()
        self.page_url = page_url
        self.widget = {}
        self.scripts = []

    def handle_starttag(self, tag, attrs):
        a = dict(attrs)
        if "frc-captcha" in (a.get("class") or "").split():
            self.widget = a
        # Skip nomodule fallbacks; keep full addresses, never relative.
        if tag == "script" and a.get("src") and "nomodule" not in a:
            self.scripts.append(urljoin(self.page_url, a["src"]))


session = requests.Session()
page = FriendlyPage("https://example.com/signup")
page.feed(session.get(page.page_url, timeout=30).text)

Der Aufruf von urljoin hat seinen Grund. Ein selbst gehostetes Widget kann ein relatives src haben, etwa /js/site.min.js, und CapSkip braucht eine Adresse, die es abrufen kann: Bei v2 lädt es genau dieses Skript in seinem eigenen Browser, um das Lösen auszuführen. Übergeben Sie nur den nackten Pfad, lädt das Widget nie.

Schritt 2: Die Version wählen und friendly_captcha aufrufen

CapSkip bestimmt die Version in einer festen Reihenfolge und hört bei der ersten Antwort auf: zuerst die Version, die Sie übergeben, dann die Skriptadresse, die Sie als module_script übergeben, dann der Standardwert v1. Dieser letzte Schritt ist die Falle. Ein Skript, aus dem CapSkip keine Version ablesen kann, etwa ein gebündeltes /assets/app.4f2a.js, wird kommentarlos als v1 gelöst, und eine v2-Website lehnt dann jeden Token ab.

Bestimmen Sie die Version also in Ihrem eigenen Code, wo Sie sich weigern können zu raten. Der Paketname in einer CDN-Adresse ist eindeutig. Ein selbst gehosteter Build lässt ihn oft weg, behält aber den Dateinamen, so wie es das offizielle WordPress-Plugin macht: site.min.js ist v2, und widget.module.min.js oder widget.min.js ist v1. Die eigenen Attribute des Widgets sind der letzte Ausweg, denn die beiden Versionen benennen ihre Optionen unterschiedlich:

from urllib.parse import urlparse

V2_FILES = {"site.min.js", "site.compat.min.js"}
V1_FILES = {"widget.module.min.js", "widget.min.js", "widget.polyfilled.min.js"}

def friendly_version(page):
    # Package names are unambiguous, so check them first.
    for src in page.scripts:
        if "@friendlycaptcha/sdk" in src:
            return "v2", src
        if "friendly-challenge" in src:
            return "v1", src
    # Self-hosted builds usually keep the file name. Themes ship their own
    # site.min.js too, so only trust a path that says friendly.
    for src in [s for s in page.scripts if "friendly" in s.lower()]:
        name = urlparse(src).path.rsplit("/", 1)[-1]
        if name in V2_FILES:
            return "v2", src
        if name in V1_FILES:
            return "v1", src
    # Last resort: v2 and v1 name their widget options differently.
    if {"data-api-endpoint", "data-form-field-name"} & page.widget.keys():
        return "v2", None
    if {"data-puzzle-endpoint", "data-solution-field-name"} & page.widget.keys():
        return "v1", None
    raise RuntimeError("v1 or v2? Read the page and set it by hand.")

Die Prüfung des Dateinamens vertraut nur Pfaden, die friendly enthalten, denn ein Theme kann ein eigenes site.min.js laden, das mit dem Widget nichts zu tun hat.

Dann folgt der Aufruf. Senden Sie die gefundene Version und, falls vorhanden, die Skriptadresse. Die explizite Version hat Vorrang, und bei v2 sagt die Adresse CapSkip, dass es mit genau dem Build lösen soll, den die Website lädt. Ein Wert None wird einfach aus der Anfrage weggelassen.

from capskip import CapSkip

solver = CapSkip(host="127.0.0.1", port=8080)

version, script = friendly_version(page)
result = solver.friendly_captcha(
    page.widget["data-sitekey"],
    "https://example.com/signup",
    version=version,
    module_script=script,
    # data-api-endpoint="eu" (v2) or data-puzzle-endpoint (v1).
    api_server=page.widget.get("data-api-endpoint")
    or page.widget.get("data-puzzle-endpoint"),
)

print(result["token"][:40])   # v2 tokens start with AQQA.

Die Zeile mit api_server deckt Websites am EU-Endpunkt von Friendly Captcha ab. Auch der sitekey einer EU-Website bekommt vom globalen Endpunkt einen Token, ein Lösen dort scheitert also erst bei der Verifizierung durch die Website selbst, dasselbe stille Scheitern wie bei der Version. Ist keines der beiden Attribute vorhanden, ist der Wert None, und CapSkip verwendet den globalen Endpunkt.

Das Ergebnis ist ein einfaches dict. result["token"] ist die Zeichenfolge zum Absenden, result["code"] enthält dieselbe Zeichenfolge für Skripte, die von einem anderen Solver portiert wurden, und result["captchaId"] ist die Referenz von CapSkip für den Auftrag. Eine Version außer v1, v2, 1 oder 2, ein leerer sitekey oder eine Option, die die Methode nicht annimmt, löst eine ValidationException aus, bevor überhaupt etwas gesendet wird.

Schritt 3: Den Token in das Feld senden, das das Widget verwendet

Der Feldname ist der zweite Unterschied zwischen den Versionen, und eine Website kann ihn am Widget-Element umbenennen:

import requests

# A renamed field wins; otherwise the default for the version.
field = (
    page.widget.get("data-form-field-name")          # v2 rename
    or page.widget.get("data-solution-field-name")   # v1 rename
    or ("frc-captcha-response" if version == "v2" else "frc-captcha-solution")
)

# session is the requests.Session that fetched the page.
resp = session.post(
    "https://example.com/signup",
    data={"email": "YOUR_EMAIL", field: result["token"]},
    # Browsers send the page as Referer; some servers refuse a post without it.
    headers={"Referer": page.page_url},
    timeout=30,
)
print(resp.status_code)

Ein Sonderfall bei v1: Ist data-solution-field-name auf einen einzelnen Bindestrich gesetzt, schreibt das Widget überhaupt kein verstecktes Feld, und das eigene Skript der Website sendet den Token auf anderem Weg. Bilden Sie diese Anfrage nach, wie unten beschrieben.

Senden Sie an die Adresse, auf die das Attribut action des Formulars zeigt, und nehmen Sie die übrigen Felder des Formulars mit, auch versteckte wie etwa einen CSRF-Token. Wenn Sie die Seite über eine einzige requests.Session abrufen und das Formular darüber senden, bleiben die Cookies der Website erhalten, von denen dieser CSRF-Token meist abhängt. Senden Sie die Seiten-URL außerdem als Referer: requests sendet weder einen Referer- noch einen Origin-Header, und manche Frameworks, darunter Django, lehnen einen HTTPS-Formular-POST ab, der keinen von beiden hat, egal wie korrekt Cookie und Token sind.

Senden Sie den Token mit data= im Body, niemals mit params= in der URL. Ein v2-Token ist rund sechs Kilobyte groß, genug, um das Limit eines Servers für die URL-Länge zu sprengen, während ein v1-Token aus vier durch Punkte getrennten Teilen und einigen hundert Zeichen besteht. Reichen Sie ihn unverändert weiter, ohne Kürzen oder Neukodieren. Er gilt für genau ein Absenden: Die Verifizierung von Friendly Captcha lehnt eine Antwort ab, die bereits verwendet wurde oder abgelaufen ist, lösen Sie also für jedes Formular neu.

Manche Websites senden das Formular per JavaScript mit einem JSON-Body statt als Formular-POST. Wenn das Absenden trotz korrektem Feldnamen scheitert, öffnen Sie die DevTools, senden einmal von Hand ab und übernehmen genau das, was die Seite sendet.

Schritt 4: Viele Formulare gleichzeitig und wo der Solver läuft

AsyncCapSkip ist in Python ein echter asynchroner Client auf Basis von httpx und kein Alias des blockierenden Clients, sodass ein einziger Event Loop viele Lösevorgänge gleichzeitig in Arbeit halten kann. Begrenzen Sie sie mit einem Semaphor, damit nie mehr laufen, als CapSkip gleichzeitig bearbeitet. Die Einstellung Max. Threads im Friendly-Captcha-Bereich von CapSkip steht standardmäßig auf 10.

import asyncio
from capskip import AsyncCapSkip

solver = AsyncCapSkip(host="127.0.0.1", port=8080)
limit = asyncio.Semaphore(10)   # match Friendly Captcha Max. Threads

async def solve(sitekey, url, version, script):
    async with limit:
        r = await solver.friendly_captcha(
            sitekey, url, version=version, module_script=script)
        return r["token"]

async def main(jobs):
    # jobs: (sitekey, url, version, script) tuples from Step 2
    return await asyncio.gather(*(solve(*j) for j in jobs))

Rechnen Sie mit schwankenden Lösezeiten. Friendly Captcha legt die Arbeitsmenge pro Anfrage fest und erhöht sie für Adressen, die es schon oft gesehen hat, und CapSkip löst jedes v2-Widget in einem echten Browser. Deshalb pollt die Methode mit recaptchaTimeout, standardmäßig 300 Sekunden, statt mit dem defaultTimeout von 120 Sekunden. CapSkip hat außerdem eigene Limits. In seinen Friendly-Captcha-Einstellungen darf eine Aufgabe 250 Sekunden auf einen freien Thread warten und dann 120 Sekunden mit dem Lösen verbringen, bevor CapSkip sie als gescheitert abbricht. Ein langsamer Lösevorgang braucht also ein höheres Row Timeout, und das eigene Timeout des SDK, standardmäßig 300 Sekunden oder ein timeout= pro Aufruf, muss diesen Wert plus jede Wartezeit der Aufgabe auf einen Thread abdecken. Der Semaphor oben hält diese Wartezeit nahe bei null. Wenn das Lösen über einen langen Durchlauf hinweg langsamer wird, ist meist die steigende Schwierigkeit für eine Adresse die Ursache. Übergeben Sie einen Proxy pro Anfrage als dict mit den Schlüsseln type und uri, oder konfigurieren Sie in CapSkip einen Proxy-Pool, damit nicht jeder Lösevorgang von derselben Adresse kommt.

Die Beispiele verwenden 127.0.0.1, weil das richtig ist, wenn Ihr Skript und der Solver auf demselben Rechner laufen. Sobald das Skript irgendwo anders läuft, etwa auf einem VPS, in einem Container oder auf einem CI-Runner, zeigt Loopback auf den falschen Rechner, und der erste Aufruf löst eine NetworkException aus. Schalten Sie CapSkip in den Server-Modus, dann lauscht es auf Ihrer Netzwerkadresse oder öffentlichen IP, sodass jede dieser Umgebungen es über dieselbe API erreichen kann. Verwenden Sie eine statische öffentliche IP, wenn der Weg über das Internet führt, zusammen mit einer Firewall-Regel für die Adressen, die Sie erwarten. Es bleibt Ihre eigene Hardware, und es bleibt ohne Abrechnung pro Lösung. Der Client liest Umgebungsvariablen nicht von selbst, lesen Sie CAPSKIP_HOST also in Ihrem Code aus und übergeben Sie den Wert, wie es das vollständige Beispiel unten tut.

Vollständiges lauffähiges Beispiel

# pip install capskip requests
import os
from html.parser import HTMLParser
from urllib.parse import urljoin, urlparse

import requests
from capskip import CapSkip
from capskip.exceptions import CapSkipError, ValidationException

PAGE_URL = "https://example.com/signup"
V2_FILES = {"site.min.js", "site.compat.min.js"}
V1_FILES = {"widget.module.min.js", "widget.min.js", "widget.polyfilled.min.js"}


class FriendlyPage(HTMLParser):
    def __init__(self, page_url):
        super().__init__()
        self.page_url, self.widget, self.scripts = page_url, {}, []

    def handle_starttag(self, tag, attrs):
        a = dict(attrs)
        if "frc-captcha" in (a.get("class") or "").split():
            self.widget = a
        if tag == "script" and a.get("src") and "nomodule" not in a:
            self.scripts.append(urljoin(self.page_url, a["src"]))


def friendly_version(page):
    for src in page.scripts:
        if "@friendlycaptcha/sdk" in src:
            return "v2", src
        if "friendly-challenge" in src:
            return "v1", src
    for src in [s for s in page.scripts if "friendly" in s.lower()]:
        name = urlparse(src).path.rsplit("/", 1)[-1]
        if name in V2_FILES or name in V1_FILES:
            return ("v2" if name in V2_FILES else "v1"), src
    keys = page.widget.keys()
    if {"data-api-endpoint", "data-form-field-name"} & keys:
        return "v2", None
    if {"data-puzzle-endpoint", "data-solution-field-name"} & keys:
        return "v1", None
    raise SystemExit("v1 or v2? Read the page and set it by hand.")


solver = CapSkip(
    apiKey=os.getenv("CAPSKIP_API_KEY", "capskip"),
    host=os.getenv("CAPSKIP_HOST", "127.0.0.1"),
    port=int(os.getenv("CAPSKIP_PORT", "8080")),
)
session = requests.Session()

page = FriendlyPage(PAGE_URL)
page.feed(session.get(PAGE_URL, timeout=30).text)
if not page.widget.get("data-sitekey"):
    raise SystemExit("No frc-captcha widget in the HTML; it may be built by JS.")

version, script = friendly_version(page)
try:
    result = solver.friendly_captcha(
        page.widget["data-sitekey"], PAGE_URL,
        version=version, module_script=script,
        api_server=page.widget.get("data-api-endpoint")
        or page.widget.get("data-puzzle-endpoint"),
    )
except ValidationException as exc:
    raise SystemExit(f"not sent: {exc}")
except CapSkipError as exc:
    raise SystemExit(f"solve failed: {exc!r}")

field = (page.widget.get("data-form-field-name")
         or page.widget.get("data-solution-field-name")
         or ("frc-captcha-response" if version == "v2" else "frc-captcha-solution"))

# Post wherever the form's action points, with its other fields.
# Browsers send the page as Referer; some servers refuse a post without it.
resp = session.post(PAGE_URL, data={"email": "YOUR_EMAIL", field: result["token"]},
                    headers={"Referer": PAGE_URL}, timeout=30)
print(resp.status_code, version, field)

Die Version wird einmal bestimmt und zweimal verwendet, für das Lösen und für den Feldnamen, sodass beides nie auseinanderlaufen kann. Findet der Parser kein Widget, erzeugt die Seite es meist per JavaScript, und Sie brauchen den sitekey aus der gerenderten Seite oder aus dem Skript, das es erzeugt. Alle Parameter, die der rohe Endpunkt annimmt, finden Sie in der API-Referenz zu Friendly Captcha.

Häufige Fehler und was sie bedeuten

Was Sie sehenUrsacheBeheben
Die Website lehnt einen Token ab, den CapSkip ohne Fehler zurückgegeben hatDie falsche Version wurde gelöst, oft weil v1 stillschweigend als Standard griffBestimmen Sie die Version wie in Schritt 2 im Code und übergeben Sie sie
Abgelehnt auf einer Website, deren Widget data-api-endpoint (v2) oder data-puzzle-endpoint (v1) hatDer Token kam vom globalen Endpunkt, und die Website nutzt den EU-EndpunktÜbergeben Sie den Wert des Attributs als api_server
Der Token stimmt, aber das Absenden scheitert trotzdemEr ist im falschen Feld gelandet, das Absenden erfolgte ohne Referer, oder die Website sendet JSONPrüfen Sie die Attribute zum Umbenennen und senden Sie die Seiten-URL als Referer, dann bilden Sie die Anfrage mit den DevTools nach
Ein v2-Lösevorgang scheitert auf einer Website, die das Widget selbst hostetmodule_script war ein relativer Pfad, daher wurde das Widget nie geladenLösen Sie src vor dem Übergeben mit urljoin auf
ApiException mit ERROR_CAPTCHA_UNSOLVABLE innerhalb von Sekunden, jedes MalFriendly Captcha lehnt den sitekey oder den Origin der Seite ab, oder im Konto des Schlüssels ist weder v2 noch der EU-Endpunkt aktiviertPrüfen Sie sitekey, Seiten-URL und api_server; ein erneuter Versuch hilft nicht
ValidationException, bevor überhaupt etwas gesendet wirdEin leerer sitekey, eine Version außer v1, v2, 1 oder 2 oder eine unbekannte OptionPrüfen Sie, ob der Parser das Widget gefunden hat, und entfernen Sie die Option, die die Meldung nennt
Lösevorgänge werden im Lauf eines langen Durchlaufs langsamerFriendly Captcha erhöht die Arbeit für eine viel genutzte AdresseFügen Sie Proxys pro Anfrage oder einen Proxy-Pool in CapSkip hinzu
ApiException mit ERROR_CAPTCHA_UNSOLVABLE nach zwei Minuten oder mehrEin Lösevorgang lief länger als das Row Timeout von CapSkip mit 120 Sekunden oder wartete länger als das Wait Timeout von 250 Sekunden auf einen freien ThreadHalten Sie den Semaphor bei Max. Threads, fügen Sie Proxys hinzu oder erhöhen Sie Row Timeout in den Friendly-Captcha-Einstellungen
TimeoutException nach 300 SekundenEine Aufgabe wartete auf einen freien Thread, und der Lösevorgang lief danach länger, als das SDK polltHalten Sie den Semaphor bei Max. Threads oder übergeben Sie ein längeres timeout=
NetworkException beim ersten AufrufCapSkip läuft nicht, oder Host und Port sind falschStarten Sie CapSkip und prüfen Sie dann, ob der Local-Modus oder der Server-Modus passt

FAQ

Warum nicht nur module_script senden und CapSkip entscheiden lassen?

Das können Sie, und bei einem Skript, das von einem CDN geladen wird, funktioniert es auch, weil der Paketname in der Adresse steht. Das Risiko ist der Fallback. Nennt die Adresse keinen Build, den CapSkip erkennt, löst es v1, statt zu scheitern, und nichts im Ergebnis verrät Ihnen das. Eine Prüfung in Ihrem eigenen Code macht aus diesem stillen Standardwert eine Exception, die Sie sehen können.

Braucht das Lösen auf meiner Seite einen Browser, etwa Selenium oder Playwright?

Nein. Ihr Skript braucht nur das HTML, und das ruft requests ab. Jede Browserarbeit findet in CapSkip statt, das v2-Widgets in seinem eigenen Browser und v1-Rätsel direkt löst. Wenn Sie aus anderen Gründen ohnehin einen Browser steuern, funktioniert derselbe Aufruf; lesen Sie sitekey und Skriptadresse dann stattdessen aus der Live-Seite aus.

Kann ein Skript auf einem VPS oder in der Cloud einen Solver auf meinem Windows-PC nutzen?

Ja. Schalten Sie CapSkip in den Verbindungseinstellungen in den Server-Modus, damit es auf einer Netzwerkadresse statt auf Loopback lauscht, setzen Sie CAPSKIP_HOST dort, wo das Skript läuft, und übergeben Sie den Wert an den Client, wie es das vollständige Beispiel tut. Ein VPS, ein Container und ein gehosteter Runner verbinden sich alle über dieselbe HTTP-API. Verwenden Sie eine statische öffentliche IP mit einer Firewall-Regel, wenn der Weg über das Internet führt. Der Solver bleibt auf Hardware, die Ihnen gehört, mehr Lösevorgänge ändern also nie etwas an dem, was Sie zahlen.

Worin unterscheidet sich das vom C#-Leitfaden?

Der rohe Endpunkt, die Optionen und die Ergebnisfelder sind in jedem CapSkip SDK gleich; nur die Schreibweise ändert sich. Der eigentliche Unterschied liegt im Code drumherum: der Parser aus der Standardbibliothek, die requests-Session, die die Cookies der Website mitführt, und AsyncCapSkip, das in Python ein eigener asynchroner Client ist, während es in .NET nur ein anderer Name für CapSkipClient ist, der ohnehin schon asynchron ist. Die .NET-Version dieses Workflows zeigt der C#-Leitfaden zu Friendly Captcha, und wie Sie in Python mehrere Lösevorgänge gleichzeitig ausführen, erklärt der Leitfaden zum parallelen Lösen.

Die Kurzfassung

Um Friendly Captcha in Python zu lösen, durchsuchen Sie die Seite nach dem Element frc-captcha und seinen Script-Tags und machen aus jedem src eine vollständige Adresse. Bestimmen Sie v1 oder v2 anhand des Paketnamens oder der eigenen Attribute des Widgets, und werfen Sie eine Exception, wenn beides nichts verrät. Rufen Sie friendly_captcha mit dem sitekey, der Seiten-URL, dieser Version und der Skriptadresse auf, bei EU-Websites zusätzlich mit api_server. Senden Sie den Token einmal ab, im Body und in dem Feld, das Version und Widget vorgeben.

Noch ein Punkt zum Volumen. Friendly Captcha verlangt für seine Schwierigkeit CPU-Zeit und kein Geld, ein arbeitsreicher Tag kostet Sie also Lösezeit auf Ihrem eigenen Rechner. Wenn ein unbegrenzter Captcha-Löser lokal läuft, setzen nur dieser Rechner und die Threads, die Sie ihm geben, Grenzen, kein Abrechnungszähler.