Bir denetim günlüğü, "bu CAPTCHA çözümünü kim tetikledi, hangi site içindi, ne kadar sürdü ve kaça mal oldu?" sorularına dakikalar içinde yanıt vermenizi sağlar. Günde binlerce CAPTCHA çözen bir ekipte bu kayıt olmadan ne fatura mutabakatı yapabilir, ne bir hatayı geriye doğru izleyebilir, ne de bir denetçiye çözüm hacminizi kanıtlayabilirsiniz. Bu rehber, CaptchaAI çözümleriniz için yapılandırılmış bir denetim günlüğünü Python ve Node.js ile nasıl kuracağınızı adım adım gösterir.
Denetim günlüğü neden gerekli?
Otomatik CAPTCHA çözümü kritik bir iş akışının parçası olduğunda, her istek üç açıdan hesap verebilir olmalıdır: operasyonel, mali ve yasal.
- Operasyonel: Bir çözüm oranı düştüğünde ya da gecikme arttığında, denetim günlüğü hangi site, hangi CAPTCHA türü ve hangi işin sorumlu olduğunu gösterir. Kör tahminle değil, veriyle sorun giderirsiniz.
- Mali: Kayıt altındaki istek sayısı ve tahmini maliyet, CaptchaAI kullanım panelindeki gerçek tüketimle karşılaştırılabilir. Beklenmedik bir sıçramayı ilk fark eden siz olursunuz.
- Yasal ve uyumluluk: Türkiye'de faaliyet gösteren ekipler için KVKK (Kişisel Verilerin Korunması Kanunu), SOC 2 ve GDPR gibi çerçeveler, otomatik veri toplama süreçlerinde izlenebilirlik bekler. İstanbul merkezli bir e-ticaret ekibinin ödeme adımındaki reCAPTCHA'yı QA ortamında doğrularken tuttuğu denetim izi, tam da bu izlenebilirliği kanıtlar.
Kritik ilke: Denetim günlüğü yalnızca meta veriyi kaydeder, kişisel veriyi değil. Hedef siteden gelen kişisel bilgiler KVKK kapsamındadır ve bu kaydın içinde asla yer almamalıdır.
Hangi alanları günlüğe kaydetmelisiniz?
Her CAPTCHA çözümü en az şu alanları içeren yapılandırılmış bir kayıt üretmelidir:
| Alan | Amaç | Örnek |
|---|---|---|
timestamp |
İsteğin ne zaman yapıldığı | 2026-04-04T14:30:00Z |
request_id |
Bu çözüme özel benzersiz kimlik | uuid4() |
captcha_type |
Kullanılan CAPTCHA yöntemi | userrecaptcha |
target_site |
Çözülen sayfanın URL'si | https://staging.example.com/qa-login |
task_id |
CaptchaAI görev kimliği | 73829451 |
status |
Sonuç | solved, failed, timeout |
solve_time_ms |
Gönderimden sonuca kadar geçen süre | 18432 |
error_code |
Başarısızlıkta hata kodu | ERROR_CAPTCHA_UNSOLVABLE |
initiator |
Çözümü tetikleyen iş ya da kullanıcı | scraper-job-42 |
cost |
Tahmini maliyet | 0.003 |
Şunları asla kaydetmeyin: API anahtarları, CAPTCHA token'ları (zaten geçicidirler) ve hedef sitelerden alınan kişisel veriler. Bunlar günlüğe hiçbir denetim değeri katmaz, buna karşılık ciddi bir güvenlik ve KVKK riski taşır.
Python ile denetim günlüğü uygulaması
Aşağıdaki uygulama, çözüm akışını sarmalayarak her aşamada (gönderim, sorgulama, sonuç, hata) tek satırlık bir JSONL kaydı üretir. Denetim günlükleyicisi bilinçli olarak uygulama loglarından ayrı tutulur ve dosya boyutu RotatingFileHandler ile sınırlanır.
# audit_solver.py
import os
import uuid
import time
import json
import logging
from datetime import datetime, timezone
import requests
API_KEY = os.environ.get("CAPTCHAAI_KEY", "YOUR_API_KEY")
# Configure audit logger — separate from application logs
audit_logger = logging.getLogger("captcha_audit")
audit_logger.setLevel(logging.INFO)
# File handler with rotation
from logging.handlers import RotatingFileHandler
handler = RotatingFileHandler(
"captcha_audit.jsonl",
maxBytes=50_000_000, # 50 MB per file
backupCount=10,
)
handler.setFormatter(logging.Formatter("%(message)s"))
audit_logger.addHandler(handler)
def log_audit(record):
"""Write a structured audit record."""
audit_logger.info(json.dumps(record, default=str))
def solve_with_audit(sitekey, pageurl, captcha_type="userrecaptcha",
initiator="unknown"):
"""Solve a CAPTCHA with full audit logging."""
request_id = str(uuid.uuid4())
start = time.time()
audit_record = {
"request_id": request_id,
"timestamp": datetime.now(timezone.utc).isoformat(),
"captcha_type": captcha_type,
"target_site": pageurl,
"initiator": initiator,
"status": "submitted",
}
session = requests.Session()
try:
# Submit
resp = session.get("https://ocr.captchaai.com/in.php", params={
"key": API_KEY,
"method": captcha_type,
"googlekey": sitekey,
"pageurl": pageurl,
"json": "1",
})
result = resp.json()
if result.get("status") != 1:
audit_record.update({
"status": "submit_failed",
"error_code": result.get("request"),
"solve_time_ms": int((time.time() - start) * 1000),
})
log_audit(audit_record)
return None
task_id = result["request"]
audit_record["task_id"] = task_id
# Poll
time.sleep(15)
for _ in range(25):
poll = session.get("https://ocr.captchaai.com/res.php", params={
"key": API_KEY, "action": "get",
"id": task_id, "json": "1",
})
poll_result = poll.json()
if poll_result.get("status") == 1:
solve_time = int((time.time() - start) * 1000)
audit_record.update({
"status": "solved",
"solve_time_ms": solve_time,
"cost_estimate": 0.003, # Adjust per your rate
})
log_audit(audit_record)
return poll_result["request"]
if poll_result.get("request") != "CAPCHA_NOT_READY":
audit_record.update({
"status": "failed",
"error_code": poll_result.get("request"),
"solve_time_ms": int((time.time() - start) * 1000),
})
log_audit(audit_record)
return None
time.sleep(5)
audit_record.update({
"status": "timeout",
"solve_time_ms": int((time.time() - start) * 1000),
})
log_audit(audit_record)
return None
except Exception as e:
audit_record.update({
"status": "error",
"error_code": str(e)[:200],
"solve_time_ms": int((time.time() - start) * 1000),
})
log_audit(audit_record)
raise
# Usage
token = solve_with_audit(
sitekey="6Le-wvkSAAAAAPBMRTvw0Q4Muexq9bi0DJwx_mJ-",
pageurl="https://www.google.com/recaptcha/api2/demo",
initiator="price-scraper-v2",
)
Denetim günlüğü çıktısı (JSONL biçimi)
Her satır bağımsız bir JSON nesnesidir; bu, günlüğü hem jq gibi araçlarla hem de bir log toplayıcıyla işlemeyi kolaylaştırır.
{"request_id":"a1b2c3d4-...","timestamp":"2026-04-04T14:30:00+00:00","captcha_type":"userrecaptcha","target_site":"https://www.google.com/recaptcha/api2/demo","initiator":"price-scraper-v2","status":"solved","task_id":"73829451","solve_time_ms":18432,"cost_estimate":0.003}
Node.js ile aynı akış
Node.js tarafında bağımlılıkları hafif tutmak için kayıtları doğrudan bir JSONL dosyasına ekleyebilirsiniz. Mantık Python sürümüyle aynıdır: gönder, 15 saniye bekle, sonucu sorgula ve her durumu kaydet.
// audit_solver.js
const fs = require('fs');
const { v4: uuidv4 } = require('uuid');
const axios = require('axios');
const API_KEY = process.env.CAPTCHAAI_KEY || 'YOUR_API_KEY';
const AUDIT_FILE = 'captcha_audit.jsonl';
function logAudit(record) {
fs.appendFileSync(AUDIT_FILE, JSON.stringify(record) + '\n');
}
async function solveWithAudit(sitekey, pageurl, initiator = 'unknown') {
const requestId = uuidv4();
const start = Date.now();
const record = {
request_id: requestId,
timestamp: new Date().toISOString(),
captcha_type: 'userrecaptcha',
target_site: pageurl,
initiator,
status: 'submitted',
};
try {
const submit = await axios.get('https://ocr.captchaai.com/in.php', {
params: {
key: API_KEY, method: 'userrecaptcha',
googlekey: sitekey, pageurl, json: '1',
},
});
if (submit.data.status !== 1) {
record.status = 'submit_failed';
record.error_code = submit.data.request;
record.solve_time_ms = Date.now() - start;
logAudit(record);
return null;
}
record.task_id = submit.data.request;
await new Promise(r => setTimeout(r, 15000));
for (let i = 0; i < 25; i++) {
const poll = await axios.get('https://ocr.captchaai.com/res.php', {
params: { key: API_KEY, action: 'get', id: submit.data.request, json: '1' },
});
if (poll.data.status === 1) {
record.status = 'solved';
record.solve_time_ms = Date.now() - start;
record.cost_estimate = 0.003;
logAudit(record);
return poll.data.request;
}
if (poll.data.request !== 'CAPCHA_NOT_READY') {
record.status = 'failed';
record.error_code = poll.data.request;
record.solve_time_ms = Date.now() - start;
logAudit(record);
return null;
}
await new Promise(r => setTimeout(r, 5000));
}
record.status = 'timeout';
record.solve_time_ms = Date.now() - start;
logAudit(record);
return null;
} catch (e) {
record.status = 'error';
record.error_code = e.message.slice(0, 200);
record.solve_time_ms = Date.now() - start;
logAudit(record);
throw e;
}
}
Denetim günlüklerini sorgulama ve raporlama
Kayıtları toplamak yalnızca ilk adımdır; asıl değer, onları özet metriklere dönüştürdüğünüzde ortaya çıkar. Aşağıdaki fonksiyon belirli bir güne ait toplam istek sayısını, durum dağılımını, tahmini maliyeti ve medyan çözüm süresini üretir.
Günlük özet raporu
import json
from collections import Counter
from datetime import date
def daily_summary(log_file, target_date=None):
"""Generate a daily summary from audit logs."""
target = target_date or date.today().isoformat()
statuses = Counter()
total_cost = 0
solve_times = []
with open(log_file) as f:
for line in f:
record = json.loads(line)
if record["timestamp"].startswith(target):
statuses[record["status"]] += 1
total_cost += record.get("cost_estimate", 0)
if record.get("solve_time_ms"):
solve_times.append(record["solve_time_ms"])
print(f"Date: {target}")
print(f"Total requests: {sum(statuses.values())}")
print(f"Statuses: {dict(statuses)}")
print(f"Estimated cost: ${total_cost:.2f}")
if solve_times:
print(f"Median solve time: {sorted(solve_times)[len(solve_times)//2]}ms")
daily_summary("captcha_audit.jsonl")
Bu çıktıyı her sabah çalıştıran bir cron işi, ekibinize çözüm oranındaki ani düşüşleri ve maliyet sapmalarını erkenden haber verir.
Saklama süresi ve depolama stratejisi
Denetim günlükleri hızla büyür, bu yüzden hacme göre bir depolama planı seçin. Aşağıdaki büyüklükler kaba tahminlerdir ve kayıt yapınıza göre değişir:
| Hacim | Günlük log boyutu | Aylık depolama | Öneri |
|---|---|---|---|
| 100 çözüm/gün | ~30 KB | ~1 MB | Yerel dosya |
| 1.000 çözüm/gün | ~300 KB | ~10 MB | Yerel dosya + döndürme |
| 10.000 çözüm/gün | ~3 MB | ~100 MB | Bir log toplayıcıya gönderin |
| 100.000 çözüm/gün | ~30 MB | ~1 GB | Merkezi loglama (ELK, Datadog) |
Düşük hacimde yerel bir dosya ve logrotate yeterlidir; on binlerce çözümü aşan operasyonlarda kayıtları merkezi bir sisteme akıtmak hem sorgulamayı hem de saklama politikalarını yönetmeyi kolaylaştırır.
Sık karşılaşılan sorunlar ve çözümleri
| Sorun | Sebep | Çözüm |
|---|---|---|
| Günlük dosyası aşırı büyüyor | Döndürme yapılandırılmamış | RotatingFileHandler ya da logrotate kullanın |
| Kayıtlar eksik kalıyor | Loglamadan önce oluşan istisna | Kaydı finally bloğunda yazın |
| Yüksek hacimde yavaş yazma | Senkron dosya G/Ç | Eşzamansız yazma veya arabelleğe alma kullanın |
| Tutarsız zaman damgaları | Sistem saati sapması | NTP kullanın; her zaman UTC'ye yazın |
Denetlenebilir bir kayıt için kısa kontrol listesi
Üretime almadan önce günlükleyicinizi şu maddelere karşı gözden geçirin:
- Kayıt her durumu yazıyor mu —
solved,failed,timeoutveerror? Yalnızca başarılı çözümleri kaydetmek, denetimin en kritik kısmını gizler. - Yazma işlemi bir
finallybloğunda mı? İstisna, kaydı atlatmamalı. - API anahtarları, token'lar ve kişisel veri kayıt dışında mı tutuluyor?
- Zaman damgaları UTC ve tek biçim mi? Sapmayı önlemek için NTP kullanın.
- Döndürme (
RotatingFileHandlerya dalogrotate) ve saklama süresi tanımlı mı?
Sık sorulan sorular
Denetim günlükleri KVKK kapsamında kişisel veri sayılır mı?
Doğru kurulduğunda hayır. Kayıt yalnızca request_id, task_id, zaman damgası ve maliyet gibi meta veriyi tutar. Hedef sayfadan gelen kullanıcı bilgilerini veya CAPTCHA token'ını saklamadığınız sürece günlük, kişisel veri barındırmaz ve KVKK yükümlülüğünüzü basitleştirir.
Denetim günlüğü verilerini faturamla nasıl karşılaştırırım?
daily_summary çıktısındaki toplam istek sayısını ve tahmini maliyeti, CaptchaAI kullanım paneliyle yan yana koyun. İki değer arasındaki fark, kayıtsız kalan istekleri veya yanlış işaretlenmiş bir işi işaret eder.
Yüksek hacimde günlük yazmak botu yavaşlatır mı?
Senkron dosya yazımı, saniyede yüzlerce çözümde darboğaz olabilir. Bu noktaya geldiğinizde arabelleğe alma ya da eşzamansız yazma kullanın; kayıtları bir kuyruğa alıp toplu halde bir toplayıcıya göndermek de çözüm süresini etkilemeden ölçeklenmenizi sağlar.
Hangi CAPTCHA türleri için denetim günlüğü tutabilirim?
captcha_type alanı yönteme göre değişir, ancak yaklaşım her tür için aynıdır. CaptchaAI'nin desteklediği reCAPTCHA v2/v3, Cloudflare Turnstile, GeeTest v3, BLS ve görüntü/grid CAPTCHA'larının hepsini aynı kayıt şemasıyla izleyebilirsiniz.
Ne kadar süre saklamalıyım?
Operasyonel günlükler için 90 gün yaygın bir standarttır. Uyumluluk odaklı bir kayıt tutuyorsanız, tabi olduğunuz çerçevenin (KVKK, SOC 2, GDPR, HIPAA) saklama gereksinimini esas alın.
İlgili makaleler
Sonraki adımlar
Her CAPTCHA çözümünü hesap verebilir hale getirin — CaptchaAI API anahtarınızı alın ve ilk denetim kaydınızı bugün üretin.
İlgili kılavuzlar: