Tutorials

Yeniden Kullanım için CAPTCHA Jetonlarını Önbelleğe Alma

CAPTCHA'yı çözmek zaman ve para gerektirir. Aynı belirteç geçerlilik süresi içinde yeniden kullanılabiliyorsa önbelleğe alma, gereksiz API çağrılarını ortadan kaldırır. Bu kılavuz, hangi belirteçlerin önbelleğe alınabileceğini, ne kadar süre dayanabileceğini ve önbelleğe almanın güvenli bir şekilde nasıl uygulanacağını kapsar.


CAPTCHA türüne göre belirteç yaşam süreleri

CAPTCHA türü Jeton ömrü Önbelleğe alınabilir mi? Notlar
reCAPTCHA v2 ~120 saniye Sınırlı Çoğu sitede tek seferlik kullanım
reCAPTCHA v3 ~120 saniye Sınırlı Puan isteğe göre değişebilir
reCAPTCHA Kurumsal ~120 saniye Hayır Aksiyona özel, tek kullanımlık
Cloudflare Turnstile ~300 saniye Evet, pencere içinde Jeton, süresi dolana kadar yeniden kullanılabilir
Cloudflare doğrulama akışı qa_session_cookie ~15–30 dk. Evet Çerez oturum için yeniden kullanılabilir
Görüntü OCR'si N/A (metin sonucu) Evet Sonuç hiçbir zaman sona ermez
GeeTest v3 ~60 saniye Hayır Mücadeleye özel

Önemli bilgi: Cloudflare doğrulama akışı (qa_session_cookie) ve Görüntü OCR en önbelleğe alınabilir olanlardır. reCAPTCHA belirteçlerinin kısa pencereleri vardır ve genellikle tek kullanımlıktır.


Önbelleğe alma çalıştığında

Önbelleğe alma şu durumlarda etkilidir:

  1. Aynı sayfa, birden fazla istek - örneğin, aynı formun birden çok kez gönderilmesi
  2. Cloudflare qa_session_cookie – tek bir çözüm tüm oturumun kilidini açar
  3. Toplu OCR – aynı resim tekrar tekrar görünüyor (ör. statik CAPTCHA)
  4. Ön QA testileme – jetonları ihtiyaç duyulmadan önce çözün

Önbelleğe alma aşağıdaki durumlarda çalışmaz:

  • Site her jetonu yalnızca bir kez doğrular
  • Belirteç belirli bir eyleme veya oturuma bağlıdır
  • Belirtecin süresi zaten doldu

Python – bellek içi önbellek

import time
import hashlib
from typing import Optional
import requests

SUBMIT_URL = "https://ocr.captchaai.com/in.php"
RESULT_URL = "https://ocr.captchaai.com/res.php"


class TokenCache:
    def __init__(self):
        self.cache = {}

    def _key(self, method: str, params: dict) -> str:
        # Cache key from method + stable params
        stable = {k: v for k, v in sorted(params.items())
                  if k not in ("key", "json")}
        raw = f"{method}:{stable}"
        return hashlib.sha256(raw.encode()).hexdigest()[:16]

    def get(self, method: str, params: dict) -> Optional[str]:
        key = self._key(method, params)
        entry = self.cache.get(key)
        if entry and entry["expires_at"] > time.time():
            print(f"Cache HIT: {key}")
            return entry["token"]
        if entry:
            del self.cache[key]
        return None

    def set(self, method: str, params: dict, token: str, ttl: int):
        key = self._key(method, params)
        self.cache[key] = {
            "token": token,
            "expires_at": time.time() + ttl,
        }
        print(f"Cached: {key} (TTL: {ttl}s)")

    def invalidate(self, method: str, params: dict):
        key = self._key(method, params)
        self.cache.pop(key, None)

    def cleanup(self):
        now = time.time()
        expired = [k for k, v in self.cache.items() if v["expires_at"] <= now]
        for k in expired:
            del self.cache[k]


# TTL per CAPTCHA type
TTL_MAP = {
    "userrecaptcha": 100,       # 120s lifetime, 20s safety margin
    "turnstile": 240,           # 300s lifetime, 60s margin
    "cloudflare_challenge": 900,# 15min lifetime, 5min margin
    "base64": 86400,            # OCR result never expires — cache 24h
}


