Kullanım Senaryoları

Üniversite Ders Kayıt Testi için CAPTCHA Kullanımı

Üniversite ders kayıt sistemleri, kayıt formlarını, sınıf arama sayfalarını ve program planlayıcılarını korumak için reCAPTCHA v2'yi kullanır. Bu sistemleri test eden QA ekiplerinin, CAPTCHA'ları birden fazla test senaryosunda (kayıt iş akışları, bekleme listesi mantığı, koltuk kullanılabilirliği ve son tarih uygulaması) ele alması gerekir. CAPTCHA çözümünü kayıt testine nasıl entegre edeceğiniz aşağıda açıklanmıştır.

CAPTCHA'ların Kayıt Sistemlerinde Nerede Göründüğü

Kayıt adımı CAPTCHA türü Amaç
Öğrenci giriş sayfası reCAPTCHA v2 Kimlik bilgisi doldurmayı önleyin
Kurs arama/browse reCAPTCHA v2 Otomatik aramaları sınırlayın
/drop kursları ekle reCAPTCHA v2 Otomatik kaydı engelle
Bekleme listesi kaydı reCAPTCHA v2 Otomatik kayıt botlarını engelle
Zamanlama planlayıcısı Cloudflare Turnstile Etkileşimli araçları koruyun
Transkript istekleri reCAPTCHA v2 İnsan kullanıcıyı doğrulayın

CAPTCHA Çözme ile Kayıt Testi

import requests
import time
import re

