Cara Memecahkan Capy Puzzle di C# dan Mengirim Ketiga Field-nya

solve capy puzzle in c# - How to Solve Capy Puzzle in C# and Submit All Three Fields

Untuk memecahkan Capy Puzzle di C#, baca key PUZZLE_ milik situs dari halaman, panggil CapyAsync dengan key tersebut dan URL halaman, lalu kirim tiga nilai yang dikembalikannya di field form capy_captchakey, capy_challengekey dan capy_answer, bersamaan dan secepatnya. Hanya itu seluruh integrasinya, dan bagian yang sering menjebak orang adalah bentuk jawabannya. Sebagian besar tipe yang mungkin pernah Anda pecahkan mengembalikan satu token. Capy mengembalikan tiga nilai yang hanya berfungsi sebagai satu set, dan salah satunya cepat kedaluwarsa. CapSkip menambahkan Capy Puzzle pada versi 1.4.0. Panduan ini membahas key-nya, pemanggilannya, jeda dua detik yang memang disengaja, dan pengirimannya.

Apa yang Anda butuhkan

  • CapSkip 1.4.0 atau lebih baru yang berjalan di komputer Windows. Dukungan Capy hadir pada rilis tersebut, bersama CaptchaFox dan Friendly Captcha.
  • Paket CapSkip .NET versi 1.3.0 atau lebih baru, yaitu rilis yang menambahkan CapyAsync. Paket ini menargetkan .NET Standard 2.0 dan bergantung pada System.Text.Json 8, sehingga didukung di .NET Framework 4.6.2 ke atas dan di .NET 6 ke atas. Contoh kodenya memakai top-level statements dan implicit usings dari proyek console .NET 6, jadi jalankan di .NET 6 atau lebih baru.
  • Dua nilai dari halaman target: key Capy, yang diawali PUZZLE_, dan URL halaman tempat widget berjalan. Langkah 1 menunjukkan letak key tersebut, dan tempat yang sama memberi tahu Anda apakah Anda memerlukan nilai ketiga yang opsional.
  • Sebuah alamat untuk pemecah CAPTCHA. Mode Local menjawab di 127.0.0.1 hanya untuk perangkat itu; mode Server mendengarkan di alamat jaringan atau IP publik Anda sehingga mesin lain dapat memanggilnya melalui API. Keduanya ada di pengaturan koneksi, dan salah satu bagian di bawah membahas kapan Anda perlu beralih.
# dotnet add package CapSkip
dotnet add package CapSkip

Langkah 1: temukan key PUZZLE_ dan host Capy

Semua yang Anda butuhkan untuk memecahkan Capy Puzzle di C# diambil dari halaman target. Key-nya bersifat publik dan sama untuk setiap pengunjung, serta berada di dua tempat. Parameter k pada URL script widget ada di HTML yang dikirim server, dan HTML itulah yang ditampilkan kode sumber halaman sekaligus diterima HttpClient. Setelah widget berjalan di browser, key itu juga ada di input tersembunyi capy_captchakey yang ditulis widget ke dalam form, dan di situlah panel Elements di DevTools menampilkannya.

<!-- In the HTML the server sends: the k parameter of the widget script -->
<script src="https://jp.api.capy.me/puzzle/get_js/?k=PUZZLE_YOUR_KEY"></script>

<!-- Written into the form by the widget once it has run (DevTools only) -->
<input type="hidden" name="capy_captchakey" value="PUZZLE_YOUR_KEY" />

Salin key persis apa adanya, termasuk awalannya. Selagi Anda melihat tag script itu, catat host-nya. Semua bagian URL script sebelum /puzzle/get_js/ adalah Capy API yang menaungi key tersebut, dan CapSkip menyebutnya api_server. Nilai default-nya https://jp.api.capy.me, tempat layanan aktifnya berjalan, jadi Anda hanya perlu memberikannya ketika sebuah halaman memuat widget dari tempat lain.

Satu jebakan di sini berasal dari dokumentasi pemecah CAPTCHA lain. Beberapa di antaranya masih menampilkan api.capy.me, tanpa awalan regional, dan host itu sudah tidak bisa di-resolve lagi. Jika Anda menyalinnya dari contoh lama, hapus opsi tersebut dan biarkan CapSkip memakai default-nya.

