الدروس التطبيقية

التسجيل المنظم لعمليات CAPTCHA

عندما يفشل حل اختبار CAPTCHA في الساعة 3 صباحًا، فإن سجلات النص العادي مثل "Error solving captcha" لا تساعد. تتيح لك سجلات JSON المنظمة بمعرفات المهام وأنواع captcha وأوقات الحل وأكواد الأخطاء إمكانية التصفية والبحث والتنبيه بشأن الأخطاء التي حدثت بالضبط.


لماذا التسجيل المنظم

نص عادي JSON منظم
Captcha solved in 12.3s {"event":"captcha_solved","task_id":"abc123","type":"recaptcha_v2","solve_time_ms":12300}
من الصعب تحليلها يمكن قراءتها آليًا
بحث Grep فقط تصفية حسب أي حقل
لا يوجد ارتباط روابط معرف المهمة إرسال †’ استطلاع †’ حقن

بايثون: سجل البنية

import structlog
import time

structlog.configure(
    processors=[
        structlog.processors.TimeStamper(fmt="iso"),
        structlog.processors.add_log_level,
        structlog.processors.JSONRenderer(),
    ],
    logger_factory=structlog.PrintLoggerFactory(),
)

log = structlog.get_logger()

تسجيل دورة حياة الحل

import requests

API_KEY = "YOUR_API_KEY"


def solve_captcha(captcha_type, sitekey, page_url, proxy=None):
    solve_log = log.bind(
        captcha_type=captcha_type,
        site_url=page_url,
        sitekey=sitekey[:12] + "...",
    )

    # Submit
    start = time.time()
    solve_log.info("captcha_submit_start")

    resp = requests.post("https://ocr.captchaai.com/in.php", data={
        "key": API_KEY,
        "method": "userrecaptcha",
        "googlekey": sitekey,
        "pageurl": page_url,
        "json": "1",
    }).json()

    if resp["status"] != 1:
        solve_log.error("captcha_submit_failed", error=resp["request"])
        return None

    task_id = resp["request"]
    submit_ms = int((time.time() - start) * 1000)
    solve_log = solve_log.bind(task_id=task_id)
    solve_log.info("captcha_submitted", submit_ms=submit_ms)

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

        if result["status"] == 1:
            solve_ms = int((time.time() - start) * 1000)
            solve_log.info(
                "captcha_solved",
                solve_time_ms=solve_ms,
                poll_attempts=attempt + 1,
                token_length=len(result["request"]),
            )
            return result["request"]

        if result["request"] != "CAPCHA_NOT_READY":
            solve_log.error(
                "captcha_solve_failed",
                error=result["request"],
                poll_attempts=attempt + 1,
            )
            return None

    solve_log.warning("captcha_solve_timeout", poll_attempts=24)
    return None

الإخراج:

{"event":"captcha_submit_start","captcha_type":"recaptcha_v2","site_url":"https://example.com","sitekey":"6Le-wvkSAAAA...","timestamp":"2025-07-15T10:30:00Z","level":"info"}
{"event":"captcha_submitted","task_id":"71845302","submit_ms":245,"timestamp":"2025-07-15T10:30:00Z","level":"info"}
{"event":"captcha_solved","task_id":"71845302","solve_time_ms":18230,"poll_attempts":4,"token_length":580,"timestamp":"2025-07-15T10:30:18Z","level":"info"}

Node.js: بينو

const pino = require('pino');

const log = pino({
  level: 'info',
  timestamp: pino.stdTimeFunctions.isoTime,
});

تسجيل دورة حياة الحل

const axios = require('axios');

const API_KEY = 'YOUR_API_KEY';

