Troubleshooting

reCAPTCHA Token Sona Erme Tarihi: Zamanlama Pencereleri ve Yarış Koşulları

timeout-or-duplicate hatası, otomasyon iş akışlarında en yaygın reCAPTCHA hatasıdır. Bu, jetonunuzun gönderilmeden önce süresinin dolduğu veya iki kez kullanıldığı anlamına gelir. ReCAPTCHA belirteçlerinin yalnızca 120 saniye sürdüğü ve API çözücülerin bunları oluşturmasının 15-45 saniye sürdüğü göz önüne alındığında, zamanlama yönetimi kritik öneme sahiptir. Bu kılavuz, kesin son kullanma mekanizmalarını, genel yarış koşullarını ve pratik zamanlama stratejilerini kapsar.


120 saniye kuralı

Her reCAPTCHA jetonunun süresi, oluşturulduktan tam 120 saniye sonra sona erer. Bu, tüm sürümler için geçerlidir:

Token generated (solve complete)
    ├─── 0s:   Token is valid ✓
    ├─── 60s:  Token is valid ✓
    ├─── 110s: Token is valid ✓  (but cutting it close)
    ├─── 119s: Token is valid ✓  (dangerous territory)
    └─── 120s: Token EXPIRED ✗  (timeout-or-duplicate)

Zamanlayıcının başladığı yer

Senaryo Zamanlayıcı ne zaman başlar...
reCAPTCHA v2 onay kutusu Kullanıcı onay kutusunu işaretler (sorun çözüldü)
reCAPTCHA v2 görüntü ızgarası Kullanıcı son resim seçim turunu tamamlar
reCAPTCHA v2 görünmez execute() jetonla geri arama başlatılıyor
reCAPTCHA v3 execute() Promise token ile çözümleniyor
API çözücü (CaptchaAI) Çözücü jetonu oluşturur (aldığınızda DEĞİL)

Çözücü zamanlama boşluğu

Bir API çözücü kullanıldığında, çözücünün belirteci oluşturması ile kodunuzun onu alması arasında bir gecikme olur:

Solver generates token (timer starts)
    ↓ ~1-5 seconds (network + polling interval)
Your code receives token via res.php poll
    ↓ You now have ~115-119 seconds remaining
Your code processes and submits token
    ↓ ~1-10 seconds (depends on your workflow)
Target website validates token with Google
    ↓ ~1-2 seconds (Google API response time)
Total remaining after validation: ~105-117 seconds (comfortable)

Uygulamada, 120 saniyelik pencere, kodunuzun jetonu aldıktan hemen sonra gönderilmesi için yeterli süre sağlar. Sorunlar şu durumlarda ortaya çıkar:

  • Kodunuzda, jetonun alınmasıyla gönderilmesi arasında ek işlem adımları var
  • Gönderimden önce birden fazla formun doldurulması gerekiyor
  • Hedef web sitesinin yanıt süresi yavaştır
  • Jetonları sıraya koyar ve daha sonra gönderirsiniz

Ortak yarış koşulları

Yarış koşulu 1: Paralel çözüm + sıralı gönderme

# WRONG: Solving multiple CAPTCHAs in parallel, then submitting sequentially
tokens = []
for url in urls:
    task_id = solve_captcha(url)  # All submitted at t=0
    tokens.append(task_id)

# All tokens arrive around t=30
solved_tokens = [poll_result(tid) for tid in tokens]

# Sequential submission: first token at t=32, last at t=120+
for i, (url, token) in enumerate(zip(urls, solved_tokens)):
    submit_form(url, token)  # Later tokens may be expired!
    time.sleep(10)  # Each wait adds pressure

Düzeltme: Bir sonrakine başlamadan önce her CAPTCHA'yı çözün ve gönderin:

# CORRECT: Solve and submit one at a time
for url in urls:
    token = solve_and_wait(url)  # Token received at t=30
    submit_form(url, token)      # Submitted at t=31 (89 seconds remaining)

Yarış koşulu 2: Jeton ön alımı

# WRONG: Pre-fetching tokens before knowing when they'll be used
token = solve_captcha()  # Token received at t=0