Langkah 2: pemanggilan CapyAsync

Metode ini menerima key, URL halaman, dan dictionary opsi yang bersifat opsional. Untuk halaman di host default, Anda tidak butuh apa pun selain dua yang pertama.

// dotnet add package CapSkip
using CapSkip;

var solver = new CapSkipClient(host: "127.0.0.1", port: 8080);

// The PUZZLE_ key, and the page the widget runs on.
var result = await solver.CapyAsync(
    "PUZZLE_YOUR_KEY",
    "https://example.com/login");

Console.WriteLine(result.CaptchaKey);    // capy_captchakey
Console.WriteLine(result.ChallengeKey);  // capy_challengekey
Console.WriteLine(result.Answer);        // capy_answer

Baca ketiga properti bernama itu. Properti Code berisi jawaban yang sama dalam bentuk JSON mentah, yang berguna untuk logging, dan RespKey kembali kosong karena hanya ada demi kompatibilitas dengan layanan lain. Answer adalah string panjang yang bagian awalnya kira-kira berbentuk 0xax8ex0xax84x. String ini adalah jalur seretan yang akan direkam widget saat potongan puzzle bergerak, bukan sebuah koordinat.

Dictionary opsi menerima api_server, proxy, proxytype dan useragent, plus timeout per panggilan dalam detik. User agent, jika Anda menyetelnya, dikirim pada satu-satunya permintaan yang dibuat CapSkip untuk mengambil puzzle, dan Anda akan jarang membutuhkannya. Ada juga opsi version, tetapi hanya puzzle yang diterima: keluarga Capy yang lain, avatar, adalah challenge berbeda di balik endpoint yang berbeda, jadi SDK menolaknya dengan ValidationException alih-alih mengembalikan jawaban yang akan ditolak situs. Nama opsi yang tidak dikenal, key PUZZLE_ yang kosong, URL halaman yang kosong, atau proxytype yang tidak didukung memicu exception yang sama sebelum apa pun dikirim. Opsi yang nilainya null langsung dibuang, sehingga Anda bisa memberikan host opsional tanpa pernyataan if.

// The script tag's host. jp.api.capy.me is the default, so pass
// this only when the page loads the widget from somewhere else.
var result = await solver.CapyAsync(
    "PUZZLE_YOUR_KEY",
    "https://example.com/login",
    new Dictionary<string, object?>
    {
        ["api_server"] = "https://jp.api.capy.me/",
    });

Mengapa pemecahan Capy memakan waktu sekitar dua detik

Deteksinya sendiri cepat. CapSkip mengambil gambar puzzle, menemukan lubangnya dengan sedikit perhitungan piksel, lalu menyusun jalur seretan, semuanya tanpa browser atau model. Setelah itu ia menunggu, dengan sengaja.

Capy mengukur waktu antara puzzle diambil dan jawaban diterima, dan menolak apa pun yang tiba lebih cepat daripada waktu yang dibutuhkan seseorang untuk menyeret potongannya. Pengukuran CapSkip sendiri terhadap Capy menempatkan batas bawahnya di sekitar satu detik: jawaban pada setengah detik ditolak, sedangkan jawaban dari satu hingga empat detik, durasi terpanjang yang diuji, diterima. Penolakan itu memakai pesan yang sama dengan jawaban yang salah, sehingga pemecahan yang benar tetapi dikirim terlalu cepat terlihat persis seperti pemecah yang rusak. Karena itu CapSkip menahan setiap hasil Capy sampai dua detik setelah ia mengambil puzzle. Penantian ini berupa sleep, jadi yang dikorbankan hanya latensi, bukan CPU, dan karena CapyAsync melakukan polling untuk Anda, yang Anda lihat hanyalah pemanggilan yang memakan waktu beberapa detik.

Mengapa beberapa detik dan bukan dua: polling SDK dimulai dengan jarak seperempat detik lalu melambat, menggandakan jaraknya hingga pollingInterval, yaitu 5 detik secara default. Dengan pengaturan default, jawabannya biasanya diambil di sekitar detik keempat. Jika sebagian besar yang dipecahkan sebuah klien adalah Capy, buat klien itu dengan pollingInterval: 0.5 dan pemanggilannya akan kembali jauh lebih dekat ke dua detik.