class CachedSolver:
    def __init__(self, api_key: str):
        self.api_key = api_key
        self.cache = TokenCache()

    def solve(self, method: str, params: dict) -> str:
        # Check cache first
        cached = self.cache.get(method, params)
        if cached:
            return cached

        # Solve via API
        token = self._api_solve(method, params)
        ttl = TTL_MAP.get(method, 60)
        self.cache.set(method, params, token, ttl)
        return token

    def _api_solve(self, method: str, params: dict) -> str:
        data = {
            "key": self.api_key,
            "method": method,
            "json": 1,
            **params
        }

        resp = requests.post(SUBMIT_URL, data=data, timeout=15)
        result = resp.json()

        if result.get("status") != 1:
            raise Exception(result.get("error_text", result.get("request")))

        task_id = result["request"]
        return self._poll(task_id)

    def _poll(self, task_id: str, max_wait: int = 120) -> str:
        elapsed = 0
        while elapsed < max_wait:
            time.sleep(5)
            elapsed += 5

            resp = requests.get(RESULT_URL, params={
                "key": self.api_key,
                "action": "get",
                "id": task_id,
                "json": 1
            }, timeout=10)
            result = resp.json()

            if result.get("status") == 1:
                return result["request"]
            if result.get("request") == "CAPCHA_NOT_READY":
                continue

            raise Exception(result.get("error_text", result.get("request")))

        raise Exception(f"Timeout: {task_id}")


# Usage
solver = CachedSolver(api_key="YOUR_API_KEY")

# First call — hits API
token1 = solver.solve("turnstile", {
    "sitekey": "0x4AAAA-SITEKEY",
    "pageurl": "https://example.com"
})
print(f"Token 1: {token1[:40]}...")

# Second call within TTL — cache hit, no API call
token2 = solver.solve("turnstile", {
    "sitekey": "0x4AAAA-SITEKEY",
    "pageurl": "https://example.com"
})
print(f"Token 2: {token2[:40]}...")
print(f"Same token: {token1 == token2}")  # True

Node.js – bellek içi önbellek

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

const SUBMIT_URL = "https://ocr.captchaai.com/in.php";
const RESULT_URL = "https://ocr.captchaai.com/res.php";

const TTL_MAP = {
  userrecaptcha: 100,
  turnstile: 240,
  cloudflare_challenge: 900,
  base64: 86400,
};

class TokenCache {
  constructor() {
    this.cache = new Map();
  }

  _key(method, params) {
    const stable = Object.entries(params)
      .filter(([k]) => k !== "key" && k !== "json")
      .sort(([a], [b]) => a.localeCompare(b))
      .map(([k, v]) => `${k}=${v}`)
      .join("&");
    return crypto.createHash("sha256").update(`${method}:${stable}`).digest("hex").slice(0, 16);
  }

  get(method, params) {
    const key = this._key(method, params);
    const entry = this.cache.get(key);
    if (entry && entry.expiresAt > Date.now()) {
      console.log(`Cache HIT: ${key}`);
      return entry.token;
    }
    if (entry) this.cache.delete(key);
    return null;
  }

  set(method, params, token, ttlMs) {
    const key = this._key(method, params);
    this.cache.set(key, { token, expiresAt: Date.now() + ttlMs });
    console.log(`Cached: ${key} (TTL: ${ttlMs / 1000}s)`);
  }
}

class CachedSolver {
  constructor(apiKey) {
    this.apiKey = apiKey;
    this.cache = new TokenCache();
  }

  async solve(method, params) {
    const cached = this.cache.get(method, params);
    if (cached) return cached;

    const token = await this._apiSolve(method, params);
    const ttl = (TTL_MAP[method] || 60) * 1000;
    this.cache.set(method, params, token, ttl);
    return token;
  }

  async _apiSolve(method, params) {
    const resp = await axios.post(SUBMIT_URL, null, {
      params: { key: this.apiKey, method, json: 1, ...params },
      timeout: 15000,
    });

    if (resp.data.status !== 1) {
      throw new Error(resp.data.error_text || resp.data.request);
    }

    return this._poll(resp.data.request);
  }

  async _poll(taskId, maxWait = 120000) {
    let elapsed = 0;
    while (elapsed < maxWait) {
      await new Promise((r) => setTimeout(r, 5000));
      elapsed += 5000;

      const resp = await axios.get(RESULT_URL, {
        params: { key: this.apiKey, action: "get", id: taskId, json: 1 },
        timeout: 10000,
      });

      if (resp.data.status === 1) return resp.data.request;
      if (resp.data.request === "CAPCHA_NOT_READY") continue;

      throw new Error(resp.data.error_text || resp.data.request);
    }
    throw new Error("Timeout");
  }
}

// Usage
(async () => {
  const solver = new CachedSolver("YOUR_API_KEY");

  const token1 = await solver.solve("turnstile", {
    sitekey: "0x4AAAA-SITEKEY",
    pageurl: "https://example.com",
  });
  console.log(`Token 1: ${token1.slice(0, 40)}...`);

  const token2 = await solver.solve("turnstile", {
    sitekey: "0x4AAAA-SITEKEY",
    pageurl: "https://example.com",
  });
  console.log(`Token 2: ${token2.slice(0, 40)}...`);
  console.log(`Same token: ${token1 === token2}`);
})();

Dağıtılmış sistemler için Redis önbelleği

Çok çalışanlı kurulumlarda bellek içi önbellek yerine Redis'i kullanın:

import redis
import json

r = redis.Redis(host="localhost", port=6379, db=0)

