Use Cases

Node.js ve CaptchaAI ile Puppeteer CAPTCHA Çözme

Puppeteer ile veri toplarken sayfada bir CAPTCHA belirdiğinde akış durur. Çözüm, doğrulamayı tarayıcının içinde çözmeye çalışmak değil: sitekey'i DOM'dan çıkarıp CaptchaAI API'sine gönderir, dönen token'ı forma enjekte edip gönderirsiniz. Bu rehber, reCAPTCHA v2 ve Cloudflare Turnstile için bu akışı Node.js'te sıfırdan kurar — çözücü modülü, Puppeteer yapılandırması, token enjeksiyonu ve callback tetikleme dahil.

Neye ihtiyacınız var

Gereksinim Ayrıntılar
Node.js 16+ npm ile
Puppeteer npm install puppeteer
axios npm install axios
CaptchaAI API anahtarı captchaai.com hesabınızdan

Token akışı nasıl çalışır?

CaptchaAI CAPTCHA'yı sunucu tarafında çözer; Puppeteer yalnızca parametreleri taşır. Akış dört adımdan oluşur:

  1. Puppeteer, CAPTCHA'nın bulunduğu sayfaya gider.
  2. Betiğiniz CAPTCHA sitekey'ini DOM'dan çıkarır.
  3. CaptchaAI doğrulamayı sunucu tarafında çözer.
  4. Betiğiniz token'ı enjekte eder ve formu gönderir.

Çözümün sunucu tarafında gerçekleşmesi, testi headless çalıştırabilmeniz anlamına gelir — arayüzü açık tutmanız gerekmez. Bu ayrım önemli: tarayıcının içinde CAPTCHA çözmeye çalışmak yerine, Puppeteer'ın tek görevi sitekey'i okumak ve dönen token'ı doğru alana yazmaktır. Böylece otomasyon kodunuz sade kalır ve her CAPTCHA türü için ayrı bir çözüm mantığı yazmanız gerekmez.

Adım 1: CaptchaAI çözücü modülünü oluşturun

Önce API çağrılarını tek bir dosyada toplayın. Aşağıdaki modül görevi in.php uç noktasına gönderir, ardından token hazır olana kadar res.php'yi 5 saniyede bir sorgular. reCAPTCHA v2 için userrecaptcha, Turnstile için turnstile metodu kullanılır.

// solver.js
const axios = require("axios");

const API_KEY = "YOUR_API_KEY";
const POLL_INTERVAL = 5000;
const MAX_ATTEMPTS = 60;

async function solveRecaptchaV2(siteKey, pageUrl) {
  // Submit task
  const submitResp = await axios.get("https://ocr.captchaai.com/in.php", {
    params: {
      key: API_KEY,
      method: "userrecaptcha",
      googlekey: siteKey,
      pageurl: pageUrl,
    },
  });

  if (!submitResp.data.startsWith("OK|")) {
    throw new Error(`Submit failed: ${submitResp.data}`);
  }

  const taskId = submitResp.data.split("|")[1];
  console.log(`Task submitted: ${taskId}`);

  // Poll for result
  for (let i = 0; i < MAX_ATTEMPTS; i++) {
    await new Promise((r) => setTimeout(r, POLL_INTERVAL));

    const result = await axios.get("https://ocr.captchaai.com/res.php", {
      params: { key: API_KEY, action: "get", id: taskId },
    });

    if (result.data === "CAPCHA_NOT_READY") continue;
    if (result.data.startsWith("OK|")) {
      return result.data.split("|")[1];
    }
    throw new Error(`Solve failed: ${result.data}`);
  }
  throw new Error("Solve timed out");
}

async function solveTurnstile(siteKey, pageUrl) {
  const submitResp = await axios.get("https://ocr.captchaai.com/in.php", {
    params: {
      key: API_KEY,
      method: "turnstile",
      sitekey: siteKey,
      pageurl: pageUrl,
    },
  });

  if (!submitResp.data.startsWith("OK|")) {
    throw new Error(`Submit failed: ${submitResp.data}`);
  }

  const taskId = submitResp.data.split("|")[1];

  for (let i = 0; i < MAX_ATTEMPTS; i++) {
    await new Promise((r) => setTimeout(r, POLL_INTERVAL));
    const result = await axios.get("https://ocr.captchaai.com/res.php", {
      params: { key: API_KEY, action: "get", id: taskId },
    });
    if (result.data === "CAPCHA_NOT_READY") continue;
    if (result.data.startsWith("OK|")) return result.data.split("|")[1];
    throw new Error(`Solve failed: ${result.data}`);
  }
  throw new Error("Solve timed out");
}

module.exports = { solveRecaptchaV2, solveTurnstile };

Adım 2: Puppeteer tarayıcısını başlatın

Standart bir yapılandırmayla tarayıcıyı açın. Burada özel bir şey yok: --no-sandbox ile başlatıyor, makul bir user agent atıyor ve sayfayı hazırlıyoruz.