Ada dua konsekuensi praktis. Jangan menambahkan penundaan sendiri sebelum mengirim, karena jeda tersebut sudah mencakupnya. Dan jangan mencoba memangkas waktunya, karena jeda itulah yang membuat jawabannya lolos.

Langkah 3: kirim ketiga nilai dalam satu permintaan

Ketiga nilai itu masuk ke field yang akan ditulis sendiri oleh widget ke dalam form. Kirim ketiganya bersamaan, dalam permintaan yang sama dengan isi form lainnya.

// http is your HttpClient; result comes from Step 2.
var form = new FormUrlEncodedContent(new Dictionary<string, string>
{
    ["username"] = "someone",
    ["capy_captchakey"] = result.CaptchaKey!,
    ["capy_challengekey"] = result.ChallengeKey!,
    ["capy_answer"] = result.Answer!,
});

var response = await http.PostAsync("https://example.com/login", form);

Kirim jawaban persis seperti yang dikembalikan. Jawaban itu adalah jalur seretan, dan backend situs memeriksanya terhadap puzzle yang diambil, jadi memotongnya, menyusunnya ulang dari bagian-bagiannya, atau merapikannya dengan cara apa pun akan membuatnya tidak valid. Melakukan percent-encoding untuk body form tidak masalah, karena itu bagian dari transport dan server men-decode-nya lebih dulu.

Lalu kirim secepatnya. CapSkip membuat challenge key baru untuk setiap pemecahan dan puzzle terikat padanya, jadi key tersebut hanya sekali pakai dan berumur pendek. Satu pemecahan untuk satu pengiriman. Jika form ditinggalkan lalu dilanjutkan kemudian, pecahkan lagi alih-alih memakai nilai yang Anda simpan.

Tiru apa yang dikirim form aslinya. Sebagian besar halaman juga membawa field tersembunyi sendiri, seperti token anti-forgery, dan sebagian mengirim lewat script dengan body JSON, bukan form post. Banyak juga yang menolak permintaan tanpa header User-Agent, yang tidak dikirim HttpClient kecuali Anda menambahkannya. Kirim sekali secara manual dengan DevTools terbuka lalu salin permintaannya, kemudian taruh ketiga nilai Capy di tempat halaman itu menaruhnya.

Langkah 4: kegagalan, percobaan ulang, dan menjalankan banyak pemecahan sekaligus

Saat Anda memecahkan Capy Puzzle di C# dalam volume berapa pun, beberapa pemecahan akan gagal. Pemecahan Capy yang gagal datang sebagai ApiException, dan lewat SDK, kegagalan itu terbaca sebagai tidak bisa dipecahkan pada kedua kasus yang penting. Keduanya membutuhkan respons yang berlawanan, dan yang membedakannya adalah seberapa sering terjadi. Keduanya gagal lebih awal, sebelum jeda dua detik, karena CapSkip hanya menahan jawaban yang berhasil dipecahkan.

Apa yang terjadiGejalanyaApa yang harus dilakukan
Lubang tidak ditemukanSesekali, dan percobaan berikutnya biasanya berhasilCoba ulang. Setiap percobaan memunculkan puzzle baru di atas foto yang berbeda, jadi percobaan ulang benar-benar merupakan percobaan yang independen
Capy API menolak key tersebutSetiap percobaan, untuk satu key itu, dan daftar tugas Capy di CapSkip menampilkan Invalid captcha keyPeriksa key dan api_server. CapSkip tidak mencoba ulang key yang ditolak, karena key itu akan ditolak dengan cara yang sama persis

Pemecahan yang meleset jarang terjadi, jadi satu kali percobaan ulang sudah mencakup hampir semuanya. Anda bisa mencoba ulang di kode Anda sendiri, seperti pada contoh lengkap, atau menyetel Retries di bagian Capy pada pengaturan CapSkip, yang bernilai 0 secara default dan mengizinkan hingga tiga kali per tugas.

