Hướng Dẫn Thực Hành

Kiểm tra CaptchaAI trước khi di chuyển hoàn toàn: Hướng dẫn chạy song song

Việc chuyển đổi nhà cung cấp CAPTCHA mà không kiểm tra là rất rủi ro. Quá trình chạy song song sẽ gửi đồng thời các thử thách CAPTCHA giống nhau cho cả nhà cung cấp hiện tại của bạn và CaptchaAI, cung cấp cho bạn dữ liệu song song về tốc độ giải quyết, tốc độ và chi phí.

Tại sao thử nghiệm song song lại quan trọng

Điểm chuẩn trên trang tiếp thị không phản ánh kiểu lưu lượng truy cập cụ thể của bạn. CAPTCHA của bạn có các đặc điểm độc đáo — khóa trang web, cấu hình proxy, phân bố địa lý. Thử nghiệm song song cho thấy sự khác biệt thực sự về hiệu suất với khối lượng công việc thực tế của bạn.

Kiến trúc

                    ┌──────────────┐
                    │ Your App     │
                    └──────┬───────┘
                           │
                    ┌──────▼───────┐
                    │ CAPTCHA      │
                    │ Router       │
                    └──┬───────┬───┘
                       │       │
              ┌────────▼──┐ ┌──▼────────┐
              │ Current   │ │ CaptchaAI │
              │ Provider  │ │           │
              └────────┬──┘ └──┬────────┘
                       │       │
                    ┌──▼───────▼──┐
                    │ Metrics     │
                    │ Collector   │
                    └─────────────┘

Triển khai Python

Trừu tượng hóa nhà cung cấp

import os
import time
import requests
from dataclasses import dataclass, field
from typing import Optional
from concurrent.futures import ThreadPoolExecutor

@dataclass
class SolveResult:
    provider: str
    success: bool
    solution: Optional[str] = None
    error: Optional[str] = None
    elapsed: float = 0.0
    cost: float = 0.0

class CaptchaProvider:
    def __init__(self, name, submit_url, result_url, api_key):
        self.name = name
        self.submit_url = submit_url
        self.result_url = result_url
        self.api_key = api_key
        self.session = requests.Session()

    def solve_recaptcha(self, sitekey, pageurl):
        start = time.time()

        resp = self.session.post(self.submit_url, data={
            "key": self.api_key,
            "method": "userrecaptcha",
            "googlekey": sitekey,
            "pageurl": pageurl,
            "json": 1
        })
        data = resp.json()
        if data.get("status") != 1:
            return SolveResult(
                provider=self.name, success=False,
                error=data.get("request"), elapsed=time.time() - start
            )

        captcha_id = data["request"]

        for _ in range(60):
            time.sleep(5)
            result = self.session.get(self.result_url, params={
                "key": self.api_key, "action": "get",
                "id": captcha_id, "json": 1
            }).json()

            if result.get("status") == 1:
                return SolveResult(
                    provider=self.name, success=True,
                    solution=result["request"], elapsed=time.time() - start
                )
            if result.get("request") != "CAPCHA_NOT_READY":
                return SolveResult(
                    provider=self.name, success=False,
                    error=result.get("request"), elapsed=time.time() - start
                )

        return SolveResult(
            provider=self.name, success=False,
            error="TIMEOUT", elapsed=time.time() - start
        )

Người chạy song song

class ParallelTestRunner:
    def __init__(self, primary, challenger):
        self.primary = primary
        self.challenger = challenger
        self.results = {"primary": [], "challenger": []}

    def run_test(self, sitekey, pageurl, num_runs=20):
        print(f"Running {num_runs} parallel solves...")

        for i in range(num_runs):
            with ThreadPoolExecutor(max_workers=2) as executor:
                primary_future = executor.submit(
                    self.primary.solve_recaptcha, sitekey, pageurl
                )
                challenger_future = executor.submit(
                    self.challenger.solve_recaptcha, sitekey, pageurl
                )

                primary_result = primary_future.result()
                challenger_result = challenger_future.result()

            self.results["primary"].append(primary_result)
            self.results["challenger"].append(challenger_result)

            print(f"  Run {i+1}/{num_runs}: "
                  f"{self.primary.name}={'OK' if primary_result.success else 'FAIL'} "
                  f"({primary_result.elapsed:.1f}s) | "
                  f"{self.challenger.name}={'OK' if challenger_result.success else 'FAIL'} "
                  f"({challenger_result.elapsed:.1f}s)")

        return self.generate_report()

    def generate_report(self):
        report = {}
        for label, results in self.results.items():
            total = len(results)
            successes = sum(1 for r in results if r.success)
            times = [r.elapsed for r in results if r.success]
            errors = [r.error for r in results if not r.success]

            report[label] = {
                "provider": results[0].provider if results else "unknown",
                "total": total,
                "successes": successes,
                "success_rate": (successes / total * 100) if total else 0,
                "avg_time": sum(times) / len(times) if times else 0,
                "min_time": min(times) if times else 0,
                "max_time": max(times) if times else 0,
                "errors": errors
            }

        return report