class RegistrationTester:
    def __init__(self, api_key, portal_url):
        self.api_key = api_key
        self.portal_url = portal_url
        self.session = requests.Session()
        self.session.headers.update({
            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
        })

    def test_login(self, student_id, password):
        """Test login flow with CAPTCHA handling."""
        login_page = self.session.get(f"{self.portal_url}/login")

        site_key = self._extract_site_key(login_page.text)
        token = self._solve_recaptcha(site_key, f"{self.portal_url}/login")

        response = self.session.post(f"{self.portal_url}/login", data={
            "studentId": student_id,
            "password": password,
            "g-recaptcha-response": token
        })

        return {
            "status": response.status_code,
            "redirected": response.url != f"{self.portal_url}/login",
            "success": "dashboard" in response.url or response.status_code == 200
        }

    def test_course_search(self, term, department, level=None):
        """Test course search returns correct results."""
        params = {"term": term, "dept": department}
        if level:
            params["level"] = level

        response = self.session.get(
            f"{self.portal_url}/courses/search", params=params
        )

        if self._has_captcha(response.text):
            site_key = self._extract_site_key(response.text)
            token = self._solve_recaptcha(
                site_key, f"{self.portal_url}/courses/search"
            )
            response = self.session.post(
                f"{self.portal_url}/courses/search",
                data={**params, "g-recaptcha-response": token}
            )

        courses = self._parse_courses(response.text)
        return {
            "count": len(courses),
            "courses": courses,
            "all_match_dept": all(
                c["department"] == department for c in courses
            )
        }

    def test_enrollment(self, course_id, section):
        """Test enrolling in a course section."""
        enroll_page = self.session.get(
            f"{self.portal_url}/enroll/{course_id}/{section}"
        )

        if self._has_captcha(enroll_page.text):
            site_key = self._extract_site_key(enroll_page.text)
            token = self._solve_recaptcha(
                site_key,
                f"{self.portal_url}/enroll/{course_id}/{section}"
            )
        else:
            token = None

        form_data = {
            "courseId": course_id,
            "section": section,
            "confirm": "true"
        }
        if token:
            form_data["g-recaptcha-response"] = token

        response = self.session.post(
            f"{self.portal_url}/enroll/submit",
            data=form_data
        )

        return {
            "status": response.status_code,
            "enrolled": "success" in response.text.lower(),
            "waitlisted": "waitlist" in response.text.lower(),
            "error": self._extract_error(response.text)
        }

    def test_seat_availability(self, course_ids):
        """Test seat availability display for multiple courses."""
        results = []
        for course_id in course_ids:
            response = self.session.get(
                f"{self.portal_url}/courses/{course_id}"
            )

            if self._has_captcha(response.text):
                site_key = self._extract_site_key(response.text)
                token = self._solve_recaptcha(
                    site_key, f"{self.portal_url}/courses/{course_id}"
                )
                response = self.session.post(
                    f"{self.portal_url}/courses/{course_id}",
                    data={"g-recaptcha-response": token}
                )

            availability = self._parse_availability(response.text)
            results.append({"course_id": course_id, **availability})

        return results

    def _has_captcha(self, html):
        return "g-recaptcha" in html or "recaptcha" in html.lower()

    def _extract_site_key(self, html):
        match = re.search(r'data-sitekey="([^"]+)"', html)
        if match:
            return match.group(1)
        raise ValueError("reCAPTCHA site key not found")

    def _solve_recaptcha(self, site_key, page_url):
        resp = requests.post("https://ocr.captchaai.com/in.php", data={
            "key": self.api_key,
            "method": "userrecaptcha",
            "googlekey": site_key,
            "pageurl": page_url,
            "json": 1
        })
        task_id = resp.json()["request"]

        for _ in range(60):
            time.sleep(3)
            result = requests.get("https://ocr.captchaai.com/res.php", params={
                "key": self.api_key,
                "action": "get",
                "id": task_id,
                "json": 1
            })
            data = result.json()
            if data["status"] == 1:
                return data["request"]

        raise TimeoutError("reCAPTCHA solve timed out")

    def _parse_courses(self, html):
        from bs4 import BeautifulSoup
        soup = BeautifulSoup(html, "html.parser")

        def text_or_empty(node):
            return node.text.strip() if node and node.text else ""

        courses = []
        for row in soup.select(".course-row, tr.course"):
            courses.append({
                "id": row.get("data-course-id", ""),
                "department": text_or_empty(row.select_one(".dept")),
                "number": text_or_empty(row.select_one(".number")),
                "title": text_or_empty(row.select_one(".title")),
                "seats": text_or_empty(row.select_one(".seats"))
            })
        return courses

    def _parse_availability(self, html):
        from bs4 import BeautifulSoup
        soup = BeautifulSoup(html, "html.parser")

        def text_or_none(node):
            return node.text.strip() if node and node.text else None

        return {
            "total_seats": text_or_none(soup.select_one(".total-seats")),
            "enrolled": text_or_none(soup.select_one(".enrolled-count")),
            "available": text_or_none(soup.select_one(".available-seats")),
            "waitlist": text_or_none(soup.select_one(".waitlist-count"))
        }

    def _extract_error(self, html):
        from bs4 import BeautifulSoup
        soup = BeautifulSoup(html, "html.parser")
        error = soup.select_one(".error-message, .alert-danger")
        return error.text.strip() if error else None

Test Paketi Çalıştırıcısı (JavaScript)

class RegistrationTestSuite {
  constructor(apiKey, portalUrl) {
    this.apiKey = apiKey;
    this.portalUrl = portalUrl;
    this.results = [];
  }

  async runAll(testCredentials) {
    const tests = [
      () => this.testLogin(testCredentials),
      () => this.testCourseSearch('Fall2025', 'CS'),
      () => this.testEnrollment('CS101', '001'),
      () => this.testDropCourse('CS101', '001'),
      () => this.testWaitlistFlow('CS201', '001')
    ];

    for (const test of tests) {
      try {
        const result = await test();
        this.results.push({ ...result, passed: true });
      } catch (error) {
        this.results.push({ name: test.name, error: error.message, passed: false });
      }
    }

    return this.generateReport();
  }

  async solveRecaptcha(pageUrl, html) {
    const match = html.match(/data-sitekey="([^"]+)"/);
    if (!match) return null;