CapyAsync melakukan polling dengan defaultTimeout, 120 detik, karena pemecahan Capy hanyalah satu pengambilan dan sedikit aritmetika, bukan sesi browser. Itu mencakup pemecahan normal berkali-kali lipat. Naikkan nilainya di konstruktor jika Anda menaikkan Retries, atau jika Anda mengantrekan jauh lebih banyak pemecahan daripada yang dijalankan CapSkip sekaligus. Pengaturan Max. Threads di bagian Capy bernilai default 10, yang bisa Anda naikkan, dan tugas tambahan menunggu thread yang kosong.

Saat Anda menjalankan banyak pemecahan secara paralel, pasangkan setiap pemecahan dengan pengirimannya. Memulai seratus pemanggilan CapyAsync dengan Task.WhenAll lalu mengirim hasilnya belakangan membuat challenge key yang paling awal menua selagi pemecahan terakhir selesai. Bungkus pemecahan dan pengiriman bersama dalam satu task, dan batasi jumlah yang sedang berjalan dengan sebuah SemaphoreSlim yang ukurannya disesuaikan dengan jumlah thread. Dan pada volume besar, tambahkan proxy. Setiap pemecahan mengambil puzzle baru dari Capy API, dan aliran permintaan seperti itu dari satu alamat persis pola yang ingin ditangkap oleh rate limiting. Konfigurasikan pool proxy di CapSkip, atau berikan proxy per permintaan. Proxy hanya menyentuh pengambilan puzzle, yang merupakan satu-satunya permintaan yang dibuat oleh pemecahan Capy.

Menjalankan pemecah di tempat lain

Contoh kode memakai 127.0.0.1 karena itu benar selama kode Anda dan CapSkip berada di mesin yang sama. Begitu aplikasi .NET berjalan di tempat lain, seperti container, build agent, VPS atau app service, loopback menunjuk ke mesin yang salah dan pemecahan pertama melempar NetworkException. Alihkan CapSkip ke mode Server dan ia akan mendengarkan di alamat jaringan atau IP publik Anda, sehingga semua lingkungan itu dapat menjangkaunya melalui API. Gunakan IP publik statis jika rutenya melewati internet, aktifkan validasi API key, dan batasi port hanya untuk alamat yang Anda harapkan dengan aturan Windows Firewall. Mesinnya tetap mesin Windows milik Anda sendiri, dan pemecahannya tetap tanpa kuota.

Klien tidak membaca variabel lingkungan dengan sendirinya. Baca CAPSKIP_HOST dan CAPSKIP_API_KEY di kode Anda sendiri dan berikan ke konstruktor, seperti pada contoh lengkap, agar build yang sama bisa berjalan di komputer Anda maupun di server.

Contoh lengkap yang berfungsi

// dotnet add package CapSkip
using System.Text.RegularExpressions;
using CapSkip;

var pageUrl = "https://example.com/login";
var http = new HttpClient();
var solver = new CapSkipClient(
    apiKey: Environment.GetEnvironmentVariable("CAPSKIP_API_KEY") ?? "capskip",
    host: Environment.GetEnvironmentVariable("CAPSKIP_HOST") ?? "127.0.0.1",
    port: 8080,
    // Capy answers after a two second hold; poll often enough to catch it.
    pollingInterval: 0.5);

// The widget script's k parameter. The capy_captchakey input only
// exists once the widget has run in a browser.
var html = await http.GetStringAsync(pageUrl);
var key = Regex.Match(html, "PUZZLE_[A-Za-z0-9_-]+").Value;
if (key.Length == 0)
    throw new InvalidOperationException("No PUZZLE_ key in the HTML; check DevTools.");

// The script URL up to /puzzle/get_js/, when there is one; a null value is dropped.
var host = Regex.Match(html, @"(https://[^""'\s<>]+?)/puzzle/get_js/").Groups[1].Value;
var options = new Dictionary<string, object?>
{
    ["api_server"] = host.Length > 0 ? host : null,
};

