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

التعامل مع اختبار CAPTCHA في تطبيقات Django باستخدام CaptchaAI

تحتاج تطبيقات Django في كثير من الأحيان إلى التعامل مع اختبارات CAPTCHA في سيناريوهين: التحقق من اختبارات CAPTCHA في النماذج الخاصة بك (الحماية من الروبوتات) و حل اختبارات CAPTCHA على المواقع الخارجية (جمع البيانات، والاختبار، والأتمتة). يغطي هذا الدليل كلا النموذجين باستخدام CaptchaAI.


السيناريو 1: التحقق من اختبارات CAPTCHA في نماذج Django الخاصة بك

عند إضافة Turnstile أو reCAPTCHA إلى نماذج Django الخاصة بك، فإنك تحتاج إلى التحقق من الرموز المميزة من جانب الخادم.

إضافة Turnstile إلى نموذج Django

# forms.py
from django import forms

class ContactForm(forms.Form):
    name = forms.CharField(max_length=100)
    email = forms.EmailField()
    message = forms.CharField(widget=forms.Textarea)
    cf_turnstile_response = forms.CharField(
        widget=forms.HiddenInput(),
        required=True,
    )
# views.py
import requests
from django.conf import settings
from django.shortcuts import render, redirect
from .forms import ContactForm

def contact_view(request):
    if request.method == "POST":
        form = ContactForm(request.POST)
        if form.is_valid():
            # Verify Turnstile token with Cloudflare
            token = form.cleaned_data["cf_turnstile_response"]
            verification = requests.post(
                "https://challenges.cloudflare.com/turnstile/v0/siteverify",
                data={
                    "secret": settings.TURNSTILE_SECRET_KEY,
                    "response": token,
                    "remoteip": request.META.get("REMOTE_ADDR"),
                },
            ).json()

            if verification.get("success"):
                # Process the form
                return redirect("success")
            else:
                form.add_error(None, "CAPTCHA verification failed")
    else:
        form = ContactForm()

    return render(request, "contact.html", {
        "form": form,
        "turnstile_sitekey": settings.TURNSTILE_SITE_KEY,
    })
<!-- templates/contact.html -->
<form method="post">
    {% csrf_token %}
    {{ form.as_p }}
    <div class="cf-turnstile" data-sitekey="{{ turnstile_sitekey }}"></div>
    <button type="submit">Send</button>
</form>
<script src="https://challenges.cloudflare.com/turnstile/v0/api.js" async defer></script>

السيناريو 2: حل اختبارات CAPTCHA على المواقع الخارجية

هذا هو المكان الذي يأتي فيه CaptchaAI - عندما يحتاج تطبيق Django الخاص بك إلى التفاعل مع المواقع الخارجية المحمية بـ CAPTCHA.

فئة الخدمة CaptchaAI

# services/captcha_solver.py
import time
import requests
from django.conf import settings


class CaptchaSolverService:
    """Django service for solving CAPTCHAs via CaptchaAI."""

    API_BASE = "https://ocr.captchaai.com"

    def __init__(self):
        self.api_key = settings.CAPTCHAAI_API_KEY

    def solve_recaptcha_v2(self, sitekey, page_url, invisible=False):
        """Solve reCAPTCHA v2."""
        params = {
            "key": self.api_key,
            "method": "userrecaptcha",
            "googlekey": sitekey,
            "pageurl": page_url,
            "json": 1,
        }
        if invisible:
            params["invisible"] = 1
        return self._submit_and_poll(params)

    def solve_turnstile(self, sitekey, page_url, action=None):
        """Solve Cloudflare Turnstile."""
        params = {
            "key": self.api_key,
            "method": "turnstile",
            "sitekey": sitekey,
            "pageurl": page_url,
            "json": 1,
        }
        if action:
            params["action"] = action
        return self._submit_and_poll(params)

    def solve_image(self, image_base64):
        """Solve image/text CAPTCHA."""
        return self._submit_and_poll({
            "key": self.api_key,
            "method": "base64",
            "body": image_base64,
            "json": 1,
        })

    def get_balance(self):
        """Check API balance."""
        response = requests.get(f"{self.API_BASE}/res.php", params={
            "key": self.api_key,
            "action": "getbalance",
            "json": 1,
        }, timeout=30)
        return float(response.json().get("request", 0))

    def _submit_and_poll(self, params, timeout=120):
        """Submit task and poll for result."""
        # Submit
        response = requests.post(f"{self.API_BASE}/in.php", data=params, timeout=30)
        response.raise_for_status()
        data = response.json()

        if data.get("status") != 1:
            raise CaptchaSolveError(f"Submit failed: {data.get('request')}")

        task_id = data["request"]

        # Poll
        start = time.time()
        while time.time() - start < timeout:
            time.sleep(5)
            result = requests.get(f"{self.API_BASE}/res.php", params={
                "key": self.api_key,
                "action": "get",
                "id": task_id,
                "json": 1,
            }, timeout=30).json()

            if result.get("status") == 1:
                return result["request"]
            if result.get("request") == "ERROR_CAPTCHA_UNSOLVABLE":
                raise CaptchaSolveError("CAPTCHA unsolvable")

        raise CaptchaSolveError("Solve timed out")