async function solveCaptcha(captchaType, sitekey, pageUrl) {
  const taskLog = log.child({
    captchaType,
    siteUrl: pageUrl,
    sitekey: sitekey.substring(0, 12) + '...',
  });

  const start = Date.now();
  taskLog.info('captcha_submit_start');

  const submit = await axios.post('https://ocr.captchaai.com/in.php', null, {
    params: {
      key: API_KEY, method: 'userrecaptcha',
      googlekey: sitekey, pageurl: pageUrl, json: 1,
    },
  });

  if (submit.data.status !== 1) {
    taskLog.error({ error: submit.data.request }, 'captcha_submit_failed');
    return null;
  }

  const taskId = submit.data.request;
  const boundLog = taskLog.child({ taskId });
  boundLog.info({ submitMs: Date.now() - start }, 'captcha_submitted');

  for (let attempt = 1; attempt <= 24; attempt++) {
    await new Promise(r => setTimeout(r, 5000));
    const poll = await axios.get('https://ocr.captchaai.com/res.php', {
      params: { key: API_KEY, action: 'get', id: taskId, json: 1 },
    });

    if (poll.data.status === 1) {
      boundLog.info({
        solveTimeMs: Date.now() - start,
        pollAttempts: attempt,
        tokenLength: poll.data.request.length,
      }, 'captcha_solved');
      return poll.data.request;
    }

    if (poll.data.request !== 'CAPCHA_NOT_READY') {
      boundLog.error({ error: poll.data.request, pollAttempts: attempt }, 'captcha_solve_failed');
      return null;
    }
  }

  boundLog.warn({ pollAttempts: 24 }, 'captcha_solve_timeout');
  return null;
}

مرجع حقول السجل

الميدان النوع الوصف
event سلسلة اسم الحدث: captcha_submitted، captcha_solved، إلخ.
task_id سلسلة معرف المهمة CaptchaAI للارتباط
captcha_type سلسلة recaptcha_v2، turnstile، image، إلخ.
site_url سلسلة عنوان URL للصفحة المستهدفة
solve_time_ms عدد صحيح إجمالي الوقت من إرسال إلى حلها
poll_attempts عدد صحيح عدد طلبات الاستطلاع المقدمة
error سلسلة رمز الخطأ من CaptchaAI
token_length عدد صحيح طول الرمز المميز الذي تم إرجاعه

التصفية والتنبيه

البحث عن جميع حالات الفشل في الساعة الماضية

# With jq
cat captcha.log | jq 'select(.level == "error" and .event == "captcha_solve_failed")'

تنبيه بشأن ارتفاع معدل الفشل

# Count errors vs successes in a rolling window
from collections import deque

class ErrorRateMonitor:
    def __init__(self, window_size=100, threshold=0.2):
        self.results = deque(maxlen=window_size)
        self.threshold = threshold

    def record(self, success):
        self.results.append(success)
        if len(self.results) >= 50:
            error_rate = 1 - sum(self.results) / len(self.results)
            if error_rate > self.threshold:
                log.warning(
                    "captcha_error_rate_high",
                    error_rate=round(error_rate, 3),
                    window=len(self.results),
                )

استكشاف الأخطاء وإصلاحها

مشكلة السبب إصلاح
سجلات مطولة جدا تسجيل كل محاولة استطلاع سجل فقط الأحداث التي تم إرسالها وحلها والفاشلة
لا يمكن ربط الأحداث معرف المهمة مفقود ربط task_id مبكرًا باستخدام log.bind() أو log.child()
سجلات غير قابلة للبحث تنسيق نص عادي قم بالتبديل إلى JSON باستخدام structlog أو pino
البيانات الحساسة في السجلات تسجيل مفتاح API الكامل لا تقم مطلقًا بتسجيل مفاتيح واجهة برمجة التطبيقات؛ اقتطاع مفاتيح الموقع

الأسئلة الشائعة

هل يجب أن أقوم بتسجيل رمز CAPTCHA؟

قم بتسجيل طول الرمز المميز، وليس الرمز المميز الكامل. يمكن أن تتكون الرموز المميزة من أكثر من 500 حرف وتضيف حجم سجل غير ضروري.

ما هو مستوى السجل لـ CAPCHA_NOT_READY؟

لا تقم بتسجيله على الإطلاق، فمن المتوقع أن يتم ذلك أثناء الاقتراع، فقط قم بتسجيل النتيجة النهائية.


أنشئ سير عمل اختبار CAPTCHA يمكن ملاحظته باستخدام CaptchaAI

احصل على مفتاح API الخاص بك علىcaptchaai.com.


أدلة ذات صلة

التعليقات غير مفعّلة لهذا المقال.