try
{
    // A missed hole comes back unsolvable; a retry draws a new puzzle.
    SolveResult? result = null;
    for (var attempt = 1; result is null; attempt++)
    {
        try
        {
            result = await solver.CapyAsync(key, pageUrl, options);
        }
        catch (ApiException ex) when (attempt < 3 && ex.Message.Contains("UNSOLVABLE"))
        {
            Console.WriteLine($"attempt {attempt}: {ex.Message}");
        }
    }

    // All three together, straight away: the challenge key is single-use.
    var form = new FormUrlEncodedContent(new Dictionary<string, string>
    {
        ["username"] = "someone",
        ["capy_captchakey"] = result.CaptchaKey!,
        ["capy_challengekey"] = result.ChallengeKey!,
        ["capy_answer"] = result.Answer!,
    });

    // Post wherever the form's action attribute points.
    var response = await http.PostAsync(pageUrl, form);
    Console.WriteLine((int)response.StatusCode);
}
catch (CapSkip.ValidationException ex)
{
    // An empty key or URL, avatar as the version, or an unknown option.
    Console.WriteLine($"not sent: {ex.Message}");
}
catch (CapSkip.TimeoutException)
{
    Console.WriteLine("gave up waiting; defaultTimeout is 120 seconds");
}
catch (CapSkipError ex)
{
    // The third miss, a refused key, or CapSkip unreachable.
    Console.WriteLine($"gave up: {ex.Message}");
}

Regex key mencari awalan PUZZLE_ di mana pun dalam HTML, sehingga ia mengambil key dari URL script widget tanpa perlu mem-parsing tag-nya. Input capy_captchakey sama sekali tidak ada di HTML yang diunduh, karena widget baru menuliskannya ketika berjalan di browser. Regex host mengambil semua bagian URL script https sebelum /puzzle/get_js/, termasuk path-nya, dan ketika tidak menemukan apa pun, nilai null dibuang dan CapSkip memakai default-nya. Jika ketiga percobaan gagal, periksa key sebelum hal lain, karena key yang ditolak gagal dengan cara yang sama setiap kali, sedangkan pemecahan yang meleset hampir tidak pernah terjadi tiga kali berturut-turut. Ketika halaman membangun widget dari script yang di-bundle dan tidak ada regex yang cocok, buka tab Network dan salin kedua nilai dari permintaan milik widget itu sendiri. Endpoint mentah di balik metode ini didokumentasikan di referensi API, dan setiap tipe CAPTCHA lain yang dipecahkan paket ini ada di halaman pemecah CAPTCHA C#.

Kesalahan umum dan artinya

Apa yang Anda lihatPenyebabPerbaiki
Situs menolak pengiriman padahal CapSkip mengembalikan ketiga nilaiJawaban diubah, atau hanya satu atau dua nilai yang sampai ke formKirim result.Answer apa adanya, bersama dua nilai lainnya, dalam satu permintaan
Pengiriman yang berhasil sekali gagal pada percobaan keduaChallenge key hanya sekali pakai dan berumur pendekPecahkan ulang untuk setiap pengiriman, dan langsung kirim
ApiException pada setiap percobaan, untuk satu keyCapy API menolak key tersebut, atau api_server menunjuk ke host yang salahSalin ulang key, termasuk awalannya, dan periksa host pada tag script
ApiException sesekali yang menyatakan CAPTCHA tidak bisa dipecahkanCapSkip tidak dapat menemukan lubang pada puzzle ituCoba ulang; percobaan berikutnya memunculkan puzzle yang berbeda
Setiap pemecahan gagal setelah Anda menyalin contoh dari layanan lainContoh itu menyetel api_server ke api.capy.me, yang sudah tidak bisa di-resolveHapus opsi itu dan pakai host default
ValidationException sebelum apa pun terkirimKey atau URL halaman kosong, avatar sebagai version, atau opsi yang tidak diterima metode iniPastikan regex menemukan key-nya, dan buang opsi yang disebut dalam pesan
Kegagalan makin sering seiring berjalannya proses yang panjangSetiap puzzle diambil dari satu alamatSebarkan pemecahan ke pool proxy yang dikonfigurasi di CapSkip
TimeoutException di bawah beban paralel yang beratTugas yang mengantre lebih banyak daripada yang bisa diselesaikan Max. Threads dalam 120 detikBatasi konkurensi dengan SemaphoreSlim, atau naikkan defaultTimeout
NetworkException pada pemecahan pertamaCapSkip tidak berjalan, atau host dan port-nya salahJalankan CapSkip, lalu periksa apakah ia harus berada di mode Local atau mode Server
Build gagal karena TimeoutException yang ambiguCapSkip dan System sama-sama mendefinisikan nama pendek ituTulis CapSkip.TimeoutException secara lengkap, atau tangkap CapSkipError