class CaptchaSolveError(Exception):
    pass

إعدادات Django

# settings.py
CAPTCHAAI_API_KEY = "YOUR_API_KEY"
TURNSTILE_SITE_KEY = "0x4AAAAAAAC3DHQhMMQ_Rxrg"
TURNSTILE_SECRET_KEY = "0x4AAAAAAAC3DHQhYYY_secret"

استخدام الخدمة في وجهات النظر

عرض لجمع البيانات الخارجية

# views.py
from django.http import JsonResponse
from django.views.decorators.http import require_POST
from .services.captcha_solver import CaptchaSolverService, CaptchaSolveError

@require_POST
def scrape_external_data(request):
    """Solve CAPTCHA and fetch data from external CAPTCHA-protected site."""
    url = request.POST.get("target_url")
    if not url:
        return JsonResponse({"error": "target_url required"}, status=400)

    solver = CaptchaSolverService()

    try:
        # Solve the CAPTCHA
        token = solver.solve_turnstile(
            sitekey="0x4AAAAAAAC3DHQhMMQ_Rxrg",
            page_url=url,
        )

        # Use token to access the protected resource
        import requests as http_requests
        response = http_requests.post(url, data={
            "cf-turnstile-response": token,
        }, timeout=30)

        return JsonResponse({
            "status": "success",
            "data": response.text[:1000],
        })

    except CaptchaSolveError as e:
        return JsonResponse({"error": str(e)}, status=500)

أمر إدارة Django

# management/commands/solve_captcha.py
from django.core.management.base import BaseCommand
from myapp.services.captcha_solver import CaptchaSolverService


class Command(BaseCommand):
    help = "Solve a CAPTCHA and print the token"

    def add_arguments(self, parser):
        parser.add_argument("--type", choices=["recaptcha", "turnstile"], required=True)
        parser.add_argument("--sitekey", required=True)
        parser.add_argument("--url", required=True)

    def handle(self, *args, **options):
        solver = CaptchaSolverService()

        self.stdout.write(f"Solving {options['type']} for {options['url']}...")

        if options["type"] == "recaptcha":
            token = solver.solve_recaptcha_v2(options["sitekey"], options["url"])
        else:
            token = solver.solve_turnstile(options["sitekey"], options["url"])

        self.stdout.write(self.style.SUCCESS(f"Token: {token[:50]}..."))

        # Check balance
        balance = solver.get_balance()
        self.stdout.write(f"Remaining balance: ${balance:.2f}")

الاستخدام:

python manage.py solve_captcha --type turnstile --sitekey 0x4AAA... --url https://example.com

غير متزامن مع Django مع CaptchaAI

يدعم Django 4.1+ طرق العرض غير المتزامنة:

# views.py (async)
import aiohttp
import asyncio
from django.http import JsonResponse

CAPTCHAAI_API_KEY = "YOUR_API_KEY"

async def solve_captcha_async(request):
    """Async view for solving CAPTCHAs."""
    sitekey = request.GET.get("sitekey")
    page_url = request.GET.get("url")

    if not sitekey or not page_url:
        return JsonResponse({"error": "sitekey and url required"}, status=400)

    async with aiohttp.ClientSession() as session:
        # Submit
        async with session.post("https://ocr.captchaai.com/in.php", data={
            "key": CAPTCHAAI_API_KEY,
            "method": "turnstile",
            "sitekey": sitekey,
            "pageurl": page_url,
            "json": 1,
        }) as resp:
            data = await resp.json()

        if data.get("status") != 1:
            return JsonResponse({"error": data.get("request")}, status=500)

        task_id = data["request"]

        # Poll
        for _ in range(30):
            await asyncio.sleep(5)
            async with session.get("https://ocr.captchaai.com/res.php", params={
                "key": CAPTCHAAI_API_KEY,
                "action": "get",
                "id": task_id,
                "json": 1,
            }) as resp:
                result = await resp.json()

            if result.get("status") == 1:
                return JsonResponse({"token": result["request"]})

    return JsonResponse({"error": "timeout"}, status=504)