# ... user fills out form (30-120+ seconds) ...
# ... validation checks ...
# ... other processing ...

submit_form(token)  # Token may be expired!

Düzeltme: Gönderimden önceki son adım olarak CAPTCHA'yı çözün:

# CORRECT: Late-bind the CAPTCHA solve
prepare_form_data()   # Do everything that doesn't need the token
validate_inputs()     # Run validation before spending a token

# Now solve and submit immediately
token = solve_captcha()  # Token received at t=0
submit_form(token)       # Submitted at t=1 (119 seconds remaining)

Yarış koşulu 3: Çok adımlı form gönderimi

# PROBLEMATIC: Multi-step form where CAPTCHA is on step 1 but submit is step 3
token = solve_captcha()       # t=0: Token received

fill_step_1(token)            # t=5: Step 1 submitted
response = fill_step_2()      # t=15: Step 2 completed
# ... step 2 has additional verification ...
wait_for_verification()       # t=60: Verification complete
fill_step_3_and_submit()      # t=65: Final submission (55 seconds remaining - OK)
# BUT if step 2 takes longer than expected...

Düzeltme: Belirteç yaşını ölçün ve gerekirse yeniden çözün:

token_received_at = time.time()
token = solve_captcha()
token_received_at = time.time()

# ... multi-step process ...

# Before final submission, check token age
token_age = time.time() - token_received_at
if token_age > 100:  # 20-second safety margin
    print(f"Token is {token_age:.0f}s old — requesting fresh token")
    token = solve_captcha()
    token_received_at = time.time()

submit_final(token)

Token zamanlama yöneticisi

Belirteç yaşam sürelerini yönetmek için üretime hazır bir sınıf:

import time
import requests

class TokenTimingManager:
    """Manage reCAPTCHA token timing to prevent expiration errors."""

    API_KEY = "YOUR_API_KEY"
    TOKEN_LIFETIME = 120
    SAFETY_MARGIN = 15  # seconds before expiry to consider "stale"

    def __init__(self, site_key, page_url, version="v2"):
        self.site_key = site_key
        self.page_url = page_url
        self.version = version
        self.current_token = None
        self.token_timestamp = None

    def _solve(self):
        """Request and poll for a new token."""
        params = {
            "key": self.API_KEY,
            "method": "userrecaptcha",
            "googlekey": self.site_key,
            "pageurl": self.page_url,
            "json": 1,
        }
        if self.version == "v3":
            params.update({"version": "v3", "action": "submit"})

        submit = requests.post("https://ocr.captchaai.com/in.php", data=params).json()
        task_id = submit["request"]

        for _ in range(60):
            time.sleep(5)
            result = requests.get("https://ocr.captchaai.com/res.php", params={
                "key": self.API_KEY,
                "action": "get",
                "id": task_id,
                "json": 1,
            }).json()

            if result.get("status") == 1:
                self.current_token = result["request"]
                self.token_timestamp = time.time()
                return self.current_token

        raise TimeoutError("Token solve timeout")

    @property
    def token_age(self):
        """Seconds since current token was received."""
        if self.token_timestamp is None:
            return float("inf")
        return time.time() - self.token_timestamp

    @property
    def token_remaining(self):
        """Seconds remaining before token expires."""
        return max(0, self.TOKEN_LIFETIME - self.token_age)

    @property
    def is_fresh(self):
        """Whether the token is fresh enough to use."""
        return self.token_remaining > self.SAFETY_MARGIN

    def get_token(self):
        """Get a valid token, solving if current is stale or missing."""
        if self.current_token and self.is_fresh:
            return self.current_token

        return self._solve()

    def use_token(self):
        """Get and consume a token (cannot be reused)."""
        token = self.get_token()
        # Mark as consumed
        self.current_token = None
        self.token_timestamp = None
        return token

# Usage
manager = TokenTimingManager(
    site_key="6LcR_RsTAAAAAN_r0GEkGBfq3L7KmU5JbPHJtwNp",
    page_url="https://staging.example.com/qa-login",
)

# Get a fresh token right before submission
token = manager.use_token()
print(f"Token remaining: {manager.TOKEN_LIFETIME}s (fresh solve)")

# Submit form with token...

