Solver captcha di C# dengan HttpClient: contoh .NET (2026)
Di C#, solver captcha adalah sebuah class kecil yang membungkus HttpClient. Anda mengirim sitekey dan URL halaman ke API Scarnox, membaca token dari respons JSON, lalu mengirimkannya ke form situs. Panduan ini membangun class tersebut untuk .NET 8, untuk PopularCaptcha, yang saat ini di-solve Scarnox secara proxyless.
Mulai dengan kredit uji coba gratis, tanpa kartu dan coba kodenya di halaman yang Anda kontrol sebelum menjalankannya di tempat lain.
Kebutuhan
- .NET 8 SDK (
dotnet --version). - API key Scarnox, dibaca dari environment variable.
- Sitekey dari widget PopularCaptcha di halaman tersebut. Untuk bantuan menemukannya, lihat cara mencari sitekey captcha.
Membuat project
dotnet new console -n CaptchaDemo
cd CaptchaDemo
Tidak perlu package tambahan. System.Net.Http dan System.Text.Json sudah termasuk dalam framework.
Class solver
Class di bawah ini memiliki satu HttpClient dengan header Bearer dan timeout 185 detik. Class ini mengembalikan token atau melempar exception dengan teks error dari API:
// ScarnoxSolver.cs
using System.Net.Http.Headers;
using System.Net.Http.Json;
using System.Text.Json.Serialization;
public sealed class ScarnoxSolver : IDisposable
{
private const string ApiUrl = "https://api.scarnox.com/api/tasks/create";
private readonly HttpClient _http;
public ScarnoxSolver(string apiKey)
{
_http = new HttpClient { Timeout = TimeSpan.FromSeconds(185) };
_http.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", apiKey);
}
public async Task<string> SolveAsync(
string sitekey,
string pageUrl,
bool invisible = false,
CancellationToken ct = default)
{
var body = new Dictionary<string, object>
{
["captcha_type"] = "PopularCaptchaTaskProxyless",
["site_key"] = sitekey,
["site_url"] = pageUrl,
};
if (invisible)
{
body["is_invisible"] = true;
}
// Panggilan ini kembali saat token sudah siap. Tidak ada polling.
using var resp = await _http.PostAsJsonAsync(ApiUrl, body, ct);
var data = await resp.Content.ReadFromJsonAsync<CreateTaskResponse>(cancellationToken: ct)
?? throw new InvalidOperationException(
$"HTTP {(int)resp.StatusCode}: empty response");
if (data.ErrorId != 0)
{
throw new InvalidOperationException($"{data.ErrorCode}: {data.ErrorDescription}");
}
return data.Solution?.Token
?? throw new InvalidOperationException("Response had no token");
}
public void Dispose() => _http.Dispose();
}
public sealed class CreateTaskResponse
{
[JsonPropertyName("errorId")]
public int ErrorId { get; set; }
[JsonPropertyName("errorCode")]
public string? ErrorCode { get; set; }
[JsonPropertyName("errorDescription")]
public string? ErrorDescription { get; set; }
[JsonPropertyName("solution")]
public Solution? Solution { get; set; }
}
public sealed class Solution
{
[JsonPropertyName("token")]
public string? Token { get; set; }
}
Baris pengecekan errorId adalah yang paling penting. API mengembalikan 0 saat berhasil. Nilai lain disertai errorCode dan errorDescription, dan class ini memunculkan keduanya.
Mengirim token
Token dikirim ke form situs. Gunakan HttpClient kedua dengan cookie container, agar sesi yang memuat form tetap dipakai saat POST:
// Program.cs
using System.Net;
var apiKey = Environment.GetEnvironmentVariable("SCARNOX_API_KEY")
?? throw new InvalidOperationException("Set SCARNOX_API_KEY");
const string pageUrl = "https://example.com/signup";
const string sitekey = "YOUR-SITEKEY-UUID";
using var solver = new ScarnoxSolver(apiKey);
string token = "";
// Coba ulang kegagalan sementara. Solve yang gagal tidak ditagih.
for (int attempt = 1; attempt <= 3; attempt++)
{
try
{
token = await solver.SolveAsync(sitekey, pageUrl);
break;
}
catch (InvalidOperationException ex) when (attempt < 3)
{
Console.Error.WriteLine($"Attempt {attempt} failed: {ex.Message}");
await Task.Delay(TimeSpan.FromSeconds(attempt));
}
}
var cookies = new CookieContainer();
var handler = new HttpClientHandler { CookieContainer = cookies, UseCookies = true };
using var site = new HttpClient(handler) { Timeout = TimeSpan.FromSeconds(60) };
// GET dulu agar situs men-set cookie sesinya.
await site.GetAsync(pageUrl);
using var form = new FormUrlEncodedContent(new Dictionary<string, string>
{
["email"] = "you@example.com",
["h-captcha-response"] = token,
["g-recaptcha-response"] = token,
});
using var response = await site.PostAsync(pageUrl, form);
Console.WriteLine($"Status: {(int)response.StatusCode}");
Jalankan:
set SCARNOX_API_KEY=scarnox_YOURAPIKEY
dotnet run
Di PowerShell, gunakan $env:SCARNOX_API_KEY = "scarnox_YOURAPIKEY" sebagai gantinya.
Mengapa strukturnya seperti ini
**Satu HttpClient per solver.** HttpClient memang dirancang untuk dipakai ulang, bukan dibuat untuk setiap panggilan. Solver memilikinya dan membuangnya di akhir.
Timeout 185 detik. API memblokir sampai token siap. Timeout yang lebih pendek akan membatalkan solve yang hampir selesai.
Deserialisasi bertipe. ReadFromJsonAsync memetakan JSON ke CreateTaskResponse, sehingga pengecekan error dan token terbaca seperti C# biasa.
Pengiriman form. Situs menerima h-captcha-response dan g-recaptcha-response sekaligus, karena situs membaca salah satunya. Cookie container menjaga sesi antara GET dan POST.
Waktu
Token kedaluwarsa dalam sekitar dua menit. Lakukan solve tepat sebelum Anda mengirim. Jika Anda melakukan solve lebih awal dalam sebuah batch lalu mengirim jauh setelahnya, token akan basi. Masa berlaku token captcha membahas detailnya.
Widget invisible
Berikan invisible: true ke SolveAsync saat widgetnya invisible. Request kemudian menyertakan is_invisible: true. Beberapa halaman memerlukan callback JavaScript yang tidak bisa dipicu oleh client sisi server. Dalam kasus itu, alat browser automation adalah pilihan yang lebih baik. Panduan captcha invisible membahas polanya.
Scraping secara bertanggung jawab
Jika program ini melakukan scraping pada halaman publik, cek robots.txt dan terms situs terlebih dahulu. Gunakan jeda di antara request, dan simpan hanya data pribadi yang Anda butuhkan. Untuk latar belakang hukumnya, lihat apakah web scraping legal.
Harga
Scarnox menagih per solve yang berhasil, dan solve yang gagal tidak dikenai biaya. Lihat harga terkini untuk tarifnya. Mulai dengan kredit uji coba gratis, tanpa kartu.