Cara Memecahkan hCaptcha Enterprise di Node.js (SDK capskip)

Untuk memecahkan hCaptcha Enterprise di Node.js, ambil rqdata baru dari situs dan berikan ke metode hcaptcha() dari paket capskip sebagai opsi data, bersama sitekey dan URL halaman. Metode ini mengirim task ke CapSkip, melakukan polling sampai token siap, dan mengembalikannya. Setelah itu kirim token ke formulir dengan User-Agent yang ada di hasil. Dokumentasi CapSkip menyebut situs menerbitkan setiap rqdata untuk satu challenge dan rqdata cepat kedaluwarsa, jadi setiap task, dan setiap percobaan ulang, memerlukan yang baru. Kode di bawah berkomunikasi dengan pemecah hCaptcha CapSkip di PC Windows Anda sendiri, tanpa biaya per pemecahan.
Apa yang Anda butuhkan
- CapSkip versi 4.0.0 atau lebih tinggi, terinstal di mesin Windows Anda. Rilis itu menambahkan pemecahan hCaptcha, termasuk Enterprise, dalam format in.php yang dipakai di sini dan dalam format JSON createTask.
- Node.js 18 atau lebih baru dan paket capskip, versi 1.6.0 atau lebih baru, yang pertama memiliki metode hcaptcha. Paket ini menyatakan Node.js 18 sebagai batas minimumnya dan tidak punya dependensi sendiri, dan POST formulir memakai fetch bawaan. Saya hanya menjalankan kode di 20.11.1, 24.22.0, dan 25.2.1.
- Situs milik Anda atau yang boleh Anda otomatisasi yang menampilkan widget hCaptcha, beserta sitekey widget itu.
- Sebuah jalur dari skrip ke CapSkip. Mode Local menjaga CapSkip di 127.0.0.1, hanya dapat dijangkau dari satu perangkat itu. Mode Server juga membuatnya mendengarkan di jaringan atau IP publik Anda, sehingga skrip di Windows VPS, PC lain, atau platform hosting juga dapat memakainya, dan itu mengharuskan CapSkip berjalan sebagai administrator. Pilih di pengaturan koneksi.
Posisi saat ini: saya menjalankan kode dengan capskip 1.6.0 terhadap dua server mock buatan saya sendiri, satu berperan sebagai CapSkip dan satu sebagai situs Enterprise yang menerima setiap rqdata sekali saja. Aturan itu buatan saya, diambil dari dokumentasi CapSkip dan source paket. Tidak ada halaman dokumentasi publik hCaptcha yang saya baca yang menjelaskan rqdata, jadi setiap fakta tentang rqdata di sini berasal dari dokumentasi CapSkip. Tidak ada pemecahan sungguhan yang terjadi, jadi saya tidak bisa menyebut berapa lama satu pemecahan berlangsung atau bagaimana situs Enterprise sungguhan berperilaku.
Langkah 1: temukan sitekey, flag invisible, dan rqdata
Di folder kosong, jalankan npm install capskip. Lalu salin blok Langkah 1 sampai 4 ke satu file bernama hcaptcha-demo.js di folder itu, sesuai urutan yang ditampilkan. Tidak ada yang berjalan sampai Langkah 4, kecuali Anda menambahkan baris uji di akhir Langkah 2. Opsi recaptchaTimeout adalah batas polling SDK dalam detik untuk hCaptcha. Defaultnya 300, dan saya sendiri memilih 120 yang lebih pendek.
// npm install capskip
const { CapSkip, ApiException } = require("capskip");
const CAPSKIP = { host: "127.0.0.1", port: 8080 }; // Local mode; Server mode: your server
const SITE = "https://www.example.com"; // a site you may automate
const PAGE_URL = `${SITE}/login`; // the page the hCaptcha widget is on
// The SDK's default key. Use your own if API Key Validation is on in CapSkip.
const API_KEY = "capskip";
const PROXY = null; // for example "203.0.113.10:8080"; null means no proxy
const solver = new CapSkip({
...CAPSKIP,
apiKey: API_KEY,
recaptchaTimeout: 120, // poll limit in seconds for hCaptcha; the default is 300
});Sitekey biasanya berada pada container widget sebagai data-sitekey. Ketika skrip membangun widget, cari opsi sitekey dari hcaptcha.render(), atau parameter sitekey= pada alamat iframe hCaptcha. Selain itu, panduan widget invisible hCaptcha menandai widget invisible dengan data-size yang diatur ke invisible, dan dokumentasi CapSkip meminta Anda mengirim invisible=1 untuk widget semacam itu.
Nilai rqdata adalah yang paling tidak biasa. Dokumentasi CapSkip menyebut beberapa situs Enterprise meneruskan nilai rqdata ke widget lewat hcaptcha.setData() sebelum widget berjalan, dan jika halaman melakukan ini, Anda mengirim nilai itu sebagai data. Jika tidak, jangan kirim field data. Dari mana nilai itu berasal adalah pilihan situs. Nilai itu bisa berada di HTML halaman atau datang dari permintaan yang dibuat halaman, jadi cari panggilan yang mengaturnya di skrip halaman dan telusuri string-nya. Saya tidak mencobanya pada situs Enterprise sungguhan, dan fungsi di bawah memakai jalur yang disediakan mock saya.
// Ask the site for a new challenge. The route and the field names are the
// site's choice; these are the ones in my test mock, so adapt them.
// If the sitekey is fixed in the page, return it as a constant here.
// If the site puts the values in the page HTML, fetch PAGE_URL and
// extract them here instead.
async function getChallenge() {
const resp = await fetch(`${SITE}/api/challenge`);
if (!resp.ok) throw new Error(`challenge failed: HTTP ${resp.status}`);
const { sitekey, rqdata, invisible } = await resp.json();
return { sitekey, rqdata, invisible: Boolean(invisible) };
}Langkah 2: kirim task dan ambil token
Satu panggilan mengirim task dan melakukan polling untuk hasilnya. Metode hcaptcha() menerima sitekey, URL halaman, dan objek opsi: data adalah rqdata, invisible bernilai true untuk widget invisible, dan proxy adalah proxy untuk pemecahan. SDK mengirimnya ke /in.php sebagai field formulir dengan method=hcaptcha, dan mengirim invisible sebagai 1. SDK tidak mengirim opsi userAgent: dokumentasi menyebut CapSkip memakai opsi itu hanya jika cocok dengan browser yang dipakainya untuk memecahkan, dan hasilnya membawa User-Agent yang dipakai saat token diperoleh.
async function solve({ sitekey, rqdata, invisible }) {
const options = {};
// The Enterprise rqdata, fresh for this task. Skip it if the site has none.
if (rqdata) options.data = rqdata;
if (invisible) options.invisible = true; // data-size is invisible
if (PROXY) options.proxy = PROXY;
// Submits the task, polls until the token is ready, and returns the result.
return solver.hcaptcha(sitekey, PAGE_URL, options);
}SDK melakukan polling /res.php untuk Anda. Polling pertama dikirim seketika, dan jeda sesudahnya dimulai dari seperempat detik, berlipat ganda setiap kali, dan berhenti bertambah pada 5 detik. Body kosong dianggap belum siap: dokumentasi menyebut artinya hasil sudah dibaca atau ID tidak ada, dan source SDK menambahkan bahwa CapSkip mengirim satu tepat setelah submit. Ketika batas terlewati, panggilan melempar TimeoutException.
Hasil diberikan sekali saja, dan SDK menyimpan semuanya untuk Anda. Field code dan token berisi string yang sama. respKey adalah nilai kedua yang diberikan hCaptcha kepada widget bersama token. Menurut dokumentasi, sebagian besar situs tidak pernah membacanya, dan SDK mengaturnya menjadi string kosong jika CapSkip tidak mengirim apa pun. Baca userAgent untuk mendapatkan User-Agent yang memperoleh token.
Untuk mencoba Langkah 1 dan 2 secara terpisah, tambahkan getChallenge().then(solve).then(console.log) sebagai baris terakhir dan jalankan node hcaptcha-demo.js. Anda akan melihat sebuah objek dengan captchaId, code, userAgent, respKey, dan token. Hapus baris itu lagi sebelum menambahkan blok berikutnya.
Langkah 3: serahkan token ke formulir
Widget browser mengisi dua field textarea tersembunyi dengan sendirinya, h-captcha-response dan cerminannya bernama g-recaptcha-response. Skrip tidak punya widget, jadi mengirimnya sebagai field formulir. Menurut dokumentasi CapSkip, artinya h-captcha-response selalu, g-recaptcha-response jika formulir memiliki field itu juga, dan User-Agent dari balasan. Formulir di bawah hanyalah pengganti, karena situs Anda punya field dan rute sendiri.
Token hanya sekali pakai, dan dokumentasi CapSkip menyebut token kedaluwarsa sekitar dua menit setelah diterbitkan. Dokumentasi hCaptcha sendiri menyebut 120 detik sebagai default untuk error expired-input-response. Jadi jangan memecahkan lebih awal, dan jangan menyimpan kumpulan token. Pecahkan, lalu kirim, untuk setiap pengiriman formulir.
async function postForm(solved) {
const form = new URLSearchParams({
username: "demo", // the form's own fields
"h-captcha-response": solved.token,
// delete the next line if the form has no g-recaptcha-response field
"g-recaptcha-response": solved.token,
});
// Send the User-Agent the reply names, not Node's default one.
return fetch(PAGE_URL, {
method: "POST",
headers: { "User-Agent": solved.userAgent },
body: form,
});
}Langkah 4: contoh lengkap dengan rqdata baru pada setiap percobaan
Blok terakhir merangkai semuanya menjadi loop percobaan ulang. Tambahkan di akhir hcaptcha-demo.js dan jalankan dengan node hcaptcha-demo.js. Setiap percobaan memanggil getChallenge lebih dulu, jadi setiap task membawa rqdata yang baru diterbitkan beberapa saat lalu. Loop hanya mengulang ERROR_CAPTCHA_UNSOLVABLE, kode untuk task yang tidak bisa dipecahkan. Dokumentasi CapSkip menyebut dua kegagalan yang akan terulang jika dikirim ulang: ERROR_RECAPTCHA_INVALID_SITEKEY pada polling, yang berarti hCaptcha menolak sitekey untuk halaman itu, dan ERROR_PROXY_CONNECT_REFUSED. Loop melempar ulang keduanya, dan setiap error lain, tanpa diubah.
Loop juga berputar lagi ketika situs menjawab di luar 200 sampai 299, karena token yang ditolak bisa berarti rqdata yang sudah basi. Status 403 bisa punya penyebab lain, seperti kata sandi yang salah pada formulir login, jadi percobaan dihentikan pada tiga.
// ERROR_CAPTCHA_UNSOLVABLE is the one failure where a new task can help.
async function login() {
for (let attempt = 1; attempt <= 3; attempt += 1) {
const challenge = await getChallenge(); // a new rqdata for every attempt
try {
const solved = await solve(challenge);
const resp = await postForm(solved);
if (resp.ok) return resp;
console.log(`attempt ${attempt}: the site answered HTTP ${resp.status}`);
} catch (err) {
// The message is the text of the app's reply: a bare code or small JSON.
const unsolvable = err instanceof ApiException
&& err.message.includes("ERROR_CAPTCHA_UNSOLVABLE");
if (!unsolvable) throw err;
console.log(`attempt ${attempt}: ERROR_CAPTCHA_UNSOLVABLE`);
}
}
throw new Error("hCaptcha not passed in 3 attempts");
}
login()
.then(async (resp) => console.log(resp.status, await resp.text()))
.catch((err) => {
console.error(`${err.name}: ${err.message}`);
if (err.cause) console.error(err.cause.code); // for example ECONNREFUSED
process.exitCode = 1;
});SDK menambahkan tiga kegagalan miliknya sendiri. ValidationException berarti SDK menolak panggilan sebelum mengirim apa pun: sitekey kosong, URL halaman yang bukan http atau https absolut, nilai invisible yang buruk, atau opsi yang tidak diterima API hCaptcha CapSkip, seperti domain milik 2Captcha. NetworkException pada submit berarti tidak ada yang menjawab di alamat CapSkip, dan TimeoutException berarti batas polling terlewati. Task baru tidak mengubah satu pun dari ketiganya, jadi loop melemparnya ulang. Pesan ApiException berisi balasan aplikasi sebagai teks, jadi loop mencocokkannya dengan includes().
Berikut yang dilakukan skrip terhadap mock, dengan capskip 1.6.0 pada Node.js 24.22.0. Node.js 20.11.1 dan 25.2.1 mengakhiri setiap kasus dengan cara yang sama, dengan exit code yang sama. Harness hanya mengubah alamat dan, pada baris timeout, batas polling.
| Pengaturan mock | Yang dilakukan skrip |
|---|---|
| Situs Enterprise; mock siap pada polling ketiga, atau 20 detik setelah submit | Satu task dan status 200 pada kedua kasus. Pada kasus pertama, polling terjadi pada sekitar 0, 0.3, dan 0.8 detik. Pada kasus kedua, polling terjadi pada sekitar 0, 0.3, 0.8, 1.8, 3.8, 7.8, 12.8, 17.8, dan 22.8 detik di ketiga runtime, jadi token sampai ke skrip 2.8 detik setelah siap |
| Situs invisible; situs yang tidak menerbitkan rqdata | in.php menerima invisible=1 pada kasus pertama dan tidak ada field data pada kasus kedua, dan kedua POST formulir lolos |
| ERROR_CAPTCHA_UNSOLVABLE dua kali dalam satu eksekusi, tiga kali dalam eksekusi lain | Dua kegagalan: status 200 pada task ketiga, dengan tiga nilai rqdata yang berbeda. Tiga kegagalan: Error “hCaptcha not passed in 3 attempts” dan exit code 1 |
| Situs mock menolak token pertama | “attempt 1: the site answered HTTP 403”, lalu task kedua dengan rqdata baru dan status 200 |
| Challenge yang di-cache dipakai ulang untuk login kedua (yang pertama lolos); field data dihilangkan; formulir dikirim tanpa User-Agent dari balasan | Setiap percobaan itu mendapat 403 dari situs mock, dan setiap eksekusi berakhir dengan Error “hCaptcha not passed in 3 attempts”. Ini aturan mock saya, bukan aturan situs sungguhan |
| Sitekey kosong, pageurl ftp, invisible diatur ke kata maybe, opsi domain; string proxy yang bukan proxy, key yang tidak dikenal CapSkip, tipe task ditolak | ValidationException pada empat kasus pertama, tanpa task yang dikirim ke in.php. ApiException dengan ERROR_PROXY_FORMAT, ERROR_KEY_DOES_NOT_EXIST, dan ERROR_TASK_NOT_SUPPORTED pada kasus lainnya, masing-masing setelah satu task. Exit code 1 setiap kali |
| Polling yang menjawab ERROR_PROXY_CONNECT_REFUSED atau ERROR_RECAPTCHA_INVALID_SITEKEY | Hanya satu task. Skrip berhenti pada error pertama |
| Proxy 203.0.113.10:8080 atau user:[email protected]:8080; mock tidak pernah siap (batas dipotong menjadi 1,5 detik); tidak ada proses di alamat CapSkip | in.php menerima string proxy tanpa perubahan, dengan proxytype HTTP, dan eksekusi lolos; TimeoutException: timeout 1.5 exceeded; NetworkException: connect ECONNREFUSED, lalu ECONNREFUSED di baris berikutnya, dan tanpa task |
| Mock tidak pernah siap dengan batas 120 detik; proses mock keluar saat pemecahan berlangsung (batas dipotong menjadi 4 detik) | Polling terakhir terjadi pada 118 detik dan TimeoutException pada sekitar 123. Setelah mock mati, SDK terus melakukan polling dan berakhir dengan TimeoutException, bukan error koneksi |
Kesalahan umum
| Kesalahan | Penyebab | Perbaiki |
|---|---|---|
| ApiException dengan ERROR_WRONG_USER_KEY atau ERROR_KEY_DOES_NOT_EXIST | API Key Validation aktif di CapSkip dan API_KEY bukan salah satu key-nya. | Atur API_KEY ke key dari CapSkip. |
| ApiException dengan ERROR_TASK_NOT_SUPPORTED | CapSkip menolak tipe task. Versi yang lebih lama dari 4.0.0 adalah salah satu penyebabnya | Perbarui ke 4.0.0 atau lebih baru |
| ApiException dengan ERROR_RECAPTCHA_INVALID_SITEKEY | hCaptcha menolak sitekey untuk halaman itu. Sitekey kosong tidak pernah sampai sejauh ini, karena SDK menolaknya lebih dulu | Periksa sitekey dan pageurl terhadap halaman |
| ValidationException | SDK menolak panggilan sebelum mengirim apa pun, dan pesannya menyebut masalahnya | Perbaiki panggilannya |
| ApiException dengan ERROR_PROXY_FORMAT | String proxy berformat yang tidak diterima CapSkip | Gunakan IP:PORT, LOGIN:PASSWORD@IP:PORT, atau IP:PORT:LOGIN:PASSWORD |
| ApiException dengan ERROR_PROXY_CONNECT_REFUSED | CapSkip tidak dapat menjangkau target melalui proxy | Coba proxy secara terpisah, periksa login dan tipenya, lalu jalankan ulang skrip |
| ApiException dengan ERROR_CAPTCHA_UNSOLVABLE | Task tidak dapat dipecahkan | Ambil rqdata baru dan kirim task baru. Loop melakukannya |
| TimeoutException: timeout 120 exceeded | Task masih berjalan pada batas skrip, atau ID tidak dikenal atau hasilnya sudah dibaca (keduanya kembali sebagai body kosong) | Periksa Monitor di CapSkip, lalu jalankan skrip lagi |
| NetworkException: connect ECONNREFUSED | Tidak ada yang menjawab di alamat CAPSKIP: CapSkip berhenti, atau host atau port salah. Baris setelahnya menunjukkan penyebabnya, ECONNREFUSED untuk port tanpa pendengar | Jalankan CapSkip, lalu bandingkan alamat dengan pengaturan koneksi Anda |
| Situs menolak formulir setelah token berhasil dipecahkan | Token lebih tua dari yang diizinkan situs, User-Agent atau alamat berbeda dari saat pemecahan, situs menilai token berisiko, atau rqdata sudah basi atau dipakai ulang (mock saya menegakkannya, dokumentasi hanya menyebut cepat kedaluwarsa) | Kirim segera setelah pemecahan, kirim userAgent dari balasan, ambil rqdata baru untuk setiap task, dan lihat catatan proxy di bawah |
Proxy dan mode Server
CapSkip tidak memaksa proxy untuk hCaptcha. Dokumentasi menyebut satu alamat IP cukup untuk pengujian dan pemecahan sesekali, tetapi hCaptcha menilai jaringan asal token sekaligus browsernya, dan aliran pemecahan yang stabil dari satu IP adalah hal yang ditangkap oleh rate limit-nya. Pada volume besar, atur kumpulan proxy di aplikasi di bawah Settings, Captcha types, hCaptcha, Configure Proxies. Agar pemecahan datang dari jaringan tertentu, kirim proxy bersama task, yang dilakukan pengaturan PROXY. Proxy yang dikirim bersama task selalu diutamakan daripada daftar. CapSkip menerima proxy sebagai IP:PORT, LOGIN:PASSWORD@IP:PORT, atau IP:PORT:LOGIN:PASSWORD. String proxy saja dikirim dengan proxytype HTTP. Untuk SOCKS5, berikan proxy sebagai objek dengan type, yang menerima HTTP, HTTPS, SOCKS5, atau SOCKS5H, dan uri. Terhadap mock, hasilnya sampai di in.php sebagai proxytype SOCKS5. Saya tidak menguji pemecahan SOCKS5 yang sungguhan.
Pengaturan itu hanya memindahkan pemecahan. Untuk situs ketat, dokumentasi juga meminta agar formulir dikirim dari alamat yang sama, tetapi fetch bawaan Node.js tidak punya opsi proxy per permintaan, jadi POST formulir di sini keluar dari PC yang menjalankan skrip. Saya tidak menguji POST formulir melalui proxy.
Mode Server hanya mengubah tempat pemecah berada. Arahkan pengaturan CAPSKIP ke server dan sisa skrip tetap seperti semula. Mode Server mengharuskan CapSkip berjalan sebagai administrator, dan IP publik statis memberikan akses jarak jauh yang paling stabil. Pemecahnya tetap perangkat keras Anda sendiri tanpa biaya per pemecahan. CapSkip kemudian menerima koneksi dari setiap alamat, jadi tambahkan aturan blokir Windows Firewall untuk alamat yang tidak boleh menjangkaunya, dan aktifkan API Key Validation di CapSkip lalu isi API_KEY. Pemecahan kini berjalan di Windows VPS, jadi hCaptcha melihat jaringan mesin itu, atau proxy yang Anda berikan.
FAQ
Mengapa hCaptcha Enterprise di Node.js memerlukan rqdata baru setiap kali?
Dokumentasi CapSkip menyebut situs menerbitkan nilai itu untuk satu challenge dan nilainya cepat kedaluwarsa, jadi nilai yang di-cache adalah nilai lama. Nilai yang basi adalah salah satu kemungkinan alasan token ditolak, dan satu-satunya yang bisa disingkirkan panduan ini. Bagaimana situs sungguhan gagal dengan nilai lama tidak didokumentasikan di mana pun yang bisa saya baca, jadi penolakan oleh mock saya hanya menunjukkan bagaimana loop bereaksi.
Bagaimana jika situs tetap menolak token yang dikembalikan CapSkip?
Lihat High score mode, di baris hCaptcha pada Captcha types di Settings. Changelog CapSkip menyebut 4.0.0 mengaktifkannya secara default dan bahwa mode ini memecahkan di Google Chrome. Ketika mode nonaktif, atau Chrome tidak terinstal, pemecahan berjalan di CapSkip Custom Browser, dan tanpa Chrome pengaturannya berwarna abu-abu. Dokumentasi API menambahkan tiga kebiasaan untuk situs ketat: pakai proxy yang baik, kirim formulir dari alamat yang sama, dan kirim User-Agent yang disebut balasan.
Bisakah saya memanggil CapSkip dari skrip yang berjalan di platform hosting atau VPS?
Bisa, begitu CapSkip dalam mode Server. Arahkan pengaturan CAPSKIP ke alamatnya dan skrip tidak memerlukan perubahan lain. Ingat bahwa pemecahan kemudian berjalan di server, jadi berikan proxy pada task jika situs memperhatikan jaringan. CapSkip tetap berada di perangkat keras milik Anda.
Apa pun yang dilemparkan situs kepada Anda, memecahkan hCaptcha Enterprise di Node.js tetap satu loop: rqdata baru, task baru, token yang langsung dikirim. Jika dijalankan melalui sebuah pemecah captcha di mesin Anda sendiri, percobaan ulang tidak dikenai biaya per pemecahan. Peralatan Node.js lainnya ada di halaman pemecah CAPTCHA Node.js, dan setiap parameter ada di bagian hCaptcha dalam dokumentasi API.