FAQ

Mengapa pemecahan Capy mengembalikan tiga nilai, bukan satu token?

Karena itulah yang dikirim form Capy. Tidak ada token yang diterbitkan server pada titik mana pun. Widget itu sendiri membuat challenge key, mengambil puzzle yang menjadi pasangannya, dan merekam seretan, lalu situs mengirim challenge key dan jawaban ke Capy dengan private key miliknya untuk diperiksa. CapSkip memerankan widget, jadi ia mengembalikan apa yang akan ditulis widget ke dalam form.

Bisakah aplikasi .NET di platform hosting menjangkau pemecah CAPTCHA?

Bisa. Alihkan CapSkip ke mode Server di pengaturan koneksi agar ia mendengarkan di alamat jaringan, bukan di loopback, baca alamat itu dari CAPSKIP_HOST di kode Anda, lalu berikan ke klien. Container host, VPS, CI agent dan layanan aplikasi terkelola semuanya terhubung dengan cara yang sama, melalui API HTTP yang sama. Gunakan IP publik statis dengan aturan firewall jika rutenya melewati internet. Pemecah CAPTCHA tetap berada di perangkat milik Anda, jadi tidak ada yang berubah soal lisensi atau jumlah pemecahan.

Apa bedanya dengan memecahkan GeeTest v3 di C#?

Keduanya adalah puzzle geser yang mengembalikan beberapa nilai yang dikirim bersamaan, tetapi titik awalnya berbeda. GeeTest v3 dimulai dari challenge yang diterbitkan situs, yang harus Anda ambil tepat sebelum memecahkan karena challenge itu kedaluwarsa dalam sekitar satu menit. Capy dimulai hanya dari key, karena challenge key dibuat saat pemecahan, jadi tidak ada yang perlu diambil lebih dulu dan satu-satunya hitungan waktu yang penting berjalan setelah pemecahan. Sisi GeeTest dibahas di panduan GeeTest v3 untuk C#.

Apakah saya perlu mengirim user agent bersama pengiriman, seperti pada CaptchaFox?

Tidak. Token CaptchaFox terikat pada browser yang menerbitkannya, jadi pengiriman harus membawa user agent browser tersebut, dan panduan CaptchaFox untuk C# menjelaskan hal itu. Jawaban Capy sama sekali tidak terikat pada browser. CapSkip tidak mengembalikan user agent untuknya, dan user agent opsional yang bisa Anda berikan hanya mengubah permintaan yang mengambil puzzle.

Versi singkatnya

Untuk memecahkan Capy Puzzle di C#, salin key PUZZLE_ dari URL script widget atau input capy_captchakey, dan catat host script tersebut kalau-kalau bukan host default. Panggil CapyAsync dengan key dan URL halaman yang sebenarnya, lalu biarkan ia memakan beberapa detiknya. Kirim CaptchaKey, ChallengeKey dan Answer di capy_captchakey, capy_challengekey dan capy_answer, apa adanya, bersamaan dan seketika, lalu pecahkan lagi untuk setiap pengiriman. Coba ulang pemecahan yang sesekali meleset, tambahkan proxy seiring volume bertambah, dan beralihlah ke mode Server begitu kode pemanggil tidak lagi berada di mesin pemecah CAPTCHA.

Satu hal terakhir tentang percobaan ulang itu. Karena setiap percobaan memunculkan puzzle yang berbeda, mencoba lagi adalah solusi yang tepat untuk pemecahan yang meleset, dan dengan pemecah captcha lokal di mesin Anda sendiri, percobaan kedua hanya memakan beberapa detik, bukan satu pemecahan berbayar lagi.