Node.js ile Tarayıcı Olmadan Friendly Captcha Nasıl Çözülür

Node.js ile Friendly Captcha çözmek için sayfayı çekin ve sayfanın ayarladığı çerezleri saklayın, frc-captcha widget’ını ve script etiketini cheerio ile okuyun, v1 mi v2 mi olduğuna bu script’e bakarak karar verin ve sitekey’i, sayfa URL’sini, sürümü ve script adresini CapSkip’in friendlyCaptcha metoduna verin. Dönen token’ı formun kendi gizli alanlarıyla birlikte, v2’de frc-captcha-response, v1’de frc-captcha-solution alanında gönderin. Buradaki hataların çoğunun iki nedeni vardır. Yerleşik fetch hiçbir çerezi saklamaz, bu yüzden CSRF korumalı bir form kusursuz bir token’ı bile reddeder. Yanlış sürümü çözmek ise geçerli görünen ama sessizce başarısız olan bir token döndürür. CapSkip, Friendly Captcha desteğini 1.4.0 sürümünde ekledi; bu rehber de tüm süreci sizin tarafınızda hiçbir tarayıcı olmadan yürütüyor.
Neye ihtiyacınız var
- Bir Windows makinesinde çalışan CapSkip 1.4.0 veya üzeri. Friendly Captcha desteği, CaptchaFox ve Capy Puzzle ile birlikte bu sürümle geldi.
- Node.js 22 veya üzeri ve capskip paketinin 1.3.0 veya üzeri bir sürümü; friendlyCaptcha metodunu içeren ilk sürüm budur. Örnekler ayrıca HTML’i okumak için cheerio kullanır.
- Widget’ı gösteren sayfanın URL’si. Sitekey, script adresi ve alan adı bu sayfanın HTML’inden çıkar.
- Çözücü için bir adres. Local modu 127.0.0.1 üzerinden yalnızca o cihaza yanıt verir; Server modu ise ağ adresinizi veya genel IP’nizi dinler, böylece başka bir makinedeki bir betik onu API üzerinden çağırabilir. İkisi de bağlantı ayarları bölümünde yer alır; ne zaman geçiş yapmanız gerektiğini 4. adım anlatıyor.
# npm install capskip cheerio npm install capskip cheerio
Örnekler, üst düzey await kullanan ES modülleridir. Onları .mjs uzantısıyla kaydedin ya da package.json dosyanızdaki type alanını module olarak değiştirin, çünkü npm init artık oraya commonjs yazıyor; böylece import gösterildiği gibi çalışır. Projeniz CommonJS ise capskip paketi require ile de yüklenir.
1. Adım: sayfayı çekin ve çerezlerini saklayın
Node’daki fetch iyi bir HTTP istemcisidir, ama burada önemli olan bir eksiği vardır: cookie jar’ı yoktur. Her çağrı sıfırdan başlar, dolayısıyla sayfanın ayarladığı oturum çerezi, siz formu gönderene kadar çoktan kaybolmuştur. CSRF token’ını bu oturuma bağlayan bir site de, CAPTCHA token’ı ne kadar iyi olursa olsun, gönderimi çoğu zaman bir 403 ile reddeder. Python’daki requests.Session bu sorunu gizler, ama Node’da çerezleri kendiniz taşırsınız.
Bunun için kullanılacak araç Headers.getSetCookie() metodudur; her Set-Cookie satırını ayrı bir değer olarak döndürür. Düz bir headers.get çağrısı bu işi yapamaz, çünkü satırları virgülle birleştirir ve çerezlerin son kullanma tarihlerinde de virgül bulunur.
// npm install capskip cheerio
import * as cheerio from "cheerio";
const PAGE_URL = "https://example.com/signup";
// fetch() keeps no cookies between calls, so carry them by hand.
const jar = new Map();
function remember(res) {
for (const line of res.headers.getSetCookie()) {
const pair = line.split(";")[0];
const eq = pair.indexOf("=");
jar.set(pair.slice(0, eq).trim(), pair.slice(eq + 1).trim());
}
}
const cookieHeader = () => [...jar].map(([k, v]) => `${k}=${v}`).join("; ");
const page = await fetch(PAGE_URL);
remember(page);
const $ = cheerio.load(await page.text());Bu cookie jar bilerek küçük tutuldu. Yalnızca adları ve değerleri saklar, yolları ve son kullanma tarihlerini yok sayar; tek bir site ve tek bir form için gereken de bu kadarıdır.
2. Adım: widget’ı okuyun, v1 ya da v2’yi seçin ve friendlyCaptcha metodunu çağırın
Her iki sürüm de aynı öğeyi oluşturur: frc-captcha sınıfına ve bir data-sitekey özniteliğine sahip bir div. Bu yüzden widget tek başına protokol hakkında hiçbir şey söylemez. Bunu söyleyen script etiketidir. Bir v2 sitesi, dosyası site.min.js olan @friendlycaptcha/sdk paketini, bir v1 sitesi ise dosyası widget.module.min.js olan friendly-challenge paketini yükler. Cheerio ikisini de birkaç satırda çıkarır:
const widget = $(".frc-captcha").first();
const form = widget.closest("form");
// Every script except nomodule fallbacks, as full addresses.
const scripts = $("script[src]").not("[nomodule]")
.map((_, el) => new URL($(el).attr("src"), PAGE_URL).href)
.get();Sayfa URL’sini taban adres olarak vermek, kendi sunucusunda barındırılan widget’lar için önemlidir. Bu, /vendor/v2/site.min.js gibi göreli bir src değerini tam bir adrese çevirir; v2’de CapSkip, çözümü yürütmek için tam olarak bu script’i kendi tarayıcısında yükler. Yalın bir yol hiçbir zaman yüklenmez.
CapSkip sürümü sabit bir sırayla seçer ve ilk cevapta durur: önce sizin verdiğiniz sürüm, sonra moduleScript olarak verdiğiniz script adresi, en son da varsayılan v1. Tuzak bu varsayılandır. /assets/app.4f2a.js gibi bundle edilmiş bir script CapSkip’e hiçbir şey söylemez; bu yüzden CapSkip v1 çözer ve bir v2 sitesi her token’ı reddeder. Bunun yerine kararı, tahmin yürütmeyi reddedebileceğiniz kendi kodunuzda verin:
const V2_FILES = ["site.min.js", "site.compat.min.js"];
const V1_FILES = ["widget.module.min.js", "widget.min.js", "widget.polyfilled.min.js"];
function friendlyVersion(scripts, widget) {
// Package names are unambiguous, so check them first.
for (const src of scripts) {
if (src.includes("@friendlycaptcha/sdk")) return { version: "v2", script: src };
if (src.includes("friendly-challenge")) return { version: "v1", script: src };
}
// Self-hosted builds usually keep the file name. Themes ship their own
// site.min.js too, so only trust a path that says friendly.
for (const src of scripts.filter((s) => s.toLowerCase().includes("friendly"))) {
const file = new URL(src).pathname.split("/").pop();
if (V2_FILES.includes(file)) return { version: "v2", script: src };
if (V1_FILES.includes(file)) return { version: "v1", script: src };
}
// Last resort: v2 and v1 name their widget options differently.
if (widget.is("[data-api-endpoint], [data-form-field-name]")) return { version: "v2" };
if (widget.is("[data-puzzle-endpoint], [data-solution-field-name]")) return { version: "v1" };
throw new Error("v1 or v2? Read the page and set it by hand.");
}Dosya adı kontrolü yalnızca içinde friendly geçen yollara güvenir, çünkü bir tema, widget ile hiçbir ilgisi olmayan kendi site.min.js dosyasını yükleyebilir.
Ardından çağrıyı yapın. friendlyCaptcha metodu sitekey’i, sayfa URL’sini ve bir seçenekler nesnesini alır. SDK, herhangi bir şey göndermeden önce undefined değerleri atar; böylece sayfada bulunmayan bir öznitelik doğrudan isteğin dışında kalır:
import { CapSkip } from "capskip";
const solver = new CapSkip({ host: "127.0.0.1", port: 8080 });
const { version, script } = friendlyVersion(scripts, widget);
const result = await solver.friendlyCaptcha(widget.attr("data-sitekey"), PAGE_URL, {
version,
moduleScript: script,
// EU sites: data-api-endpoint="eu" (v2) or data-puzzle-endpoint (v1)
apiServer: widget.attr("data-api-endpoint") ?? widget.attr("data-puzzle-endpoint"),
});
console.log(result.token.slice(0, 40)); // v2 tokens start with AQQA.apiServer satırı, Friendly Captcha’nın EU endpoint’ini kullanan siteler içindir. Global endpoint bir EU sitekey’i için de token üretir; dolayısıyla orada çözmek yalnızca sitenin kendi kontrolünde başarısız olur ve bu, yanlış sürümdeki sessiz hatanın aynısıdır. result.token gönderilecek dizedir, result.code aynı dizeyi tutar, result.captchaId ise CapSkip’in bu iş için verdiği kimliktir. v1, v2, 1 veya 2 dışında bir sürüm, boş bir sitekey ya da metodun tanımadığı bir seçenek, makinenizden daha hiçbir istek çıkmadan ValidationException fırlatır.
3. Adım: token’ı formun kendi alanlarıyla birlikte gönderin
Token alanı, çektiğiniz HTML’de yoktur, çünkü onu widget script’i tarayıcıda oluşturur. Bu yüzden alanı, sürümün ve widget’ın kullandığı adla kendiniz eklersiniz. Formun taşıdığı diğer her şey, gizli bir CSRF token’ı da dahil, formun kendisinden gelir:
// A renamed field wins; otherwise the default for the version.
const field = widget.attr("data-form-field-name")
?? widget.attr("data-solution-field-name")
?? (version === "v2" ? "frc-captcha-response" : "frc-captcha-solution");
// The form's own fields, hidden CSRF token included.
const body = new URLSearchParams(
form.serializeArray().map((f) => [f.name, f.value]),
);
body.set("email", "YOUR_EMAIL");
body.set(field, result.token);
const res = await fetch(new URL(form.attr("action") || PAGE_URL, PAGE_URL), {
method: "POST",
// Browsers send the page as Referer; some servers refuse a post without it.
headers: { cookie: cookieHeader(), referer: PAGE_URL },
body,
});
console.log(res.status);serializeArray, bir tarayıcının göndereceği alanları toplar; CSRF token’ı da siz adını anmadan sunucuya bu sayede geri döner. Gönder düğmesini dışarıda bırakır; site düğmenin adını kontrol ediyorsa onu body.set ile ekleyin. Sayfa URL’sini Referer olarak da gönderin: fetch ne Referer ne de Origin başlığı gönderir ve aralarında Django’nun da bulunduğu bazı framework’ler, çerez ve token ne kadar doğru olursa olsun ikisi de olmayan bir HTTPS form gönderimini reddeder. URLSearchParams gövdesi, fetch’in sıradan bir form gönderimi yapmasını ve içerik türünü sizin yerinize ayarlamasını sağlar. Bir v2 token’ı yaklaşık altı kilobayttır, bu yüzden yeri bu gövdedir, asla bir sorgu dizesi değildir; bir v1 token’ı ise noktalarla ayrılmış dört parçadan oluşur ve birkaç yüz karakterdir. Token’a hiç dokunmadan olduğu gibi iletin.
İki durumda DevTools’a bakmanız gerekir. v1’de tek bir kısa çizgiye ayarlanmış data-solution-field-name, widget’ın hiçbir alan yazmadığı ve token’ı sitenin kendi script’inin başka bir yolla gönderdiği anlamına gelir. Bazı siteler de formu göndermek yerine JavaScript ile JSON gönderir. Her iki durumda da formu bir kez elle gönderin ve sayfanın gerçekte yaptığı isteği kopyalayın.
Her token tek bir gönderim için geçerlidir. Friendly Captcha’nın doğrulaması daha önce kullanılmış veya süresi dolmuş bir yanıtı reddeder, bu yüzden her form için yeniden çözün.
4. Adım: aynı anda çok sayıda form ve çözücünün nerede çalıştığı
Node’da her CapSkip metodu zaten bir Promise döndürür ve AsyncCapSkip aynı sınıfın yalnızca başka bir adıdır; dolayısıyla eşzamanlılık sade JavaScript’tir. İhtiyacınız olan şey bir üst sınırdır. Promise.all ile yüz çağrıyı birden gönderirseniz CapSkip, Friendly Captcha bölümündeki Max. Threads ayarını (varsayılanı 10) aşan her şeyi kuyruğa alır; orada bir görev, CapSkip onu başarısız saymadan önce boş bir thread için en fazla 250 saniye bekler. Küçük bir worker havuzu aynı anda en fazla on çağrıyı işlemde tutar:
// Run fn over items with at most `limit` in flight. A failed item
// becomes its Error instead of rejecting the whole batch.
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;
}
// jobs: { sitekey, url, version, script, apiServer } objects from Step 2
const tokens = await mapLimited(jobs, 10, (job) =>
solver.friendlyCaptcha(job.sitekey, job.url, {
version: job.version,
moduleScript: job.script,
apiServer: job.apiServer,
}).then((r) => r.token));Çözüm sürelerinin değişken olmasını bekleyin. Friendly Captcha her istek için gereken iş miktarını kendisi belirler ve çok gördüğü adresler için bu miktarı artırır; CapSkip de her v2 widget’ını gerçek bir tarayıcıda çözer. Metodun 120 saniyelik defaultTimeout yerine recaptchaTimeout süresi boyunca, yani varsayılan olarak 300 saniyeye kadar yoklama yapmasının nedeni budur. CapSkip’in de kendi saati vardır: Friendly Captcha ayarlarında bir çözüme, başarısız sayılmadan önce 120 saniyelik Row Timeout süresi tanınır. Tek bir çağrı için SDK’nın bekleme süresini değiştirmek isterseniz seçeneklerde timeout verebilirsiniz. SDK, bir thread için beklenen süre ile çözüm süresinin toplamından daha uzun dayanmalıdır ve CapSkip’in varsayılan ayarlarında bu toplam 370 saniyeyi bulabilir. Bu yüzden havuzu Max. Threads değerinde tutun ya da daha uzun bir timeout verin ve Row Timeout değerini her yükselttiğinizde timeout değerini de yeniden yükseltin; aksi halde çağrı, CapSkip hâlâ çalışırken TimeoutException ile sona erer. Yoklama aralığı da çağrı başına ayarlanabilir, ama yalnızca snake case yazımıyla, polling_interval olarak. camelCase pollingInterval constructor’a aittir ve çağrı başına seçenek olarak verildiğinde ValidationException fırlatır. Uzun bir çalışma boyunca çözümler yavaşlıyorsa olağan sebep tek bir adreste artan zorluktur; bu durumda type ve uri anahtarları olan bir proxy nesnesi verin ya da CapSkip’te bir proxy havuzu kurun.
Örnekler 127.0.0.1 kullanıyor, çünkü Node ile çözücü aynı makinede olduğunda doğru adres budur. Betiği başka herhangi bir yerde, örneğin bir VPS’te, bir konteynerde veya bir CI çalıştırıcısında çalıştırırsanız loopback o makineyi gösterir ve ilk çağrı ECONNREFUSED ile NetworkException fırlatır. CapSkip’i Server moduna alın; o zaman ağ adresinizi veya genel IP’nizi dinler, böylece bunların hepsi ona aynı API üzerinden ulaşabilir. Rota internetten geçiyorsa statik bir genel IP kullanın ve beklediğiniz adresler için bir güvenlik duvarı kuralı ekleyin. Donanım yine sizin donanımınızdır ve çözüm başına ücretlendirme yine yoktur. İstemci ortam değişkenlerini kendiliğinden okumaz; bu yüzden, aşağıdaki tam örnekte olduğu gibi, CAPSKIP_HOST değerini kendi kodunuzda okuyup istemciye verin.
Tam çalışan örnek
İşte tüm süreç tek bir dosyada: yalnızca bir sayfa URL’sinden yola çıkarak Node.js ile Friendly Captcha çözmenin en kısa eksiksiz yolu.
// npm install capskip cheerio
// solve-friendly.mjs: run with node solve-friendly.mjs
import * as cheerio from "cheerio";
import { CapSkip, CapSkipError, ValidationException } from "capskip";
const PAGE_URL = "https://example.com/signup";
const V2_FILES = ["site.min.js", "site.compat.min.js"];
const V1_FILES = ["widget.module.min.js", "widget.min.js", "widget.polyfilled.min.js"];
const jar = new Map();
function remember(res) {
for (const line of res.headers.getSetCookie()) {
const pair = line.split(";")[0];
const eq = pair.indexOf("=");
jar.set(pair.slice(0, eq).trim(), pair.slice(eq + 1).trim());
}
}
const cookieHeader = () => [...jar].map(([k, v]) => `${k}=${v}`).join("; ");
function friendlyVersion(scripts, widget) {
for (const src of scripts) {
if (src.includes("@friendlycaptcha/sdk")) return { version: "v2", script: src };
if (src.includes("friendly-challenge")) return { version: "v1", script: src };
}
for (const src of scripts.filter((s) => s.toLowerCase().includes("friendly"))) {
const file = new URL(src).pathname.split("/").pop();
if (V2_FILES.includes(file)) return { version: "v2", script: src };
if (V1_FILES.includes(file)) return { version: "v1", script: src };
}
if (widget.is("[data-api-endpoint], [data-form-field-name]")) return { version: "v2" };
if (widget.is("[data-puzzle-endpoint], [data-solution-field-name]")) return { version: "v1" };
throw new Error("v1 or v2? Read the page and set it by hand.");
}
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),
});
const page = await fetch(PAGE_URL);
remember(page);
const $ = cheerio.load(await page.text());
const widget = $(".frc-captcha").first();
if (!widget.attr("data-sitekey")) {
throw new Error("No frc-captcha widget in the HTML; it may be built by JS.");
}
const form = widget.closest("form");
const scripts = $("script[src]").not("[nomodule]")
.map((_, el) => new URL($(el).attr("src"), PAGE_URL).href).get();
const { version, script } = friendlyVersion(scripts, widget);
let result;
try {
result = await solver.friendlyCaptcha(widget.attr("data-sitekey"), PAGE_URL, {
version,
moduleScript: script,
apiServer: widget.attr("data-api-endpoint") ?? widget.attr("data-puzzle-endpoint"),
});
} catch (err) {
if (err instanceof ValidationException) throw new Error(`not sent: ${err.message}`);
if (err instanceof CapSkipError) throw new Error(`solve failed: ${err.name}: ${err.message}`);
throw err;
}
const field = widget.attr("data-form-field-name")
?? widget.attr("data-solution-field-name")
?? (version === "v2" ? "frc-captcha-response" : "frc-captcha-solution");
// Post wherever the form's action points, with its other fields.
const body = new URLSearchParams(form.serializeArray().map((f) => [f.name, f.value]));
body.set("email", "YOUR_EMAIL");
body.set(field, result.token);
const res = await fetch(new URL(form.attr("action") || PAGE_URL, PAGE_URL), {
method: "POST",
// Browsers send the page as Referer; some servers refuse a post without it.
headers: { cookie: cookieHeader(), referer: PAGE_URL },
body,
});
console.log(res.status, version, field);Sürüm bir kez belirlenir ve iki kez kullanılır: çözüm için ve alan adı için; böylece ikisi asla birbiriyle çelişemez. cheerio hiç widget bulamazsa sayfa genellikle onu JavaScript ile oluşturuyordur ve sitekey’i render edilmiş sayfadan ya da onu oluşturan script’ten almanız gerekir. Ham endpoint’in kabul ettiği tüm parametreler şurada: Friendly Captcha API referansı.
Sık görülen hatalar ve anlamları
| Gördüğünüz | Neden | Düzeltme |
|---|---|---|
| CapSkip’in döndürdüğü bir token ile 403 ya da bir CSRF hatası | Gönderim, sayfanın çerezleri, gizli alanları ya da bir Referer olmadan yapıldı | 1. adımdaki cookie başlığını ve bir Referer gönderin, gövdeyi de serializeArray ile oluşturun |
| Site, başka hiçbir hata vermeden token’ı reddediyor | Yanlış sürüm çözüldü, çoğu zaman varsayılan olarak v1 | Sürüme 2. adımdaki gibi kodda karar verin ve onu iletin |
| Widget’ında data-api-endpoint (v2) veya data-puzzle-endpoint (v1) olan bir sitede token reddediliyor | Token global endpoint’ten geldi, site ise EU endpoint’ini kullanıyor | Özniteliğin değerini apiServer olarak verin |
| Widget’ı kendisi barındıran bir sitede v2 çözümü başarısız oluyor | moduleScript göreli bir yoldu, bu yüzden widget hiç yüklenmedi | src değerini new URL ile sayfa URL’sine göre tam adrese çevirin |
| pollingInterval adını anan bir ValidationException | Çağrı başına seçeneğin yazımı polling_interval şeklindedir | Çağrı başına snake case kullanın ya da pollingInterval değerini constructor’da ayarlayın |
| await ya da import ile ilgili SyntaxError | Dosya CommonJS olarak çalışıyor | Dosyaya .mjs uzantısı verin ya da paketin type alanını module olarak ayarlayın |
| TypeError: getSetCookie is not a function | Node.js sürümü 18.15 veya 19.7’den eski | Node.js 22 veya üzerine yükseltin |
| Her seferinde birkaç saniye içinde ERROR_CAPTCHA_UNSOLVABLE diyen bir ApiException | Friendly Captcha sitekey’i ya da sayfanın origin’ini reddediyor veya hesapta v2 ya da EU endpoint’i etkin değil | Sitekey’i, sayfa URL’sini ve apiServer değerini kontrol edin; yeniden denemek işe yaramaz |
| İki dakika ya da daha uzun süre sonra ERROR_CAPTCHA_UNSOLVABLE diyen bir ApiException | Bir çözüm CapSkip’in 120 saniyelik Row Timeout süresini aştı ya da boş bir thread için 250 saniyelik Wait Timeout süresinden fazla bekledi | Havuzu Max. Threads değerinde tutun, proxy ekleyin ya da Friendly Captcha ayarlarında Row Timeout değerini yükseltin |
| 300 saniye sonra TimeoutException | Bir görevin boş bir thread için beklemesi ve ardından çözülmesi, SDK’nın yoklama süresinden uzun sürdü | Havuzu Max. Threads değerinde tutun ya da daha uzun bir timeout verin |
| ECONNREFUSED ile NetworkException | CapSkip çalışmıyor ya da host ve port yanlış | CapSkip’i başlatın, ardından Local modunda mı yoksa Server modunda mı olması gerektiğini kontrol edin |
FAQ
Node.js ile Friendly Captcha çözmek için Puppeteer veya Playwright gerekir mi?
Hayır. Betiğinizin tek ihtiyacı HTML’dir, onu da fetch alır. Tarayıcı gerektiren iş CapSkip’in içinde gerçekleşir; CapSkip v2 widget’larını kendi tarayıcısında, v1 bulmacalarını ise doğrudan çözer. Betiğiniz başka nedenlerle zaten bir tarayıcı yönetiyorsa aynı çağrı çalışır: sitekey’i ve script adresini çekilen HTML yerine canlı sayfadan okuyun.
TypeScript’te çalışır mı?
Evet. capskip paketi kendi tür tanımlarıyla gelir ve seçenekler nesnesi hem burada kullanılan camelCase adlarla hem de snake_case API adlarıyla tiplenmiştir. Tek bir pürüz var: ortak sonuç türü token alanını isteğe bağlı olarak tanımlar ve onu hâlâ bir ALTCHA alanı olarak açıklar, çünkü tek bir sonuç yapısı her metodu kapsar. friendlyCaptcha bu alanı her zaman doldurur, dolayısıyla result.token üzerinde bir non-null assertion kullanmak güvenlidir. cheerio’nun attr metodu da string ya da undefined döndürür; bu yüzden strict modda sitekey’i ve script src değerini de aynı şekilde assert edin.
Bir VPS’teki Node uygulaması, Windows bilgisayarımdaki çözücüyü kullanabilir mi?
Evet. Bağlantı ayarlarından CapSkip’i Server moduna alın; böylece loopback yerine bir ağ adresini dinler. Uygulamanın çalıştığı yerde CAPSKIP_HOST değişkenini ayarlayın ve tam örnekte olduğu gibi istemciye verin. VPS, konteyner ya da barındırılan bir çalıştırıcı fark etmez: hepsi aynı HTTP API üzerinden bağlanır. Rota internetten geçiyorsa bir güvenlik duvarı kuralıyla birlikte statik bir genel IP kullanın. Çözücü sizin sahip olduğunuz donanımda kalır, dolayısıyla daha fazla çözüm çalıştırmak ödediğiniz tutarı asla değiştirmez.
Bunun Python rehberinden farkı nedir?
Endpoint, seçenekler ve sonuç her CapSkip SDK’sında aynıdır; bunların etrafındaki kod ise aynı değildir. Python’daki requests.Session çerezleri sizin yerinize saklar, Node’daki fetch ise 1. adımdaki küçük cookie jar’a ihtiyaç duyar. Python’daki AsyncCapSkip ayrı bir asenkron istemcidir; Node’da ise her metot zaten asenkrondur, dolayısıyla eklemeniz gereken tek şey aynı anda kaç çağrının çalışacağına dair bir sınırdır. Bu iş akışının Python sürümü şurada: Python Friendly Captcha rehberi.
Kısa özet
Node.js ile Friendly Captcha çözmek için sayfayı çekin ve çerezlerini getSetCookie ile saklayın, ardından frc-captcha öğesini ve script etiketlerini cheerio ile okuyun, her src değerini tam bir adrese çevirin. v1 mi v2 mi olduğuna paket ya da dosya adından veya widget’ın kendi özniteliklerinden karar verin; hiçbiri bir şey söylemiyorsa hata fırlatın. friendlyCaptcha metodunu sitekey, sayfa URL’si, bu sürüm ve script adresiyle çağırın; EU siteleri için apiServer da ekleyin. Token’ı bir kez, gövdede, formun kendi alanlarının yanında ve sürümün belirttiği alanda gönderin.
- Bu türün nasıl çalıştığı ve çözücünün neleri kapsadığı: Friendly Captcha çözücü sayfası.
- Node paketinin çözdüğü diğer tüm CAPTCHA türleri: Node.js CAPTCHA çözücü sayfası.
Friendly Captcha zorluğun bedelini para olarak değil CPU zamanı olarak tahsil eder; bu yüzden yoğun bir gün size kendi makinenizdeki çözüm süresinden başka hiçbir şeye mal olmaz. Bir yerel captcha çözücü çalıştırdığınızda tek sınır o makine ve ona verdiğiniz thread’ler olur.
