Cara Memecahkan GeeTest v3 di Node.js dan Mengirimkannya Kembali

Hampir semua integrasi CAPTCHA berasumsi satu token masuk dan satu token keluar. GeeTest tidak bekerja seperti itu. Satu pemecahan mengembalikan tiga nilai yang harus dikirimkan bersama-sama, dan challenge yang menjadi titik awal Anda kedaluwarsa sekitar satu menit setelah Anda mengambilnya. Tidak satu pun kegagalan itu menghasilkan pesan error yang berguna, dan karena itulah GeeTest dikenal merepotkan.
Dua input, salah satunya cepat kedaluwarsa
| Nilai | Seumur hidup |
|---|---|
gt | Statis per situs. Bebas di-cache |
challenge | Sekali pakai, mati dalam kurang lebih 60 detik |
Keduanya berasal dari endpoint init GeeTest milik situs itu sendiri. Menganggap challenge dapat dipakai ulang adalah alasan integrasi lolos saat pengujian dan ambruk di produksi, tempat penundaan antrean mendorong pemecahan melewati masa kedaluwarsa.
Penyiapan
npm install capskip
const { CapSkip } = require('capskip');
const solver = new CapSkip({
host: '127.0.0.1',
port: 8080,
recaptchaTimeout: 300, // GeeTest uses this, not defaultTimeout
});Perbedaan itu penting. defaultTimeout hanya mengatur CAPTCHA gambar; semua yang interaktif menggunakan recaptchaTimeout.
Pemecahan
const result = await solver.geetest( '81388ea1fc187e0c335c0a8907ff2625', // gt, static per site '7cf6a8b1a2c34d5e6f7089abcdef0123', // challenge, fetched seconds ago 'https://example.com/login', ); console.log(result.challenge, result.validate, result.seccode);
Ketiga properti itulah jawabannya. result.code juga terisi, tetapi untuk GeeTest isinya string JSON mentah alih-alih sesuatu yang bisa dikirim, jadi mengambilnya karena kebiasaan menghasilkan kegagalan yang membingungkan.
Gunakan challenge yang dikembalikan, bukan yang Anda berikan. Keduanya tidak selalu identik.
Seluruh alur
const { CapSkip } = require('capskip');
const solver = new CapSkip();
const LOGIN = 'https://example.com/login';
// 1. Fresh pair, cache-busted. Cached init responses return spent challenges.
const init = await (await fetch(
`https://example.com/geetest/init?t=${Date.now()}`,
)).json();
// 2. Solve immediately. Nothing slow between here and the previous step.
const result = await solver.geetest(init.gt, init.challenge, LOGIN);
// 3. Post all three together with the real form fields.
const response = await fetch(LOGIN, {
method: 'POST',
body: new URLSearchParams({
geetest_challenge: result.challenge,
geetest_validate: result.validate,
geetest_seccode: result.seccode,
username: '...',
password: '...',
}),
});Timestamp penghindar cache itu benar-benar berguna. Endpoint init GeeTest sering di-cache oleh CDN atau proxy, dan respons yang di-cache memberi Anda challenge yang sudah dipakai orang lain.
Nama-nama field itu adalah konvensi umum GeeTest v3, meski sebuah situs bisa mengganti namanya. Periksa formulir aslinya sebelum berasumsi.
Jebakan batching
Di sinilah ergonomi Node bekerja melawan Anda. Versi paralel yang tampak jelas itu keliru:
// WRONG: every challenge is fetched up front, so the later solves // start against pairs that have already expired. const pairs = await Promise.all(urls.map(fetchPair)); const results = await Promise.all( pairs.map((p, i) => solver.geetest(p.gt, p.challenge, urls[i])));
Jaga agar pengambilan dan pemecahan tetap berada dalam task yang sama sehingga setiap pasangan dipakai dalam hitungan detik setelah diterbitkan:
// RIGHT: each task fetches its own pair immediately before solving.
const results = await Promise.all(urls.map(async (url) => {
const pair = await fetchPair(url);
return solver.geetest(pair.gt, pair.challenge, url);
}));AsyncCapSkip diekspor sebagai alias dari CapSkip di sini, sehingga tidak ada klien async terpisah yang perlu digunakan. Promise.all sudah mencakup semuanya.
Kesalahan
const {
ValidationException, NetworkException, ApiException, TimeoutException,
} = require('capskip');
try {
const result = await solver.geetest(gt, challenge, pageUrl);
} catch (err) {
if (err instanceof ValidationException) { /* missing gt or challenge */ }
else if (err instanceof NetworkException) { /* CapSkip not running */ }
else if (err instanceof ApiException) { /* usually an expired challenge */ }
else if (err instanceof TimeoutException) { /* exceeded recaptchaTimeout */ }
else throw err;
}Sebagian besar kegagalan GeeTest muncul sebagai ApiException dan berarti challenge-nya kedaluwarsa. Mencoba ulang dengan pasangan yang sama tidak pernah berhasil. Ambil yang baru.
Pertanyaan yang sering diajukan
Mengapa saya tidak bisa langsung memakai result.code?
Karena jawaban GeeTest terdiri dari tiga nilai. code menyimpan JSON mentah demi kelengkapan sementara SDK menguraikan bagian yang berguna menjadi challenge, validate dan seccode. Kirimkan semuanya.
Bisakah saya menyimpan nilai gt di cache?
Ya. gt adalah pengenal situs dan jarang berubah. challenge adalah bagian yang cepat kedaluwarsa dan harus diambil baru setiap kali.
Apakah ini menangani GeeTest v4?
The geetest metode menargetkan v3, teka-teki geser yang dibangun di atas gt dan challenge pasangan. v4 mengubah model parameternya, jadi periksa versi terkini dari dokumentasi API sebelum menganggap panggilan yang sama berfungsi.
Ringkasan
Ambil pasangan yang bebas cache, pecahkan segera, lalu kirim challenge, validate dan seccode bersama-sama. Gunakan challenge yang dikembalikan, cache hanya gt, dan pertahankan pengambilan dan pemecahan di dalam task yang sama saat berjalan paralel.
Bahasa lain ada di pemecah GeeTest , cakupan Node yang lebih luas ada di halaman pemecah CAPTCHA Node.js , dan ada puzzle langsung di halaman kami Demo GeeTest v3. CapSkip bisa bypass captcha secara lokal, sehingga volume pemecahan tidak menambah biaya.
