Cara Memecahkan CAPTCHA DataDome di C# dengan HttpClient

Untuk memecahkan CAPTCHA DataDome di C#, Anda membaca halaman blokir 403, membangun alamat challenge darinya, lalu mengirim alamat itu ke pemecah DataDome CapSkip dengan DataDomeAsync, dan mengulangi permintaan melalui HttpClient dengan cookie yang dikembalikan. Jawabannya adalah cookie, bukan token untuk formulir, dan dokumentasi CapSkip menyebut bahwa cookie itu hanya berfungsi dengan User-Agent dan alamat IP yang dipakai saat memperolehnya. Panduan ini menjalankan seluruh loop dalam satu proyek konsol dengan paket NuGet CapSkip dan tidak ada yang lain. CapSkip berjalan di PC Windows Anda sendiri tanpa biaya per pemecahan, jadi percobaan ulang tidak memakan biaya.
Apa yang Anda butuhkan
- CapSkip 3.2.0 atau lebih baru yang berjalan di PC Windows. Rilis itu menambahkan pemecahan DataDome untuk slider dan device check. Lihat panduan penyiapan untuk menjalankannya pertama kali.
- SDK .NET 8 atau lebih baru dan paket NuGet CapSkip versi 1.5.0 atau lebih baru. Versi sebelumnya tidak memiliki metode DataDomeAsync. Kode di bawah dijalankan pada .NET SDK 10.0.100, pada net10.0 dan net8.0 dengan CapSkip 1.5.0.
- Prompt PowerShell. Perintahnya memakai sintaks PowerShell.
- Halaman milik Anda atau yang boleh Anda otomatisasi, di balik DataDome.
- Sebuah alamat untuk pemecah CAPTCHA. Dalam mode Local, CapSkip menjawab di 127.0.0.1 hanya untuk perangkat itu. Dalam mode Server, CapSkip mendengarkan di alamat jaringan atau IP publik Anda, sehingga program di PC lain, VPS, atau platform hosting dapat menjangkaunya melalui API. Keduanya diatur di pengaturan koneksi.
- Sebuah proxy sticky (proxy yang mempertahankan alamat IP yang sama) untuk setiap task setelah Anda melewati tahap pengujian. Cookie terikat pada alamat IP yang memperolehnya, seperti dijelaskan di Langkah 3.
Cara pengujiannya: kode dijalankan terhadap tiga server mock (server pengganti yang dibuat khusus untuk pengujian) yang saya tulis, bukan terhadap situs DataDome sungguhan. Satu meniru pemeriksaan CapSkip yang tercantum di bagian DataDome pada Dokumentasi API, satu berperan sebagai situs terlindungi yang menyajikan halaman blokir 403 dan hanya menerima cookie yang diterbitkan CapSkip, dengan User-Agent yang dipakai saat cookie itu diterbitkan, dan satu lagi berperan sebagai forward proxy. SDK-nya adalah paket CapSkip 1.5.0 yang asli dari NuGet. Aplikasi CapSkip tidak berjalan di PC saya, jadi tidak ada hal di sini yang menunjukkan berapa lama pemecahan sungguhan berlangsung atau apa yang diterima situs DataDome yang aktif. Aturan tentang cookie berasal dari dokumentasi CapSkip. Sedangkan dokumentasi cookie milik DataDome sendiri menyatakan bahwa cookie datadome berlaku selama satu tahun dan memperingatkan agar Domain atau Path-nya tidak diubah. Dokumentasi itu tidak menyebut cookie tersebut terikat pada apa.
Langkah 1: buat proyek dan baca halaman blokir
Buat proyek konsol dan tambahkan paketnya. Template default mengaktifkan implicit using dan tipe nullable, dan kode ini bergantung pada keduanya.
dotnet new console -o datadome-demo cd datadome-demo dotnet add package CapSkip
Ketika DataDome meragukan sebuah permintaan, situs menjawab dengan status 403, kadang 401, dan halaman HTML kecil sebagai ganti konten. Halaman itu berisi objek skrip bernama dd dan memuat challenge dalam iframe dari geo.captcha-delivery.com. Alamat iframe itulah yang dibutuhkan CapSkip, dan dokumentasi menyebutnya captcha_url. Jika halaman sudah berisi iframe, Anda bisa mengambil src-nya apa adanya. Sebagian besar halaman blokir membangun iframe dengan skrip, jadi blok pertama merakit alamat yang sama dari objek dd. Permintaan pertama dikirim dengan User-Agent Chrome biasa. String itu tidak pernah dikirim ke CapSkip, jadi versi Chrome-nya tidak harus cocok dengan apa pun, dan saya tidak menguji apakah situs DataDome yang aktif memberikan challenge yang sama kepada User-Agent yang berbeda. Ganti isi Program.cs dengan keempat blok panduan ini, satu demi satu, mulai dari blok ini.
Nilai rt menentukan jalurnya. Nilai c berarti slider di bawah /captcha/, dan i berarti device check di bawah /interstitial/. Nilai t juga penting: fe adalah challenge, dan bv berarti DataDome telah memblokir alamat IP yang mengambil halaman itu.
using System.Net;
using System.Text.Json;
using System.Text.RegularExpressions;
using CapSkip;
static class BlockPage
{
// Build the challenge address from a DataDome block page, or return null.
public static string? CaptchaUrl(HttpStatusCode status, string html, string pageUrl)
{
if (status != HttpStatusCode.Forbidden && status != HttpStatusCode.Unauthorized) return null;
var found = Regex.Match(html, @"var\s+dd\s*=\s*(\{[^}]*\})");
if (!found.Success) return null;
using var doc = JsonDocument.Parse(found.Groups[1].Value.Replace('\'', '"'));
var dd = doc.RootElement;
string? Get(string name) => dd.TryGetProperty(name, out var v)
? (v.ValueKind == JsonValueKind.String ? v.GetString() : v.GetRawText())
: null;
var query = new List<(string Key, string? Value)>
{
("initialCid", Get("cid")), ("hash", Get("hsh")), ("cid", Get("cookie")),
};
if (!string.IsNullOrEmpty(Get("t"))) query.Add(("t", Get("t"))); // fe challenge, bv banned
query.Add(("referer", pageUrl));
query.Add(("s", Get("s")));
foreach (var key in new[] { "e", "b" })
if (!string.IsNullOrEmpty(Get(key))) query.Add((key, Get(key)));
query.Add(("dm", "cd"));
var path = Get("rt") == "i" ? "interstitial" : "captcha";
var qs = string.Join("&", query.Select(p => p.Key + "=" + Uri.EscapeDataString(p.Value ?? "")));
return $"https://{Get("host") ?? "geo.captcha-delivery.com"}/{path}/?{qs}";
}
}Metode ini mengembalikan null untuk respons apa pun yang bukan halaman blokir, sehingga pemanggil dapat membedakan “tidak ada yang perlu dipecahkan” dari “sudah dipecahkan”. Setiap halaman blokir adalah challenge baru. Pakai alamatnya segera, dan minta halaman lagi untuk task berikutnya alih-alih memakai ulang alamat lama.
Langkah 2: pecahkan dengan DataDomeAsync
Metode SDK-nya adalah DataDomeAsync(captchaUrl, url, options), yang mengikuti urutan argumen 2Captcha. Kedua alamat bersifat posisional, sedangkan userAgent dan proxy masuk ke dictionary options. Keduanya opsional di CapSkip. Jika Anda tidak mengirim User-Agent, CapSkip memakai milik browsernya sendiri dan mengembalikannya sebagai UserAgent di hasil. Jika Anda mengirimnya, harus Chrome untuk Windows dengan versi mayor yang sama dengan browser CapSkip, jadi tidak mengirimnya adalah pilihan yang mudah. Metode ini menunggu dengan timeout 300 detik yang lebih panjang, yang juga dipakai reCAPTCHA, karena CapSkip melewati challenge di browser sungguhan. Dokumentasi API menyebut pemecahan biasanya memakan 3 sampai 20 detik, dan saya tidak mengukurnya.
Proxy adalah proxy yang akan dipakai permintaan Anda berikutnya. Berikan jika program Anda keluar melalui proxy, dan jangan berikan apa pun jika permintaan keluar dari mesin yang menjalankan CapSkip. Jika CapSkip berada di server, mesin itu adalah server tersebut. Kelas Proxy menerima tipe dan alamat, seperti HTTP dan user:[email protected]:8080.
static class Solve
{
// Local mode. In Server mode, use your server's address instead.
static readonly CapSkipClient Solver = new(host: "127.0.0.1", port: 8080);
public static Task<SolveResult> Run(string captchaUrl, string pageUrl, string? proxyUrl)
{
var options = new Dictionary<string, object?>();
if (proxyUrl != null)
{
var i = proxyUrl.IndexOf("://", StringComparison.Ordinal);
options["proxy"] = new Proxy(proxyUrl[..i].ToUpperInvariant(), proxyUrl[(i + 3)..]);
}
// No userAgent option: CapSkip uses its own browser's and reports it.
return Solver.DataDomeAsync(captchaUrl, pageUrl, options);
}
}Jika device check tidak bisa dipenuhi, DataDome beralih ke slider. Menurut dokumentasi CapSkip, satu panggilan yang sama mengikutinya ke sana, jadi Anda tidak memerlukan kode terpisah untuk kedua challenge itu.
Langkah 3: kirim cookie dengan User-Agent dan alamat IP-nya
Hasilnya adalah SolveResult dengan empat properti yang penting. Properti Code pada hasil adalah cookie persis seperti yang diatur DataDome, lengkap dengan Max-Age, Domain, dan atribut lainnya, yang dibutuhkan cookie jar. Properti Cookie hanya berisi pasangan nama dan nilai datadome, yang dibutuhkan header Cookie. UserAgent adalah User-Agent yang memperolehnya. Properti Proxy hanya terisi jika Anda tidak mengirim proxy dan CapSkip memecahkan melalui daftar proxy DataDome bawaannya sendiri. Dokumentasi CapSkip menyebut DataDome menolak cookie dari alamat IP lain atau dengan User-Agent lain, jadi kirim User-Agent yang sama setiap kali, dan ketika hasilnya menyebut sebuah proxy, kirim permintaan melalui proxy itu. Properti Proxy tersebut hanya berisi host dan port, tanpa skema dan tanpa login. Program menambahkan http:// sehingga mengasumsikan proxy daftar yang tidak memerlukan login. Jika proxy Anda memerlukannya, tambahkan sendiri.
Helper di bawah mengatur header Cookie secara manual dan mematikan UseCookies, sehingga HttpClient mengirimnya apa adanya. Helper ini juga membaca cookie pengganti dari respons, karena DataDome bisa mengirimnya pada respons berikutnya dan sebuah browser akan menyimpannya. Helper membuat satu HttpClient per panggilan agar tetap singkat. Untuk banyak permintaan, simpan satu klien per proxy.
static class Web
{
static HttpClient Client(string? proxyUrl)
{
// UseCookies is off, so the Cookie header set by hand goes out as it is.
var handler = new HttpClientHandler { UseCookies = false };
if (proxyUrl != null)
{
var uri = new Uri(proxyUrl);
var proxy = new WebProxy($"{uri.Scheme}://{uri.Host}:{uri.Port}");
if (uri.UserInfo.Length > 0)
{
var login = uri.UserInfo.Split(':', 2);
proxy.Credentials = new NetworkCredential(
Uri.UnescapeDataString(login[0]),
login.Length > 1 ? Uri.UnescapeDataString(login[1]) : "");
}
handler.Proxy = proxy;
}
return new HttpClient(handler) { Timeout = TimeSpan.FromSeconds(30) };
}
// Returns the status, the body and a replacement datadome cookie if the site sent one.
public static async Task<(HttpStatusCode Status, string Body, string? Fresh)> Get(
string url, string userAgent, string? cookie, string? proxyUrl)
{
using var http = Client(proxyUrl);
using var request = new HttpRequestMessage(HttpMethod.Get, url);
request.Headers.TryAddWithoutValidation("User-Agent", userAgent);
if (cookie != null) request.Headers.TryAddWithoutValidation("Cookie", cookie);
using var response = await http.SendAsync(request);
string? fresh = null;
if (response.Headers.TryGetValues("Set-Cookie", out var lines))
fresh = lines.Select(l => Regex.Match(l, "^datadome=[^;]+"))
.FirstOrDefault(m => m.Success)?.Value;
return (response.StatusCode, await response.Content.ReadAsStringAsync(), fresh);
}
}Langkah 4: contoh lengkap yang berfungsi
Blok terakhir menyatukan alur CAPTCHA DataDome di C# dan menambahkan percobaan ulang. Jalankan dengan dotnet run. Setiap percobaan meminta halaman lagi, jadi tiap percobaan membawa challenge baru. Pemecahan yang gagal melempar ApiException dan loop mencoba lagi. Cookie yang tetap mendapat 403 juga membuat loop berputar lagi, dengan halaman blokir yang baru.
static class Program
{
const string PageUrl = "https://www.example.com/"; // a page behind DataDome
const string Browser = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 " +
"(KHTML, like Gecko) Chrome/156.0.0.0 Safari/537.36";
// The proxy your requests use, e.g. "http://user:[email protected]:8080". Null means
// they leave from the PC that runs CapSkip.
static readonly string? ProxyUrl = null;
static async Task<int> Main()
{
for (var attempt = 1; attempt <= 3; attempt++)
{
var (status, body, _) = await Web.Get(PageUrl, Browser, null, ProxyUrl); // fresh block page
var captchaUrl = BlockPage.CaptchaUrl(status, body, PageUrl);
if (captchaUrl is null)
{
Console.WriteLine($"{(int)status}: no DataDome block page on this response");
return 0;
}
SolveResult result;
try { result = await Solve.Run(captchaUrl, PageUrl, ProxyUrl); }
catch (ApiException ex)
{
Console.WriteLine($"attempt {attempt}: {ex.Message}"); // the next try gets a new page
continue;
}
// The cookie works only from the address and User-Agent that earned it.
var via = ProxyUrl ?? (result.Proxy is null ? null : "http://" + result.Proxy);
var cookie = result.Cookie;
var (code, page, fresh) = await Web.Get(PageUrl, result.UserAgent!, cookie, via);
if (code != HttpStatusCode.OK)
{
Console.WriteLine($"attempt {attempt}: HTTP {(int)code} with the cookie");
continue;
}
cookie = fresh ?? cookie; // DataDome may rotate the cookie; keep the newest
Console.WriteLine($"{(int)code} {page[..Math.Min(40, page.Length)]}");
var (again, _, _) = await Web.Get(PageUrl, result.UserAgent!, cookie, via); // reuse it
Console.WriteLine((int)again);
return 0;
}
Console.WriteLine("DataDome not passed in 3 attempts");
return 1;
}
}SDK menolak captchaUrl dengan t=bv sebelum mengirim apa pun, karena tidak ada pemecahan dari alamat itu yang bisa lolos. ValidationException itu bukan ApiException, jadi loop tidak menangkapnya. Biarkan muncul: itu adalah sinyal untuk mengganti alamat dan mulai dari awal. Pemblokiran yang justru dilaporkan CapSkip, sebagai ERROR_PROXY_BANNED, tiba sebagai ApiException dan loop mencobanya lagi pada alamat yang sama, jadi jika Anda melihat error itu di output, ganti proxy sebelum menjalankan lagi. Lihat panduan rotasi proxy untuk cara merotasinya, dan detektor CAPTCHA C# untuk mengetahui CAPTCHA apa yang dipakai sebuah halaman sebelum Anda memilih metode.
Pada eksekusi mock, program berperilaku seperti ini:
| Pengaturan mock | Yang dilakukan program |
|---|---|
| Halaman blokir slider, setiap pemecahan dijawab | Satu task, lalu status 200 dengan cookie, dan 200 lagi saat dipakai ulang |
| Halaman blokir device check | Kode yang sama berjalan: captchaUrl menunjuk ke /interstitial/ dan hasilnya sama |
| Dua pemecahan pertama ditolak | Dua baris percobaan, lalu status 200 pada task ketiga |
| Tiga pemecahan pertama ditolak | Tiga baris percobaan, lalu pesan bahwa DataDome tidak berhasil dilewati, dan exit code 1 |
| Hasil menyebut sebuah proxy, seperti daftar milik CapSkip sendiri | Permintaan dengan cookie melewati proxy itu dan mendapat 200 |
| Proxy Anda sendiri diatur di ProxyUrl | in.php menerima proxy beserta tipenya, dan permintaan memakainya |
| Halaman blokir dengan t=bv | ValidationException yang tidak ditangani, dan mock CapSkip tidak melihat permintaan sama sekali |
Satu hal yang ditunjukkan eksekusi dengan proxy: teks setelah skema dikirim ke CapSkip persis seperti yang Anda tulis. Login yang ditulis dengan percent-encoding di ProxyUrl, seperti pa%24s untuk kata sandi dengan tanda dolar, tiba di in.php dalam keadaan masih ter-encode. Jaga agar login bebas dari karakter yang perlu di-encode, atau bangun argumen Proxy sendiri dari nilai yang sudah didekode.
Kesalahan umum
| Kesalahan | Penyebab | Perbaiki |
|---|---|---|
| ValidationException | captchaUrl yang bukan alamat challenge DataDome, halaman blokir dengan t=bv, url yang bukan http atau https, atau userAgent yang bukan Chrome untuk Windows. Pesannya menyebut mana dari semua itu yang terjadi | Bangun ulang alamat dari halaman blokir yang baru, ganti alamat IP jika diblokir, dan hapus opsi userAgent |
| ApiException dengan ERROR_WRONG_USERAGENT | User-Agent adalah Chrome untuk Windows, tetapi versi mayornya berbeda dari browser CapSkip | Jangan kirim userAgent dan pakai yang dilaporkan hasilnya |
| ApiException dengan ERROR_CAPTCHA_UNSOLVABLE | Challenge tidak berhasil dilewati | Minta halaman lagi dan kirim captchaUrl barunya |
| ApiException dengan ERROR_PROXY_BANNED | CapSkip menolak task yang halaman blokirnya berisi t=bv, menurut dokumentasi API | Ganti proxy dan minta halaman lagi |
| ApiException dengan ERROR_PROXY_CONNECT_REFUSED | CapSkip melaporkannya ketika tidak bisa terhubung melalui proxy. Saya tidak mereproduksinya | Periksa alamat, login, dan tipe proxy |
| CapSkip.TimeoutException | CapSkip tidak memberi jawaban dalam waktu tunggu 300 detik. Ini bukan ApiException, jadi loop tidak menangkapnya. Tulis nama lengkapnya, karena System juga memiliki TimeoutException | Pastikan CapSkip berjalan dan memecahkan, lalu jalankan program lagi |
| NetworkException | CapSkip tidak berjalan, atau host atau port-nya salah | Jalankan CapSkip dan periksa pengaturan koneksi |
| Tetap 403 dengan cookie | Permintaan keluar dari alamat IP lain, memakai User-Agent lain, atau cookie sudah kedaluwarsa | Kirim UserAgent dan Proxy dari hasilnya setiap kali, atau jalankan loop lagi dengan halaman blokir yang baru |
Menjalankan solver di sebuah server
Program memerlukan dua hal dari CapSkip: host dan port. Dalam mode Local itu adalah 127.0.0.1 dan PC Anda sendiri. Dalam mode Server, CapSkip mendengarkan di alamat jaringan atau IP publik Anda, sehingga program di PC lain, VPS, atau platform hosting dapat memanggilnya melalui API yang sama. Ubah host dan port di konstruktor CapSkipClient, dan tidak ada hal lain yang berubah. IP publik statis disarankan untuk akses jarak jauh yang stabil. Mode Server tetap berjalan di hardware Anda sendiri dan tetap tanpa meteran. Mode Server memang membuka port untuk semua alamat, jadi tambahkan aturan blokir Windows Firewall untuk alamat yang tidak boleh menjangkaunya. Ingat bahwa pemecahan berjalan di mesin itu, jadi cookie diperoleh dari alamat IP server tersebut. Kecuali Anda memberikan proxy, permintaan yang membawa cookie juga harus keluar dari server itu. Dengan proxy, berikan proxy yang sama untuk pemecahan dan untuk permintaan Anda. Lihat pengaturan koneksi untuk cara beralih mode.
FAQ
Apakah DataDomeAsync mengembalikan token?
Tidak. Pemecah ini mengembalikan cookie datadome. Anda mengirim cookie itu di header Cookie pada permintaan yang diblokir, bersama User-Agent yang sama. Tidak ada field formulir yang perlu diisi.
Apakah saya memerlukan proxy untuk DataDome?
Tidak untuk pengujian. Satu alamat IP sudah cukup untuk percobaan pertama. Menurut dokumentasi CapSkip, cookie hanya berfungsi dari alamat IP yang memperolehnya, jadi begitu Anda mengirim banyak permintaan, rencanakan satu proxy sticky per task dan berikan proxy yang sama itu untuk pemecahan dan untuk permintaan Anda.
Bisakah platform hosting menjalankan ini terhadap CapSkip saya?
Bisa, lewat mode Server. Atur CapSkip untuk mendengarkan di jaringan atau IP publik Anda, arahkan konstruktor CapSkipClient ke host dan port itu, dan loop bekerja sama, dengan satu perubahan: pemecahan kini berjalan di server, jadi berikan proxy yang sama untuk pemecahan dan untuk permintaan Anda. Pemecah tetap berjalan di hardware Anda.
Versi singkatnya
Sebuah CAPTCHA DataDome di C# memerlukan empat langkah: baca halaman blokir, bangun captchaUrl, panggil DataDomeAsync, dan ulangi permintaan dengan cookie, User-Agent, dan alamat IP yang terikat padanya. Mencoba ulang itu gratis di mesin Anda sendiri, dan itulah yang Anda harapkan dari pemecah captcha saat situs yang dilindungi terus memberi Anda challenge baru. Untuk bagian SDK lainnya, lihat Halaman pemecah CAPTCHA C#.