Zaman aşımı veya yinelenen hatayı işleme

timeout-or-duplicate aldığınızda nedenini teşhis edin:

def handle_recaptcha_error(error_codes, token_age_seconds):
    """Diagnose and handle reCAPTCHA validation errors."""

    if "timeout-or-duplicate" in error_codes:
        if token_age_seconds > 120:
            return {
                "cause": "Token expired (age: {:.0f}s > 120s)".format(token_age_seconds),
                "fix": "Reduce time between receiving and submitting token",
                "action": "re-solve",
            }
        elif token_age_seconds < 5:
            return {
                "cause": "Token likely reused (duplicate submission)",
                "fix": "Ensure each form submission gets a unique token",
                "action": "re-solve",
            }
        else:
            return {
                "cause": "Token may have been reused or server-side timing issue",
                "fix": "Check for double-submit in form handler",
                "action": "re-solve",
            }

    if "invalid-input-response" in error_codes:
        return {
            "cause": "Token is malformed or corrupted",
            "fix": "Check token transmission (URL encoding, field name)",
            "action": "re-solve",
        }

    return {"cause": "Unknown", "action": "investigate"}

Zamanlamayla ilgili en iyi uygulamalar

Alıştırma Tavsiye
Gönderim-gönderim boşluğunu çözme 90 saniyenin altında tutun (30 saniyelik kenar boşluğu)
Anket aralığı res.php kontrolleri arasında 5 saniye
Ön QA testi Yalnızca gönderimin 60 saniye içinde gerçekleşeceğini biliyorsanız ön QA testi yapın
Süre sona erdiğinde yeniden dene timeout-or-duplicate'de her zaman yeni bir jeton isteyin
Jeton kuyruğu Belirteçleri asla sıraya koymayın; her birinin süresi bağımsız olarak sona erer
Paralel işlemler Her şeyi sonra kullan değil, görev başına çöz
İzleme Gönderim sırasında belirteç yaşını takip edin

Sık sorulan sorular

120 saniyelik jeton penceresini uzatabilir miyim?

Hayır. Geçerlilik süresi Google tarafından sunucu tarafında uygulanır ve hiçbir şekilde uzatılamaz. 120 saniye zor bir sınırdır.

Oylama gecikmesi kullanılabilir belirteç süremi azaltır mı?

Evet, biraz. Her 5 saniyede bir yoklama yaparsanız jetonu oluşturulduktan sonraki 5 saniyeye kadar alabilirsiniz. Pratikte bu, 120 yerine ~115 saniyeniz olduğu anlamına gelir. Bu genellikle bir sorun değildir.

Hazır olmaları için jetonları önceden çözmeli miyim?

Yalnızca jetonun 60-90 saniye içinde gönderileceğini garanti edebiliyorsanız. Ön QA testileme, ekstra 15-45 saniyelik çözüm süresinin önemli olduğu, gecikmeye duyarlı iş akışları (ör. rekabetçi satın alma) için kullanışlıdır. Çoğu iş akışı için isteğe bağlı çözüm daha güvenlidir.

Google neden süresi dolmuş ve yinelenen jetonlar için aynı hatayı kullanıyor?

Google, otomasyon komut dosyalarının hangi durumun oluştuğunu tespit etmek için hata kodunu kullanmasını önlemek amacıyla ayrımı kasıtlı olarak gizler. Her iki durumun da çözümü aynı: yeni bir jeton talep edin.


Özet

reCAPTCHA belirteçlerinin süresi tam olarak 120 saniye sonra dolar ve yalnızca bir kez kullanılabilir. En yaygın otomasyon hatası - timeout-or-duplicate - tokenlerin çok geç gönderilmesinden veya yeniden kullanılmasından kaynaklanır. KullanırkenCaptchaAI, belirteçleri gönderimden hemen önce çözün, belirtecin yaşını takip edin ve belirteçleri hiçbir zaman kuyruğa almayın veya yeniden kullanmayın. Üretim iş akışlarında süre sonu ve yeniden çözümleme işlemlerini otomatik olarak gerçekleştirmek için yukarıdaki zamanlama yöneticisi modelini kullanın.

İlgili Makaleler

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