التكامل الكرفس لحل الخلفية

لحل اختبار CAPTCHA طويل الأمد، استخدم الكرفس:

# tasks.py
from celery import shared_task
from .services.captcha_solver import CaptchaSolverService, CaptchaSolveError

@shared_task(bind=True, max_retries=2, default_retry_delay=10)
def solve_captcha_task(self, captcha_type, sitekey, page_url):
    """Background CAPTCHA solving with Celery."""
    solver = CaptchaSolverService()

    try:
        if captcha_type == "recaptcha_v2":
            token = solver.solve_recaptcha_v2(sitekey, page_url)
        elif captcha_type == "turnstile":
            token = solver.solve_turnstile(sitekey, page_url)
        else:
            raise ValueError(f"Unknown type: {captcha_type}")

        return {"success": True, "token": token}

    except CaptchaSolveError as e:
        self.retry(exc=e)
# Usage in views
from .tasks import solve_captcha_task

def start_solve(request):
    result = solve_captcha_task.delay("turnstile", "0x4AAA...", "https://example.com")
    return JsonResponse({"task_id": result.id})

def check_solve(request, task_id):
    from celery.result import AsyncResult
    result = AsyncResult(task_id)
    if result.ready():
        return JsonResponse(result.get())
    return JsonResponse({"status": "pending"})

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

أعراض السبب إصلاح
CaptchaSolveError قيد الإنتاج مفتاح API ليس في الإعدادات أضف CAPTCHAAI_API_KEY إلى إعدادات Django
تتم إعادة المحاولة بمهمة الكرفس إلى ما لا نهاية اختبار CAPTCHA غير قابل للحل أو مفتاح موقع خاطئ قم بتعيين max_retries والتحقق من صحة الإدخال
طريقة العرض غير المتزامنة معلقة رمز المزامنة في طريقة العرض غير المتزامنة استخدم aiohttp بدلاً من requests
انتهت صلاحية الرمز المميز قبل إرسال النموذج استغرق الحل وقتا طويلا حل في الوقت المناسب، وليس في المستقبل
أخطاء الاستيراد في أمر الإدارة الخدمة ليست في INSTALLED_APPS التحقق من تسجيل التطبيق

الأسئلة المتداولة

هل يجب أن يكون حل اختبار CAPTCHA متزامنًا أم غير متزامن؟

استخدم Celery للعرض على الويب حتى لا ينتظر المستخدم أكثر من 15 ثانية. استخدم الحل المتزامن في أوامر الإدارة والبرامج النصية الخلفية.

كيف أقوم بتخزين مفاتيح API بشكل آمن؟

استخدم متغيرات البيئة أو حزمة Django django-environ. لا تقم مطلقًا بإلزام مفاتيح API بالتحكم في الإصدار.

هل يمكنني تخزين الرموز المميزة التي تم حلها مؤقتًا؟

تنتهي صلاحية رموز reCAPTCHA خلال 120 ثانية ورموز Turnstile خلال 300 ثانية. التخزين المؤقت ليس عمليا - قم بحل المشكلة قبل الاستخدام مباشرة.

هل يجب علي إنشاء مثيل خدمة واحد أو استخدام نسخة مفردة؟

فئة CaptchaSolverService عديمة الحالة. قم بإنشاء مثيل جديد لكل طلب أو استخدم أنماط حقن التبعية الخاصة بـ Django.


ملخص

تتكامل تطبيقات Django معCaptchaAIمن خلال فئة الخدمة التي تغلف تدفق Submit/poll. استخدم الحل المتزامن في أوامر الإدارة، والحل غير المتزامن في طرق العرض غير المتزامنة لـ Django 4.1+، ومهام Celery لمعالجة الخلفية. نفس الخدمة تتعامل مع reCAPTCHA و Turnstile و image CAPTCHAs.

مقالات ذات صلة

أدلة ذات صلة

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