# Usage
current = CaptchaProvider(
    name="CurrentProvider",
    submit_url="https://current-provider.com/in.php",
    result_url="https://current-provider.com/res.php",
    api_key="current_key"
)

captchaai = CaptchaProvider(
    name="CaptchaAI",
    submit_url="https://ocr.captchaai.com/in.php",
    result_url="https://ocr.captchaai.com/res.php",
    api_key=os.environ["CAPTCHAAI_API_KEY"]
)

runner = ParallelTestRunner(primary=current, challenger=captchaai)
report = runner.run_test(
    sitekey="6Le-wvkSAAAAAPBMRTvw0Q4Muexq9bi0DJwx_mJ-",
    pageurl="https://example.com/form",
    num_runs=20
)

for label, stats in report.items():
    print(f"\n{stats['provider']}:")
    print(f"  Success rate: {stats['success_rate']:.1f}%")
    print(f"  Avg time: {stats['avg_time']:.1f}s")
    print(f"  Min/Max: {stats['min_time']:.1f}s / {stats['max_time']:.1f}s")
    if stats['errors']:
        print(f"  Errors: {stats['errors']}")

Chia lưu lượng truy cập

Để sản xuất, hãy định tuyến phần trăm lưu lượng truy cập đến CaptchaAI:

import random

class TrafficSplitter:
    def __init__(self, primary, challenger, challenger_pct=10):
        self.primary = primary
        self.challenger = challenger
        self.challenger_pct = challenger_pct

    def solve(self, sitekey, pageurl):
        if random.randint(1, 100) <= self.challenger_pct:
            result = self.challenger.solve_recaptcha(sitekey, pageurl)
            if not result.success:
                # Fall back to primary on failure
                return self.primary.solve_recaptcha(sitekey, pageurl)
            return result
        return self.primary.solve_recaptcha(sitekey, pageurl)

# Start with 10%, increase as confidence builds
splitter = TrafficSplitter(current, captchaai, challenger_pct=10)
result = splitter.solve(sitekey="...", pageurl="...")

Triển khai JavaScript

const axios = require("axios");

class CaptchaProvider {
  constructor(name, submitUrl, resultUrl, apiKey) {
    this.name = name;
    this.submitUrl = submitUrl;
    this.resultUrl = resultUrl;
    this.apiKey = apiKey;
  }

  async solveRecaptcha(sitekey, pageurl) {
    const start = Date.now();
    try {
      const submit = await axios.post(this.submitUrl, null, {
        params: { key: this.apiKey, method: "userrecaptcha", googlekey: sitekey, pageurl, json: 1 },
      });
      if (submit.data.status !== 1) {
        return { provider: this.name, success: false, error: submit.data.request, elapsed: (Date.now() - start) / 1000 };
      }

      const captchaId = submit.data.request;
      for (let i = 0; i < 60; i++) {
        await new Promise((r) => setTimeout(r, 5000));
        const poll = await axios.get(this.resultUrl, {
          params: { key: this.apiKey, action: "get", id: captchaId, json: 1 },
        });
        if (poll.data.status === 1) {
          return { provider: this.name, success: true, solution: poll.data.request, elapsed: (Date.now() - start) / 1000 };
        }
        if (poll.data.request !== "CAPCHA_NOT_READY") {
          return { provider: this.name, success: false, error: poll.data.request, elapsed: (Date.now() - start) / 1000 };
        }
      }
      return { provider: this.name, success: false, error: "TIMEOUT", elapsed: (Date.now() - start) / 1000 };
    } catch (err) {
      return { provider: this.name, success: false, error: err.message, elapsed: (Date.now() - start) / 1000 };
    }
  }
}