const puppeteer = require("puppeteer");

async function createBrowser() {
  const browser = await puppeteer.launch({
    headless: "new",
    args: [
      "--no-sandbox",
      "--disable-setuid-sandbox",
      "--no-sandbox",
    ],
  });

  const page = await browser.newPage();
  await page.setUserAgent(
    "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
  );

  // Hide automation indicators
  await page.evaluateOnNewDocument(() => {
    Object.defineProperty(navigator, "webdriver", { get: () => false });
  });

  return { browser, page };
}

Adım 3: Sayfadaki reCAPTCHA'yı çözün

Şimdi parçaları birleştirin: sayfaya gidin, .g-recaptcha öğesinden sitekey'i okuyun, çözücüyü çağırın ve dönen token'ı g-recaptcha-response alanına yazın. Ardından formu gönderin.

const { solveRecaptchaV2 } = require("./solver");

async function scrapeWithCaptcha(url) {
  const { browser, page } = await createBrowser();

  try {
    await page.goto(url, { waitUntil: "networkidle2" });

    // Extract site key
    const siteKey = await page.$eval(
      ".g-recaptcha",
      (el) => el.getAttribute("data-sitekey")
    );
    console.log("Site key:", siteKey);

    // Solve with CaptchaAI
    const token = await solveRecaptchaV2(siteKey, url);
    console.log("Token received:", token.substring(0, 50));

    // Inject token
    await page.evaluate((token) => {
      document.getElementById("g-recaptcha-response").innerHTML = token;
      document.getElementById("g-recaptcha-response").style.display = "";
    }, token);

    // Submit the form
    await page.click('button[type="submit"]');
    await page.waitForNavigation({ waitUntil: "networkidle2" });

    // Scrape the content
    const content = await page.content();
    console.log("Page loaded successfully");
    return content;
  } finally {
    await browser.close();
  }
}

Adım 4: JavaScript callback'lerini tetikleyin

Bazı siteler form göndermek yerine token'ı bir JavaScript callback'ine iletmeyi bekler. Bu durumda token'ı enjekte etmek yetmez; reCAPTCHA'nın callback fonksiyonunu bulup çağırmanız gerekir.

// Trigger the reCAPTCHA callback
await page.evaluate((token) => {
  // Method 1: Direct callback
  if (typeof ___grecaptcha_cfg !== "undefined") {
    const clients = ___grecaptcha_cfg.clients;
    Object.keys(clients).forEach((key) => {
      const client = clients[key];
      // Find the callback function
      const findCallback = (obj) => {
        for (const prop in obj) {
          if (typeof obj[prop] === "function") {
            obj[prop](token);
            return true;
          }
          if (typeof obj[prop] === "object" && obj[prop] !== null) {
            if (findCallback(obj[prop])) return true;
          }
        }
        return false;
      };
      findCallback(client);
    });
  }
}, token);

Yerel bağlam: e-ticaret QA akışları

Türkiye'de otomasyon işlerinin büyük kısmı e-ticaret ve ödeme entegrasyonlarının etrafında döner. Tipik senaryo şudur: bir staging ortamında (staging.example.com/qa-login) giriş akışını her sürümde regresyon testinden geçirmek istersiniz, ama form reCAPTCHA ile korunduğu için otomasyon takılır. CaptchaAI token'ı sunucu tarafında ürettiği için testi headless çalıştırabilirsiniz. Fiyatlandırma USD ve thread bazlıdır — BASIC ($15/ay, 5 thread) küçük bir QA paralelliği için yeterlidir ve TL kurundaki dalgalanma aylık maliyeti değiştirmez. Not: topladığınız veriler kişisel veri içeriyorsa KVKK kapsamına girer; bu akışları yalnızca yetkili test ve veri toplama süreçlerinde kullanın.

Tam çalışan örnek

Aşağıda tek dosyada uçtan uca akış var: tarayıcıyı başlatın, sitekey'i okuyun, çözün, token'ı enjekte edin ve gönderin.

const puppeteer = require("puppeteer");
const axios = require("axios");

const API_KEY = "YOUR_API_KEY";

async function solveCaptcha(siteKey, pageUrl) {
  const submit = await axios.get("https://ocr.captchaai.com/in.php", {
    params: {
      key: API_KEY,
      method: "userrecaptcha",
      googlekey: siteKey,
      pageurl: pageUrl,
    },
  });
  const taskId = submit.data.split("|")[1];

  while (true) {
    await new Promise((r) => setTimeout(r, 5000));
    const result = await axios.get("https://ocr.captchaai.com/res.php", {
      params: { key: API_KEY, action: "get", id: taskId },
    });
    if (result.data === "CAPCHA_NOT_READY") continue;
    if (result.data.startsWith("OK|")) return result.data.split("|")[1];
    throw new Error(result.data);
  }
}

