Cara Memecahkan Capy Puzzle di Node.js dan Mempertahankan Sesi

Untuk memecahkan Capy Puzzle di Node.js, ambil halaman dan baca key PUZZLE_ dari script widget. Berikan key itu bersama URL halaman ke metode capy dari paket capskip. Lalu kirim tiga nilai yang dikembalikannya di field capy_captchakey, capy_challengekey dan capy_answer, bersamaan dan secepatnya, sebagai bagian dari sesi yang mengambil halaman tersebut. Bagian terakhir itulah yang biasanya membuat kode Node gagal. Fungsi fetch bawaan Node tidak menyimpan cookie dan tidak mengirim Referer. Kiriman form pun tiba tanpa sesi yang dibuka halaman, dan situs menolaknya, sebenar apa pun jawabannya. CapSkip menambahkan Capy Puzzle pada versi 1.4.0. Panduan ini membahas key, pemanggilan, jeda dua detik, pengiriman, percobaan ulang, dan menjalankan banyak login sekaligus.
Apa yang Anda butuhkan
- CapSkip 1.4.0 atau lebih baru yang berjalan di komputer Windows. Rilis itu menambahkan Capy Puzzle, bersama CaptchaFox dan Friendly Captcha.
- Node.js 20.18.1 atau lebih baru, rilis tertua yang didukung cheerio. Untuk proyek baru, gunakan 22 atau 24, karena masa dukungan Node 20 sudah berakhir (end of life) pada April 2026.
- Paket capskip versi 1.3.0 atau lebih baru, rilis pertama yang memiliki metode capy, ditambah cheerio untuk membaca form.
- URL halaman yang menampilkan puzzle. Key, host Capy, dan field form semuanya diambil dari halaman itu.
- 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 skrip di mesin lain dapat memanggilnya melalui API. Keduanya diatur di pengaturan koneksi.
# capskip 1.3.0 added capy(); cheerio reads the form npm install capskip cheerio
Contoh kodenya berupa modul ES dengan top-level await. Simpan dengan ekstensi .mjs, atau setel field type di package.json Anda menjadi module, karena versi npm init terbaru menulis commonjs di sana, dan package.json tanpa field type juga dianggap CommonJS. Paket capskip juga bisa dimuat dengan require jika proyek Anda memakai CommonJS.
Langkah 1: ambil halaman, simpan cookie-nya, dan temukan key
Form Capy biasanya berada di balik halaman login atau pendaftaran yang menyetel cookie sesi dan menaruh token CSRF di dalam form. Fungsi fetch milik Node tidak menyimpan cookie di antara pemanggilan, sehingga cookie itu sudah hilang saat Anda mengirim form, dan token tersebut tidak lagi cocok dengan apa pun. Bawa sendiri cookie-nya. Headers.getSetCookie() mengembalikan setiap baris Set-Cookie secara terpisah, dan hanya itu yang dibutuhkan helper kecil addCookies di bawah; MDN mendokumentasikannya di bagian Headers.getSetCookie().
// npm install capskip cheerio
import * as cheerio from "cheerio";
const PAGE_URL = "https://example.com/login";
// fetch() keeps no cookies between calls, so carry them yourself.
const jar = new Map();
function addCookies(res) {
for (const line of res.headers.getSetCookie()) {
const pair = line.split(";")[0];
const eq = pair.indexOf("=");
if (eq > 0) jar.set(pair.slice(0, eq).trim(), pair.slice(eq + 1).trim());
}
}
const page = await fetch(PAGE_URL);
addCookies(page);
const html = await page.text();
const $ = cheerio.load(html);
// The widget script's k= parameter, or a capy_captchakey input.
const key = html.match(/PUZZLE_[A-Za-z0-9_-]+/)?.[0];
// Everything before /puzzle/get_js/ is the Capy host.
const apiServer = html.match(/(https:\/\/[^"'\s<>]+?)\/puzzle\/get_js\//)?.[1];
// The form that holds the widget script or a capy_captchakey input.
const form = $("form")
.has('script[src*="/puzzle/get_js/"], input[name="capy_captchakey"]').first();
console.log(key, apiServer ?? "default host", form.length);Key-nya bersifat publik dan sama untuk setiap pengunjung, dan key puzzle diawali PUZZLE_. Sebagian besar halaman menyimpannya di parameter k pada URL script widget, yang ada di HTML yang diunduh oleh fetch. Sebagian halaman juga merender input tersembunyi capy_captchakey di dalam form, dan setelah widget berjalan di browser, input itu selalu ada, di situlah DevTools menampilkannya. Satu regular expression menemukan key di kedua tempat itu.
Selagi Anda di sana, catat host script itu. 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 memerlukannya ketika sebuah halaman memuat widget dari tempat lain. Contoh kode yang ditulis untuk pemecah CAPTCHA lain sering menampilkan api.capy.me tanpa awalan regional, dan host itu sudah tidak bisa di-resolve lagi, jadi hapus opsi itu jika Anda menyalin salah satu contoh tersebut. Regex ini mengharapkan URL https://; jika src justru diawali //, tambahkan https: di depan host sebelum Anda memberikannya.
Baris form memilih form yang memuat script widget atau input capy_captchakey. Halaman yang memuat script di bagian head atau di bawah form, tanpa input capy_captchakey di dalam form, membuat form.length bernilai 0. Di halaman seperti itu, pilih form berdasarkan id atau action-nya.
Langkah 2: pemanggilan solver.capy()
Untuk memecahkan Capy Puzzle di Node.js, Anda cukup memakai satu metode. Metode ini menerima key, URL halaman, dan objek opsi yang bersifat opsional, dan untuk halaman di host default, hanya dua yang pertama yang dibutuhkan.
// npm install capskip
import { CapSkip } from "capskip";
const solver = new CapSkip({
host: "127.0.0.1",
port: 8080,
// Capy answers after a two second hold; poll often enough to catch it.
pollingInterval: 0.5,
});
// undefined (no widget script in the HTML) is dropped, so CapSkip
// uses its default host.
const result = await solver.capy(key, PAGE_URL, { apiServer });
console.log(result.captchakey); // goes in capy_captchakey
console.log(result.challengekey); // goes in capy_challengekey
console.log(result.answer); // goes in capy_answerHasilnya adalah objek biasa. Baca ketiga field bernama tersebut. result.code berisi seluruh jawaban dari server, sebuah objek dengan keempat field-nya, yang berguna untuk logging, dan result.respKey adalah string kosong yang hanya ada demi kompatibilitas dengan layanan lain. Jawabannya berupa string panjang yang awalnya kira-kira seperti 0xax8ex0xax84x: itu adalah jalur seretan yang akan direkam widget saat potongan puzzle digeser, bukan sebuah koordinat.
Opsi yang diterima metode ini
apiServer adalah alias dari api_server, dan metode ini membuang opsi apa pun yang bernilai undefined atau null, itulah sebabnya pemanggilan di atas bisa memberikan hasil regex setiap kali. Metode ini juga menerima objek proxy dengan key type dan uri, serta useragent, yang dikirim pada satu-satunya permintaan yang dibuat CapSkip untuk mengambil puzzle. 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 alih-alih mengembalikan jawaban yang akan ditolak situs.
Dua opsi per panggilan sering menjebak orang. Opsi timeout, dalam detik, menggantikan defaultTimeout milik klien untuk satu pemecahan itu. Batas atas interval polling juga bisa disetel per panggilan, tetapi hanya sebagai polling_interval. pollingInterval dalam camelCase adalah milik konstruktor, dan jika diberikan ke solver.capy(), opsi itu melempar ValidationException yang menyebut nama opsinya. TypeScript tidak akan memperingatkan Anda, karena tipe opsinya menerima key apa pun. Key atau URL yang kosong, opsi yang tidak dikenal, dan tipe proxy selain HTTP, HTTPS, SOCKS5 atau SOCKS5H juga melempar ValidationException, sebelum permintaan apa pun meninggalkan mesin Anda.
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, tanpa melibatkan browser maupun 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. Pengujian CapSkip sendiri terhadap Capy menempatkan batas bawah itu di sekitar satu detik, dan penolakannya membawa pesan yang sama dengan jawaban yang salah, sehingga pemecahan yang benar tetapi dikirim terlalu awal 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.
Dengan pengaturan default, sebuah pemanggilan memakan waktu mendekati empat detik, dan penyebabnya adalah polling. SDK meminta hasil segera setelah tugas masuk, lalu sekali lagi setelah seperempat detik. SDK terus menggandakan jaraknya hingga pollingInterval, yaitu 5 detik secara default. Polling terjadi pada 0, 0.25, 0.75, 1.75 dan 3.75 detik, sehingga jawaban yang siap pada detik kedua baru diambil pada polling kelima. Dengan pollingInterval: 0.5 di konstruktor, seperti di atas, pemanggilan kembali sekitar 2.3 detik setelah tugas dikirim dalam pengujian kami. Jangan menambahkan penundaan sendiri sebelum mengirim form, dan jangan mencoba memangkas jedanya: jeda itulah yang membuat jawabannya lolos.
Langkah 3: kirim ketiga nilai dengan cookie halaman
Ketiga nilai itu masuk ke field yang akan ditulis sendiri oleh widget ke dalam form. Kirim ketiganya bersamaan, dalam satu permintaan, dengan cookie dari Langkah 1 dan halaman tersebut sebagai Referer. Kirim juga dengan redirect disetel ke manual, agar sesi yang diberikan kembali oleh situs tetap menjadi milik Anda.
// The form's own fields, hidden CSRF token included.
const body = new URLSearchParams(
form.serializeArray().map((f) => [f.name, f.value]),
);
// Use the page's own field names, password included.
body.set("username", "YOUR_USERNAME");
body.set("capy_captchakey", result.captchakey);
body.set("capy_challengekey", result.challengekey);
body.set("capy_answer", result.answer);
const res = await fetch(new URL(form.attr("action") || PAGE_URL, PAGE_URL), {
method: "POST",
headers: {
cookie: [...jar].map(([k, v]) => `${k}=${v}`).join("; "),
// fetch sends no Referer; strict servers refuse a post without one.
referer: PAGE_URL,
},
body,
// A login answers 302 with a new session cookie; keep it.
redirect: "manual",
});
addCookies(res);
console.log(res.status, res.headers.get("location"));serializeArray mengumpulkan field yang akan dikirim browser, termasuk token CSRF tersembunyi, sehingga Anda tidak perlu menyebut namanya satu per satu. Tombol submit tidak ikut dikumpulkan, jadi jika server memeriksa nama tombol, tambahkan dengan body.set. body.set juga mengganti input capy_captchakey yang dirender sendiri oleh halaman, sehingga key tidak pernah terkirim dua kali. Referer sama pentingnya dengan cookie. Fungsi fetch tidak mengirim Referer maupun Origin, dan beberapa framework, salah satunya Django, menolak form post HTTPS yang tidak memiliki keduanya, bahkan dengan cookie, token, dan jawaban yang benar.
Pengaturan redirect menjaga sesi setelah login berhasil. Login biasanya menjawab dengan 302 beserta cookie sesi baru, karena framework seperti Django merotasi sesi pada titik itu. Jika dibiarkan, fetch mengikuti redirect tanpa cookie tersebut, kembali ke halaman login, dan melaporkan 200. Dengan redirect disetel ke manual, Anda mendapatkan 302 itu sendiri, dan addCookies menaruh cookie baru ke dalam jar untuk permintaan berikutnya.
Kirim jawaban persis seperti yang dikembalikan. Backend situs memeriksanya terhadap puzzle yang diambil, jadi memotong atau menyusunnya ulang akan membuatnya tidak valid. URLSearchParams melakukan percent-encoding pada body, dan itu tidak masalah, karena server men-decode-nya sebelum memeriksa. Lalu kirim secepatnya. CapSkip membuat challenge key baru untuk setiap pemecahan, dan Capy mengikat puzzle yang diambilnya ke key tersebut. Jadi key itu hanya sekali pakai dan berumur pendek, dan satu pemecahan hanya untuk satu pengiriman. Sebagian halaman mengirim lewat script miliknya sendiri dengan body JSON, bukan form post. Kirim sekali secara manual dengan DevTools terbuka, lalu taruh ketiga nilai di tempat halaman itu menaruhnya.
Langkah 4: percobaan ulang saat pemecahan gagal
Saat Anda memecahkan Capy Puzzle di Node.js dalam volume berapa pun, beberapa pemecahan akan gagal. Pemecahan yang gagal datang sebagai ApiException yang pesannya berisi ERROR_CAPTCHA_UNSOLVABLE, dan lewat res.php, endpoint yang di-polling SDK, satu kode itu mencakup dua situasi yang berbeda. Kegagalan menemukan lubang hanya terjadi sesekali, dan percobaan berikutnya memunculkan puzzle baru di atas foto yang berbeda, sehingga biasanya berhasil. Key yang ditolak Capy API gagal di setiap percobaan, dan hitungan Bad Keys pada kartu Capy di tab Monitor CapSkip bertambah. Coba ulang yang pertama dan perbaiki yang kedua.
import { ApiException } from "capskip";
async function solveCapy(key, url, options = {}, attempts = 3) {
for (let attempt = 1; ; attempt++) {
try {
return await solver.capy(key, url, options);
} catch (err) {
// A missed hole reads as unsolvable, and the next try draws a
// new puzzle. Anything else, such as a wrong API key, is final.
const miss = err instanceof ApiException && err.message.includes("UNSOLVABLE");
if (!miss || attempt === attempts) throw err;
}
}
}Pesan ApiException adalah balasan mentah dari CapSkip, jadi pemeriksaan ini langsung membaca kode error dari pesan itu. Key yang ditolak juga terbaca sebagai unsolvable, sehingga key itu ikut dicoba ulang di sini, dan kegagalannya selalu sama di setiap percobaan: itulah tandanya. Jalan lainnya adalah pengaturan Retries di bagian Capy pada pengaturan CapSkip, yang menerima nilai 0 sampai 3 dan bernilai 0 secara default. CapSkip lalu mencoba ulang pemecahan yang meleset dengan sendirinya, tetapi tidak pernah mencoba ulang key yang ditolak, karena key itu akan ditolak dengan cara yang sama.
Metode capy melakukan polling dengan defaultTimeout milik klien, 120 detik, karena pemecahan Capy hanyalah satu pengambilan dan sedikit aritmetika, bukan sesi browser. CapSkip juga menjalankan hitungan waktunya sendiri. Di pengaturan Capy-nya, sebuah tugas bisa menunggu hingga 250 detik (Wait Timeout) untuk mendapatkan salah satu dari 10 thread (Max. Threads), dan satu percobaan mendapat 60 detik (Row Timeout). Pemecahan normal muat di dalam semua batas itu berkali-kali lipat. SDK juga terus melakukan polling menembus error koneksi, jadi jika CapSkip berhenti di tengah pemecahan, pemanggilan berakhir dengan TimeoutException, bukan NetworkException.
Contoh lengkap yang berfungsi
Berikut seluruh alurnya dalam satu file. logIn mengambil halaman ke dalam cookie jar miliknya sendiri, membaca key dan host, memecahkan dengan percobaan ulang, lalu mengirim form beserta cookie-nya dan sebuah Referer. Fungsi ini mengembalikan respons dan jar, sehingga permintaan yang Anda buat setelah login membawa sesi yang baru.
// npm install capskip cheerio
// login.mjs: run with node login.mjs
import * as cheerio from "cheerio";
import {
CapSkip, ApiException, CapSkipError, TimeoutException, ValidationException,
} from "capskip";
const PAGE_URL = "https://example.com/login";
const solver = new CapSkip({
apiKey: process.env.CAPSKIP_API_KEY ?? "capskip",
host: process.env.CAPSKIP_HOST ?? "127.0.0.1",
port: Number(process.env.CAPSKIP_PORT ?? 8080),
pollingInterval: 0.5,
});
async function solveCapy(key, url, options = {}, attempts = 3) {
for (let attempt = 1; ; attempt++) {
try {
return await solver.capy(key, url, options);
} catch (err) {
// A missed hole reads as unsolvable; the next try draws a new puzzle.
const miss = err instanceof ApiException && err.message.includes("UNSOLVABLE");
if (!miss || attempt === attempts) throw err;
console.log(`attempt ${attempt}: ${err.message}`);
}
}
}
function addCookies(jar, res) {
for (const line of res.headers.getSetCookie()) {
const pair = line.split(";")[0];
const eq = pair.indexOf("=");
if (eq > 0) jar.set(pair.slice(0, eq).trim(), pair.slice(eq + 1).trim());
}
}
async function logIn(pageUrl, username) {
// One jar per run, so runs side by side never share a session.
const jar = new Map();
const page = await fetch(pageUrl);
addCookies(jar, page);
const html = await page.text();
const $ = cheerio.load(html);
const key = html.match(/PUZZLE_[A-Za-z0-9_-]+/)?.[0];
if (!key) throw new Error("No PUZZLE_ key in the HTML; find it in DevTools.");
const apiServer = html.match(/(https:\/\/[^"'\s<>]+?)\/puzzle\/get_js\//)?.[1];
const form = $("form")
.has('script[src*="/puzzle/get_js/"], input[name="capy_captchakey"]').first();
if (!form.length) throw new Error("No form holds the widget; select it by id.");
const result = await solveCapy(key, pageUrl, { apiServer });
// All three together, straight away: the challenge key is single-use.
const body = new URLSearchParams(form.serializeArray().map((f) => [f.name, f.value]));
// Use the page's own field names, password included.
body.set("username", username);
body.set("capy_captchakey", result.captchakey);
body.set("capy_challengekey", result.challengekey);
body.set("capy_answer", result.answer);
const action = new URL(form.attr("action") || page.url, page.url);
const res = await fetch(action, {
method: "POST",
headers: {
cookie: [...jar].map(([k, v]) => `${k}=${v}`).join("; "),
referer: page.url,
},
body,
// A login answers 302 with a new session cookie. Keep the 302, so
// its Set-Cookie lands in the jar instead of being followed away.
redirect: "manual",
});
addCookies(jar, res);
return { res, jar };
}
try {
const { res, jar } = await logIn(PAGE_URL, "YOUR_USERNAME");
// A 302 to the account page means it worked; jar holds that session.
console.log(res.status, res.headers.get("location"), [...jar.keys()]);
} catch (err) {
if (err instanceof ValidationException) console.error(`not sent: ${err.message}`);
else if (err instanceof TimeoutException) console.error("gave up after defaultTimeout");
else if (err instanceof CapSkipError) console.error(`solve failed: ${err.name}: ${err.message}`);
else throw err;
process.exitCode = 1;
}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. Jika pemeriksaan key melempar error, halaman tersebut membangun widget dari script yang di-bundle: buka tab Network lalu salin key dan host dari permintaan milik widget itu sendiri. Endpoint mentah di balik metode ini didokumentasikan di bagian Capy pada referensi API.
Menjalankan banyak login secara berdampingan
Setiap metode CapSkip di Node mengembalikan Promise, dan AsyncCapSkip hanyalah nama lain untuk kelas yang sama, jadi menjalankan pemecahan secara berdampingan cukup dengan JavaScript biasa. Yang Anda butuhkan adalah batas. CapSkip menjalankan 10 pemecahan Capy sekaligus secara default dan membuat sisanya menunggu thread yang kosong, jadi pool kecil yang menjaga sepuluh pemecahan tetap berjalan sudah sesuai dengannya. Taruh pool itu sebagai pengganti blok try di akhir contoh lengkap:
// At most `limit` calls in flight; a failure becomes that item's Error.
async function mapLimited(items, limit, fn) {
const results = new Array(items.length);
let next = 0;
async function worker() {
while (next < items.length) {
const i = next++;
results[i] = await fn(items[i]).catch((err) => err);
}
}
await Promise.all(Array.from({ length: Math.min(limit, items.length) }, worker));
return results;
}
const users = ["YOUR_USERNAME_1", "YOUR_USERNAME_2", "YOUR_USERNAME_3"];
const results = await mapLimited(users, 10, (user) => logIn(PAGE_URL, user));
for (const r of results) console.log(r instanceof Error ? r.message : r.res.status);logIn membangun cookie jar sendiri di setiap pemanggilan, dan itulah yang membuatnya aman dijalankan secara paralel. Satu jar yang dipakai bersama oleh sepuluh proses login akan mencampuradukkan sesi dan token CSRF mereka. Fungsi ini juga menjaga setiap pemecahan tetap berpasangan dengan kirimannya sendiri. Memecahkan seratus puzzle lebih dulu lalu mengirim belakangan membuat challenge key yang paling awal menua selagi pemecahan terakhir selesai. Pada volume besar, tambahkan juga 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 bagian Capy pada CapSkip, atau berikan objek proxy di setiap pemanggilan; proxy hanya menyentuh pengambilan puzzle, satu-satunya permintaan yang dibuat oleh pemecahan Capy.
Menjalankan solver di mesin lain
127.0.0.1 sudah benar selama skrip dan CapSkip berada di PC Windows yang sama. Begitu kode Node dipindahkan ke VPS, container, CI runner, atau fungsi serverless, loopback menunjuk ke mesin yang salah dan pemecahan pertama melempar NetworkException dengan ECONNREFUSED. Alihkan CapSkip ke mode Server dan ia akan mendengarkan di alamat jaringan atau IP publik Anda, sehingga semua lingkungan itu dapat memanggilnya melalui API yang sama. Gunakan IP publik statis jika rutenya melewati internet dan aktifkan validasi API key. CapSkip membuka port-nya untuk semua alamat saat mode Server dimulai, jadi untuk membatasinya hanya pada mesin yang Anda harapkan, tambahkan aturan blokir Windows Firewall untuk alamat lainnya. Pemecah CAPTCHA tetap berupa mesin Windows milik Anda sendiri, dan pemecahannya tetap tanpa kuota.
Klien tidak membaca variabel lingkungan dengan sendirinya. Baca CAPSKIP_HOST, CAPSKIP_PORT dan CAPSKIP_API_KEY di kode Anda dan berikan ke konstruktor, seperti pada contoh lengkap, agar skrip yang sama bisa berjalan di komputer Anda maupun di server.
Kesalahan umum dan artinya
| Apa yang Anda lihat | Penyebab | Perbaiki |
|---|---|---|
| Situs menyatakan sesi telah kedaluwarsa, padahal solver.capy() mengembalikan ketiga nilai | Form dikirim tanpa cookie yang disetel halaman, sehingga field CSRF tidak lagi cocok dengan sesi mana pun | Bawa cookie dari pengambilan halaman, satu jar untuk setiap login |
| Kiriman form mengembalikan 200 dan halaman login, padahal situs menerima login tersebut | Login menjawab dengan 302 beserta cookie sesi baru, dan fetch mengikuti redirect tanpa cookie itu | Kirim dengan redirect disetel ke manual dan tambahkan baris Set-Cookie dari respons 302 ke dalam jar |
| 403 saat mengirim form, padahal cookie sudah benar dan ketiga nilai lengkap | fetch tidak mengirim Referer maupun Origin, dan situs memeriksa keduanya | Kirim URL halaman sebagai header Referer |
| Situs menolak jawaban itu sendiri | Jawaban diubah, atau hanya satu atau dua nilai yang sampai ke form | Kirim result.answer apa adanya, bersama dua nilai lainnya, dalam satu permintaan |
| Kiriman yang pernah berhasil sekali gagal pada kali kedua | Challenge key hanya sekali pakai dan berumur pendek | Pecahkan ulang untuk setiap pengiriman, dan langsung kirim |
| ApiException pada setiap percobaan, untuk satu key | Capy API menolak key tersebut, atau api_server menunjuk ke host yang salah | Salin ulang key, termasuk awalannya, dan periksa host pada tag script |
| ApiException sesekali yang berisi ERROR_CAPTCHA_UNSOLVABLE | CapSkip tidak dapat menemukan lubang pada puzzle itu | Coba ulang; percobaan berikutnya memunculkan puzzle yang berbeda |
| ValidationException sebelum apa pun terkirim | Key atau URL kosong, opsi yang tidak diterima metode ini, seperti pollingInterval per panggilan, avatar sebagai version, atau tipe proxy yang tidak diterima CapSkip | Pastikan key berhasil ditemukan, lalu perbaiki atau buang opsi yang disebut dalam pesan |
| ApiException dengan ERROR_KEY_DOES_NOT_EXIST atau ERROR_WRONG_USER_KEY pada pemanggilan pertama | Validasi API key aktif di CapSkip, dan skrip mengirim key default atau tidak mengirim key sama sekali | Setel CAPSKIP_API_KEY ke key yang dikonfigurasi di CapSkip |
| Setiap pemanggilan memakan waktu sekitar empat detik | Jarak polling terus digandakan menuju batas atas default 5 detik, sehingga jawaban yang siap pada detik kedua menunggu polling pada detik 3.75 | Setel pollingInterval: 0.5 di konstruktor |
| TimeoutException di bawah beban paralel yang berat | Login yang sedang berjalan lebih banyak daripada yang bisa diselesaikan 10 thread dalam 120 detik, atau CapSkip berhenti di tengah pemecahan | Batasi ukuran pool sesuai Max. Threads, atau berikan timeout yang lebih panjang untuk pemanggilan itu |
| NetworkException pada pemanggilan pertama, dengan ECONNREFUSED atau ETIMEDOUT di pesannya, atau di err.cause.code jika host berupa nama | CapSkip tidak berjalan, host atau port-nya salah, atau firewall memblokir koneksi | Jalankan CapSkip, lalu periksa apakah ia harus berada di mode Local atau mode Server |
FAQ
Apakah paket capskip bisa dipakai dengan TypeScript di sini?
Bisa, paket ini menyertakan definisi tipenya sendiri. Ada dua detail yang penting untuk Capy. Tipe hasil menandai captchakey, challengekey dan answer sebagai opsional, karena metode lain tidak mengisinya. Karena itu strict mode membutuhkan pemeriksaan atau non-null assertion sebelum Anda memberikannya ke body.set. Selain itu, tipe opsinya menerima key apa pun, sehingga opsi yang salah tulis atau salah tempat, seperti pollingInterval per panggilan, lolos kompilasi tanpa masalah dan gagal saat runtime dengan ValidationException.
Apakah user agent node membuat jawaban ditolak?
Tidak oleh Capy. Jawaban Capy tidak terikat pada browser, CapSkip tidak mengembalikan user agent untuknya, dan user agent opsional yang bisa Anda berikan hanya mengubah permintaan yang mengambil puzzle. Situsnya sendiri mungkin tetap menolak permintaan yang user agent-nya node, dengan alasannya sendiri. Jika begitu, tambahkan header user-agent browser ke pengambilan halaman maupun ke kiriman form.
Apa bedanya dengan versi Python?
Pemanggilan, jeda, dan aturannya sama. Di Python, requests.Session menyimpan cookie untuk Anda, sedangkan di Node Anda membawanya sendiri, dan hasilnya berupa dict di sana dan objek di sini. Sisi Python dibahas dalam panduan memecahkan Capy Puzzle di Python.
Bisakah skrip Node 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 skrip Anda, lalu berikan ke konstruktor. VPS, host container, CI runner, dan fungsi serverless semuanya terhubung melalui API HTTP yang sama. Gunakan IP publik statis jika rutenya melewati internet, dengan aturan blokir Windows Firewall untuk alamat yang seharusnya tidak menjangkau port tersebut. Pemecah CAPTCHA tetap berada di perangkat milik Anda, jadi tidak ada yang berubah soal cara pemecahan dihitung.
Versi singkatnya
Untuk memecahkan Capy Puzzle di Node.js, ambil halaman ke dalam cookie jar, tarik key PUZZLE_ dengan satu regex, dan catat host script widget kalau-kalau bukan host default. Panggil solver.capy() dengan key dan URL halaman yang sebenarnya dari klien yang dibuat dengan pollingInterval: 0.5, lalu biarkan ia memakan sekitar dua detiknya. Kirim captchakey, challengekey dan answer di ketiga field capy_, apa adanya, bersamaan dan seketika, dengan cookie halaman dan halaman itu sebagai Referer, lalu simpan cookie yang diberikan kembali oleh respons 302. Coba ulang pemecahan yang sesekali meleset, jangan biarkan jumlah login yang berjalan melebihi Max. Threads, dan beralihlah ke mode Server begitu skrip tidak lagi berada di mesin pemecah CAPTCHA.
- Cara kerja tipe ini dan apa saja yang dicakup pemecah CAPTCHA: halaman pemecah Capy Puzzle.
- Setiap tipe CAPTCHA yang ditangani paket Node.js: halaman pemecah CAPTCHA Node.js.
Satu hal terakhir tentang percobaan ulang itu. Setiap percobaan memunculkan puzzle yang berbeda, jadi 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.