    const submitResp = await fetch('https://ocr.captchaai.com/in.php', {
      method: 'POST',
      body: new URLSearchParams({
        key: this.apiKey,
        method: 'userrecaptcha',
        googlekey: match[1],
        pageurl: pageUrl,
        json: '1'
      })
    });
    const { request: taskId } = await submitResp.json();

    for (let i = 0; i < 60; i++) {
      await new Promise(r => setTimeout(r, 3000));
      const result = await fetch(
        `https://ocr.captchaai.com/res.php?key=${this.apiKey}&action=get&id=${taskId}&json=1`
      );
      const data = await result.json();
      if (data.status === 1) return data.request;
    }
    throw new Error('reCAPTCHA solve timed out');
  }

  generateReport() {
    const passed = this.results.filter(r => r.passed).length;
    const failed = this.results.filter(r => !r.passed).length;

    return {
      total: this.results.length,
      passed,
      failed,
      passRate: `${((passed / this.results.length) * 100).toFixed(1)}%`,
      details: this.results
    };
  }
}

// Usage
const suite = new RegistrationTestSuite('YOUR_API_KEY', 'https://register.university.edu');
const report = await suite.runAll({ studentId: 'test123', password: 'testpass' });
console.log(`Tests: ${report.passed}/${report.total} passed (${report.passRate})`);

CAPTCHA'ları Tetikleyen Test Senaryoları

Test senaryosu CAPTCHA sıklığı Etki
Birden fazla hesapla giriş yapın Yüksek Her giriş denemesi CAPTCHA'yı tetikler
Eşzamanlı kayıt testleri Yüksek Bot karşıtı koruma
Hızlı kurs aramaları Orta Hız sınırlı sorgular
Zamanlama oluşturma Düşük Tek oturumlu etkileşim
Önkoşul doğrulama Düşük Kayıt akışının bir parçası

Sorun giderme

Sorun Sebep Düzeltme
Her test girişinde CAPTCHA Oturumun yeniden kullanımı yok Bir kez kimlik doğrulaması yapın, testleri oturum içinde çalıştırın
CAPTCHA'dan sonra kayıt başarısız oluyor CSRF jetonunun süresi doldu CAPTCHA ile yeni CSRF jetonunu çıkarın
Test verileri çalıştırmalar arasında sıfırlanır Portal test kayıtlarını temizliyor Özel test ortamını kullanın
reCAPTCHA site anahtarı bulunamadı SPA, CAPTCHA'yı dinamik olarak oluşturuyor İşlenen DOM'a erişmek için tarayıcı otomasyonunu kullanın

SSS

CAPTCHA'ların olmadığı bir test ortamı kullanmalı mıyım?

İdeal olarak, hazırlama ortamları CAPTCHA'ları devre dışı bırakır. Bu mümkün olmadığında (veya üretim davranışını test ederken), CaptchaAI, reCAPTCHA v2 çözümünü yöneterek testlerin manuel müdahale olmadan çalışmasını sağlar.

CI/CD test işlem hatlarında CAPTCHA'ları nasıl ele alırım?

CaptchaAI'yi test bağımlılığı olarak ekleyin. Bir test CAPTCHA ile karşılaştığında bunu API aracılığıyla çözün ve devam edin. Bu, güvenlik özelliklerini devre dışı bırakmadan uçtan uca testlerin güvenilir olmasını sağlar.

Yük altında kaydı CAPTCHA'larla test edebilir miyim?

Evet. CaptchaAI, yük testi için paralel reCAPTCHA çözümünü yönetir. Simüle edilen her öğrenci oturumu için aynı anda birden fazla çözüm isteği gönderin.

İlgili Makaleler

Sonraki Adımlar

Test kayıt sistemleri uçtan uca —CaptchaAI API anahtarınızı alınve üniversite portalı CAPTCHA'larını test paketinizde yönetin.

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