(async () => {
  const browser = await puppeteer.launch({
    headless: "new",
    args: ["--no-sandbox"],
  });
  const page = await browser.newPage();

  try {
    await page.goto("https://staging.example.com/qa-login", {
      waitUntil: "networkidle2",
    });

    // Get the site key
    const siteKey = await page.$eval(".g-recaptcha", (el) =>
      el.getAttribute("data-sitekey")
    );

    // Solve
    const token = await solveCaptcha(siteKey, page.url());

    // Inject and submit
    await page.evaluate((t) => {
      document.getElementById("g-recaptcha-response").innerHTML = t;
    }, token);

    await page.click("#submit-btn");
    await page.waitForNavigation();

    console.log("Done:", page.url());
  } finally {
    await browser.close();
  }
})();

Çözümü üretimde ölçeklendirin

Tek bir betik için yukarıdaki akış yeterlidir, ama birçok sayfayı paralel işleyen bir kazıma ya da QA hattında birkaç noktaya dikkat edin:

  • Eşzamanlılık thread'e bağlıdır. CaptchaAI planları thread bazlıdır ve aynı anda kaç CAPTCHA'nın çözülebileceğini plan belirler. BASIC ($15/ay, 5 thread) beş eşzamanlı görev demektir; daha yüksek paralellik için ADVANCE ($90/ay, 50 thread) gibi bir plana geçin. Aynı anda açtığınız Puppeteer sayfası sayısını thread sayınızla uyumlu tutun.
  • Yeniden deneme ekleyin. Ağ hataları ve nadir başarısız çözümler kaçınılmazdır. Başarısız bir görevi doğrudan tekrar denemek yerine, denemeler arasına artan bir bekleme (üstel geri çekilme / exponential backoff) koyun; bu, res.php uç noktasını gereksiz yormanızı önler.
  • Zaman aşımını yönetin. MAX_ATTEMPTS ve POLL_INTERVAL değerleri toplam bekleme süresini belirler. Bir görev bu süre içinde tamamlanmazsa token'ı beklemeyi bırakın, hatayı loglayın ve sayfayı sıradaki denemeye bırakın — takılı kalan bir sayfanın tüm kuyruğu bloke etmesine izin vermeyin.
  • Token'ı taze tutun. Token'lar kısa ömürlüdür. Görevi çözdükten sonra enjeksiyon ile form gönderimi arasına uzun işlemler koymayın; token'ı aldığınız anda kullanın.

Sık karşılaşılan sorunlar

Sorun Neden Çözüm
page.$eval başarısız oluyor CAPTCHA ilk render'dan sonra yükleniyor page.waitForSelector('.g-recaptcha') ile bekleyin
Token çalışmıyor Gönderilmeden önce süresi doldu Aldıktan hemen sonra enjekte edin
Site Puppeteer'ı tespit ediyor Standart yapılandırma eksik Varsayılan Puppeteer yapılandırmasını kullanın
Navigation timeout Gönderim sonrası sayfa yönlenmedi Sitenin form yerine AJAX kullanıp kullanmadığını kontrol edin

Sık sorulan sorular

Puppeteer'da bir CAPTCHA çözmek ne kadar sürer?

Çözüm süresi CAPTCHA türüne ve o anki yüke göre değişir; genellikle birkaç saniye içinde tamamlanır. Kod res.php uç noktasını 5 saniyede bir sorgular ve token hazır olur olmaz döner.

CaptchaAI hangi CAPTCHA türlerini destekliyor? hCaptcha çözülüyor mu?

reCAPTCHA v2/v3, Cloudflare Turnstile ve Challenge, GeeTest v3, görüntü/OCR ve grid CAPTCHA'ları desteklenir. hCaptcha ve FunCaptcha desteklenmez; GeeTest v4 çok yakında. CaptchaFox (beta), Friendly Captcha (beta) ve Lemin (beta) ise beta aşamasındadır.

Puppeteer entegrasyonu için CaptchaAI ne kadar?

Planlar thread bazlıdır ve USD ile faturalanır. BASIC ($15/ay, 5 thread) ile başlayabilir, paralel çözüm ihtiyacınız arttıkça ADVANCE ($90/ay, 50 thread) gibi üst planlara geçebilirsiniz. Solve başına ayrı ücret yoktur.

Token'ı enjekte ettim ama form yine de reddediyor, neden?

En sık neden token'ın süresinin dolmasıdır: token'ı aldıktan hemen sonra enjekte edip formu gönderin. Ayrıca doğru alanı (g-recaptcha-response) hedeflediğinizden ve sayfanın gerçekten form gönderimi kullandığından emin olun.

Cloudflare Turnstile'ı Puppeteer ile çözebilir miyim?

Evet. data-sitekey'i .cf-turnstile div'inden okuyun ve method=turnstile ile gönderin — yukarıdaki solveTurnstile fonksiyonu bu akışı gösterir.

İlgili rehberler

Bu makale için yorumlar devre dışı bırakılmıştır.