async function parallelTest(current, captchaai, sitekey, pageurl, runs = 20) {
  const results = { current: [], captchaai: [] };

  for (let i = 0; i < runs; i++) {
    const [currentResult, captchaaiResult] = await Promise.all([
      current.solveRecaptcha(sitekey, pageurl),
      captchaai.solveRecaptcha(sitekey, pageurl),
    ]);

    results.current.push(currentResult);
    results.captchaai.push(captchaaiResult);

    console.log(`Run ${i + 1}/${runs}: ${current.name}=${currentResult.success ? "OK" : "FAIL"} ` +
      `(${currentResult.elapsed.toFixed(1)}s) | ${captchaai.name}=${captchaaiResult.success ? "OK" : "FAIL"} ` +
      `(${captchaaiResult.elapsed.toFixed(1)}s)`);
  }

  for (const [label, data] of Object.entries(results)) {
    const successes = data.filter((r) => r.success).length;
    const times = data.filter((r) => r.success).map((r) => r.elapsed);
    const avgTime = times.length ? times.reduce((a, b) => a + b, 0) / times.length : 0;
    console.log(`\n${label}: ${successes}/${runs} success (${((successes / runs) * 100).toFixed(1)}%), avg ${avgTime.toFixed(1)}s`);
  }
}

// Run
const currentProvider = new CaptchaProvider("CurrentProvider", "https://current-provider.com/in.php", "https://current-provider.com/res.php", "current_key");
const captchaai = new CaptchaProvider("CaptchaAI", "https://ocr.captchaai.com/in.php", "https://ocr.captchaai.com/res.php", process.env.CAPTCHAAI_API_KEY);

parallelTest(currentProvider, captchaai, "SITE_KEY", "https://example.com", 20);

Kế hoạch kiểm tra được đề xuất

Giai đoạn Thời lượng Phân chia lưu lượng truy cập Mục tiêu
1. Xác thực 1 ngày 0% trực tiếp, chỉ song song Xác minh khả năng tương thích API
2. Kiểm tra bóng 3 ngày 5% cho CaptchaAI (có dự phòng) Thu thập số liệu cơ bản
3. Tăng tốc 1 tuần 25% -> 50% -> 75% Giám sát ở mỗi cấp độ
4. Cắt bỏ toàn bộ 100% CaptchaAI Ngừng hoạt động nhà cung cấp cũ

Số liệu để so sánh

Số liệu Cách đo
Tỷ lệ thành công successful_solves / total_attempts × 100
Thời gian giải quyết trung bình Thời gian từ khi gửi đến khi nhận được giải pháp
P95 giải quyết thời gian Phân vị thứ 95 của số lần giải
Tỷ lệ lỗi theo loại Đếm riêng từng mã lỗi
Chi phí cho mỗi lần giải quyết Tổng chi tiêu/giải quyết thành công
Hiệu lực của mã thông báo Mã thông báo được trả về có thực sự hoạt động trên trang đích không?

Khắc phục sự cố

Vấn đề Nguyên nhân Cách xử lý
CaptchaAI chậm hơn trong thử nghiệm song song Sự khác biệt về độ trễ mạng Kiểm tra từ máy chủ sản xuất, không phải máy cục bộ
Tỷ lệ thành công khác nhau Nhóm bộ giải của nhà cung cấp khác nhau Chạy 50+ giải quyết ý nghĩa thống kê
Các giải pháp hoạt động trên một nhà cung cấp nhưng không hoạt động trên nhà cung cấp khác Thời gian hết hạn mã thông báo Sử dụng token ngay sau khi nhận được chúng
Thử nghiệm song song tăng gấp đôi chi phí Giải cùng một CAPTCHA hai lần Ngân sách cho giai đoạn thử nghiệm; nó rẻ hơn so với việc di chuyển thất bại

Câu hỏi thường gặp

Tôi cần bao nhiêu lần chạy thử để có dữ liệu đáng tin cậy?

Tối thiểu 50 giải pháp cho mỗi nhà cung cấp. Để có kết quả có ý nghĩa thống kê, hãy chạy hơn 100 phép giải vào các thời điểm khác nhau trong ngày để tính phương sai.

Tôi nên kiểm tra bằng proxy hay proxyless?

Kiểm tra cả hai nếu bạn sử dụng cả hai trong sản xuất. Chất lượng proxy ảnh hưởng đến tỷ lệ giải quyết khác nhau giữa các nhà cung cấp – hãy kiểm tra cấu hình proxy thực tế của bạn.

Điều gì sẽ xảy ra nếu CaptchaAI hoạt động kém hơn trên một loại CAPTCHA?

Chạy thử nghiệm theo từng loại cụ thể. Nhà cung cấp có thể vượt trội ở reCAPTCHA nhưng lại tụt hậu ở hCaptcha. Nếu bạn sử dụng nhiều loại, trọng số sẽ được tính theo phân bổ lưu lượng truy cập thực tế của bạn.

bài viết liên quan

Các bước tiếp theo

Bắt đầu thử nghiệm song song không có rủi ro –tạo tài khoản CaptchaAI của bạnvà so sánh hiệu suất với dữ liệu thực.

Hướng dẫn liên quan:

Os comentários estão desativados para este artigo.