So lösen Sie GeeTest v3 in C#

GeeTest durchbricht das mentale Modell, auf dem der meiste Captcha-Code aufgebaut ist. Es gibt keinen einzelnen Token, den man in ein Formularfeld einfügt. Eine Lösung gibt drei Werte, die zusammen zurückgesendet werden müssen, und die Challenge, von der Sie ausgegangen sind, läuft in etwa einer Minute ab. Machen Sie einen der beiden Teile falsch, scheitert die Anfrage ohne nützliche Fehlermeldung.
Hier ist der gesamte Ablauf in C#, einschließlich der Teile, bei denen man leicht Fehler macht.
Zwei Eingaben, und nur eine davon ist stabil
GeeTest v3 identifiziert eine Website mit gt und ein einzelner Versuch mit challenge. Sie verhalten sich völlig unterschiedlich.
| Wert | Lifetime | Woher es kommt |
|---|---|---|
gt | Statisch für die Website. Kann bedenkenlos hartkodiert oder gecacht werden | Die GeeTest-Init-Antwort der Website |
challenge | Einmalige Verwendung, läuft in etwa 60 Sekunden ab | Dieselbe init-Antwort, jedes Mal frisch |
Dieser Ablauf ist die mit Abstand häufigste Ursache für GeeTest-Fehler. Wenn Sie ein Paar abrufen, den Job in die Warteschlange stellen und ihn dreißig Sekunden später hinter anderer Arbeit lösen, ist die Challenge möglicherweise bereits tot. Rufen Sie sie unmittelbar vor dem Lösen ab, niemals aus einem Cache.
Einrichtung
# Targets .NET Standard 2.0, so Framework 4.6.1+ and .NET 6-9 all work. dotnet add package CapSkip
CapSkip läuft auf Ihrem eigenen Rechner, starten Sie daher zuerst die App und richten Sie den Client auf den Port aus den Einstellungen:
using CapSkip;
var solver = new CapSkipClient(
apiKey: "capskip", // any string when key validation is off
host: "127.0.0.1",
port: 8080,
recaptchaTimeout: 300); // seconds, and this one covers GeeTest tooBeachten Sie, dass GeeTest verwendet recaptchaTimeout, nicht defaultTimeout. Letzteres gilt nur für Bild-Captchas.
Es lösen
Drei Positionsargumente, in dieser Reihenfolge:
var result = await solver.GeetestAsync(
"81388ea1fc187e0c335c0a8907ff2625", // gt, static per site
"7cf6a8b1a2c34d5e6f7089abcdef0123", // challenge, fetched seconds ago
"https://example.com/login");
Console.WriteLine(result.Challenge);
Console.WriteLine(result.Validate);
Console.WriteLine(result.Seccode);Diese drei Eigenschaften sind die Antwort. result.Code wird ebenfalls befüllt, aber bei GeeTest enthält es die rohe JSON-Zeichenkette statt eines nutzbaren Tokens, sodass der Griff nach Code aus Gewohnheit ist ein Fehler. Bei SolveResult, Challenge, Validate und Seccode sind GeeTest-exklusiv und null für jeden anderen Typ.
Gut zu wissen: Der challenge das zurückkommt, ist nicht immer das, das Sie eingesendet haben. Verwenden Sie den zurückgegebenen Wert, nicht Ihre Eingabe.
Die Antwort zurücksenden
Senden Sie alle drei genau so, wie es das seiteneigene Frontend tun würde. Die meisten GeeTest-v3-Integrationen verwenden diese Feldnamen, auch wenn eine Website sie umbenennen kann, prüfen Sie also das echte Formular, bevor Sie etwas annehmen:
using System.Net.Http;
using System.Collections.Generic;
using var http = new HttpClient();
var form = new FormUrlEncodedContent(new[]
{
new KeyValuePair<string, string>("geetest_challenge", result.Challenge),
new KeyValuePair<string, string>("geetest_validate", result.Validate),
new KeyValuePair<string, string>("geetest_seccode", result.Seccode),
new KeyValuePair<string, string>("username", "..."),
new KeyValuePair<string, string>("password", "..."),
});
var response = await http.PostAsync("https://example.com/login", form);Zwei der drei zu senden oder einen frischen zu kombinieren validate mit einem veralteten challenge, wird auf dieselbe Weise abgelehnt wie eine falsche Antwort.
Der gesamte Ablauf, der Reihe nach
Das Abrufen des Paares und das Lösen müssen unmittelbar nebeneinander liegen. Diese Struktur hält sie dort:
using System;
using System.Net.Http;
using System.Text.Json;
using CapSkip;
// 1. Fetch a fresh gt/challenge pair from the site's own init endpoint.
using var http = new HttpClient();
var initJson = await http.GetStringAsync(
"https://example.com/geetest/init?t=" + DateTimeOffset.UtcNow.ToUnixTimeMilliseconds());
using var doc = JsonDocument.Parse(initJson);
var gt = doc.RootElement.GetProperty("gt").GetString();
var challenge = doc.RootElement.GetProperty("challenge").GetString();
// 2. Solve immediately. Do not queue this or await anything slow in between.
var result = await solver.GeetestAsync(gt, challenge, "https://example.com/login");
// 3. Post all three values together.
Console.WriteLine($"{result.Challenge} {result.Validate} {result.Seccode}");Der Cache-Busting-Zeitstempel beim init-Aufruf ist wichtiger, als es scheint. GeeTest-init-Endpunkte werden häufig von Zwischenstationen zwischengespeichert, und eine zwischengespeicherte Antwort liefert Ihnen eine Challenge, die bereits verbraucht wurde.
Wenn es fehlschlägt
using System;
using CapSkip;
try
{
var result = await solver.GeetestAsync(gt, challenge, pageUrl);
}
catch (CapSkip.ValidationException) { /* missing gt or challenge */ }
catch (NetworkException) { /* CapSkip is not running */ }
catch (ApiException) { /* API error, often a dead challenge */ }
catch (CapSkip.TimeoutException) { /* exceeded recaptchaTimeout */ }
catch (CapSkipError) { /* anything else from the SDK */ }Qualify ValidationException und TimeoutException mit dem CapSkip -Namespace. Beide Namen existieren auch in System, und wenn beide Namespaces importiert sind, bindet ein nicht qualifiziertes catch an das System -Typ und wird stillschweigend nie ausgelöst. Das Abfangen der Basis CapSkipError umgeht das Problem vollständig.
In der Praxis treten die meisten GeeTest-Fehler auf als ApiException und bedeuten, dass die Challenge gestorben ist, bevor die Lösung fertig war. Die Lösung besteht darin, später abzurufen, nicht mit denselben Werten erneut zu versuchen.
Proxys und Parallelität
GeeTest ist neben reCAPTCHA und Turnstile einer der drei Typen, die einen Proxy akzeptieren. Bild-Captchas tun das nicht, weil sie die Zielseite niemals berühren.
using System.Collections.Generic;
var result = await solver.GeetestAsync(gt, challenge, pageUrl,
new Dictionary<string, object?>
{
["proxy"] = new Proxy("HTTPS", "user:[email protected]:3128"),
});Mehrere parallel auszuführen funktioniert, aber jede benötigt ihr eigenes, frisch abgerufenes Paar. Rufen Sie nicht im Voraus einen Stapel Challenges ab, um sie dann gemeinsam zu lösen, denn die letzten sind abgelaufen, bevor sie an der Reihe sind.
// Correct: fetch and solve inside the same task.
var tasks = urls.Select(async url =>
{
var (gt, challenge) = await FetchPairAsync(url);
return await solver.GeetestAsync(gt, challenge, url);
});
var results = await Task.WhenAll(tasks);Häufig gestellte Fragen
Warum ist result.Code kein verwendbares Token?
Weil die Antwort von GeeTest drei Werte sind, nicht einer. Code behält die rohe JSON-Zeichenkette der Vollständigkeit halber, während das SDK die nützlichen Teile aufschlüsselt in Challenge, Validate und Seccode. Verwenden Sie diese drei.
Kann ich die Herausforderung zwischenspeichern, um eine Anfrage zu sparen?
Nein. Er ist zum einmaligen Gebrauch und läuft in etwa einer Minute ab. Ihn zu cachen ist der häufigste Grund, warum GeeTest-Integrationen im Test funktionieren und unter Last versagen, weil die Verzögerung durch die Warteschlange das Lösen über das Ablauffenster hinausschiebt. Der gt Wert kann bedenkenlos zwischengespeichert werden.
Funktioniert das für GeeTest v4?
The GeetestAsync -Methode zielt auf v3 ab, die Schiebe-Puzzle-Version, die rund um das gt und challenge Paar. v4 hat das Parametermodell geändert, prüfen Sie also das aktuelle API-Dokumentation für das, was unterstützt wird, bevor Sie annehmen, dass derselbe Aufruf funktioniert.
Benötige ich einen Proxy?
Nur wenn die Website geosensibel ist oder Ihre Adresse bereits als verdächtig einstuft. Lösen und übermitteln Sie über denselben Netzwerkpfad, wenn Sie einen verwenden, sonst kann die Diskrepanz selbst eine erneute Challenge auslösen.
Zusammenfassung
Abrufen gt und challenge unmittelbar vor dem Lösen; rufen Sie auf GeetestAsync mit beiden plus der Seiten-URL, dann senden Sie per POST Challenge, Validate und Seccode wieder zusammen. Behandeln Sie die Challenge als verderblich, verwenden Sie die zurückgegebene Challenge statt Ihrer Eingabe und fangen Sie CapSkipError um die Namespace-Kollision zu vermeiden.
Die Methodensignaturen für die anderen Sprachen finden Sie auf der GeeTest-Löser Seite, der vollständige .NET-Funktionsumfang befindet sich auf der C#-Captcha-Löser Seite, und Sie können ein Live-Rätsel ausprobieren auf unserer GeeTest-v3-Demo. CapSkip übernimmt Captcha-Umgehung lokal, sodass das Lösungsvolumen pro Anfrage nichts kostet.