def cache_token(method, params, token, ttl):
    key = f"captcha:{method}:{hash(frozenset(params.items()))}"
    r.setex(key, ttl, token)

def get_cached_token(method, params):
    key = f"captcha:{method}:{hash(frozenset(params.items()))}"
    return r.get(key)

Redis, TTL'nin sona ermesini otomatik olarak yönetir ve birden fazla işlemde çalışır.


Ön QA testileme modeli

Belirteçleri ihtiyaç duyulmadan önce çözün. Hazır jetonlardan oluşan bir arabellek tutun:

from collections import deque
from threading import Thread

token_buffer = deque(maxlen=5)

def pre_solve_worker(solver, method, params):
    while True:
        if len(token_buffer) < 3:
            try:
                token = solver._api_solve(method, params)
                ttl = TTL_MAP.get(method, 60)
                token_buffer.append({
                    "token": token,
                    "expires_at": time.time() + ttl
                })
            except Exception as e:
                print(f"Ön QA testi failed: {e}")
        time.sleep(2)

# Start ön QA testir in background
thread = Thread(
    target=pre_solve_worker,
    args=(solver, "turnstile", {"sitekey": "0x4AAAA-KEY", "pageurl": "https://example.com"}),
    daemon=True
)
thread.start()

# Consume ön QA testid tokens
def get_presolved():
    while token_buffer:
        entry = token_buffer.popleft()
        if entry["expires_at"] > time.time():
            return entry["token"]
    return None

Önbellek geçersiz kılma kuralları

Tetikleyici Eylem
Belirteç hedef site tarafından reddedildi Geçersiz kıl ve yeniden çöz
TTL'nin süresi doldu Önbellekten otomatik olarak kaldırıldı
Proxy değiştirildi Cloudflare belirteçlerini geçersiz kılma (IP'ye bağlı)
Site CAPTCHA yapılandırmasını güncelledi Bu site için önbelleğe alınmış tüm jetonları temizle

Sorun giderme

Sorun Sebep Düzeltme
Önbelleğe alınan jeton reddedildi Jetonun süresi dolmuş veya tek kullanımlık Bu tür için TTL'yi azaltın veya önbelleğe almayı devre dışı bırakın
Önbellek asla isabet etmez Paramlar aramalar arasında farklılık gösterir Karma işleminden önce parametreleri normalleştirin
Redis'teki eski belirteçler TTL çok uzun Güvenlik marjıyla TTL'yi düşürün
Bellek büyümesi Temizleme yok cleanup()'yi periyodik olarak arayın veya Redis'i TTL ile kullanın

SSS

reCAPTCHA v2 belirteçlerini önbelleğe alabilir miyim?

Bazen. Birçok site jetonu yalnızca bir kez kabul eder. Aynı jetonu iki kez göndererek test edin; ikinci gönderim başarılı olursa, önbelleğe alma o site için işe yarar.

Önbelleğe alma ne kadar tasarruf sağlayabilir?

Cloudflare doğrulama akışı için tek bir çözüm, 15-30 dakikalık bir oturumun tamamını kapsayabilir. Bu, aynı alanda yüksek frekanslı kazıma maliyetlerini %90'ın üzerinde azaltabilir.

Ön QA testi buna değer mi?

Evet, boru hattınızda öngörülebilir bir talep varsa. Ön QA testileme, talebin düşmesi durumunda potansiyel token israfı pahasına bekleme süresini ortadan kaldırır.


CaptchaAI ile CAPTCHA maliyetlerini optimize edin

Belirteçleri önbelleğe almaya şuradan başlayın:captchaai.com.


İlgili kılavuzlar

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

İlgili Yazılar

Use Cases Yüksek talep gören e-commerce checkout akışları için CAPTCHA testi
Kendi staging ortamınızda e-commerce checkout akışlarındaki CAPTCHA entegrasyonlarını sahte stok, test ödeme tokenları ve Captcha AI ile doğrulamak için QA kıla...

Kendi staging ortamınızda e-commerce checkout akışlarındaki CAPTCHA entegrasyonlarını sahte stok, test ödeme t...

May 05, 2026
Use Cases Ticketing kuyruğu ve checkout akışları için CAPTCHA testi
Kendi staging ticketing platformunuzda kuyruk ve checkout CAPTCHA akışlarını sahte etkinlikler, test koltukları, simüle ödeme ve Captcha AI ile doğrulamak için...

Kendi staging ticketing platformunuzda kuyruk ve checkout CAPTCHA akışlarını sahte etkinlikler, test koltuklar...

May 09, 2026
Integrations CaptchaAI ile QA için tarayıcı profili izolasyonu
Staging QA testlerini temiz ve tekrarlanabilir tutmak için çerezleri, storage verilerini, test hesaplarını ve CAPTCHA yapılandırmalarını tarayıcı profiline göre...

Staging QA testlerini temiz ve tekrarlanabilir tutmak için çerezleri, storage verilerini, test hesaplarını ve...

Apr 29, 2026