Trường Hợp Sử Dụng

Giám sát vé sự kiện bằng cách xử lý CAPTCHA

Muốn biết ngay khi vé còn trống mà không phải ngồi bấm F5 cả buổi? Vấn đề không nằm ở tốc độ mạng, mà ở chỗ gần như mọi nền tảng bán vé — concert, thể thao, sân khấu — đặt reCAPTCHA hoặc Cloudflare Turnstile trước mỗi lần kiểm tra tình trạng vé, cộng thêm giới hạn tần suất request.

Script quét thủ công sẽ dừng ngay tại bước CAPTCHA đầu tiên. Bài này dựng một bộ giám sát vé bằng Python: tự phát hiện CAPTCHA, gửi sang CaptchaAI để giải, rồi so sánh trạng thái để chỉ báo động khi có thay đổi thật.


Luồng giám sát: kiểm tra → giải CAPTCHA → cảnh báo

Configure events → Check availability → CAPTCHA?
                                           ↓ Yes
                                      Solve via CaptchaAI → Retry
                                           ↓ No
                                      Parse availability → Changed?
                                                             ↓ Yes
                                                         Send alert

Script chỉ đọc dữ liệu tình trạng vé công khai và gửi cảnh báo — không tự động điền form thanh toán hay bấm mua thay bạn.


Ai thường triển khai kịch bản này

Ở Việt Nam, dạng script này phổ biến trong các đội automation/QA làm dịch vụ outsourcing cho khách hàng quốc tế — theo dõi vé các tour lưu diễn K-pop, NBA, giải bóng đá châu Âu bán qua các nền tảng như Ticketmaster hay SeatGeek. Yêu cầu vận hành thường giống nhau: chạy nền 24/7, tự xử lý CAPTCHA, và chỉ cảnh báo khi trạng thái vé thực sự đổi để nhóm không phải canh log liên tục.

CAPTCHA nào CaptchaAI xử lý được trên trang bán vé

  • reCAPTCHA v2, v2 Invisible, v3 — loại phổ biến nhất trên các trang bán vé lớn.
  • Cloudflare Turnstile và Cloudflare Challenge — thường gặp trên các trang dùng Cloudflare để chống bot.
  • GeeTest v3 — một số nền tảng khu vực dùng loại này.
  • hCaptcha, FunCaptcha (Arkose Labs) — ❌ chưa được hỗ trợ; nếu trang bạn theo dõi dùng hCaptcha, script bên dưới sẽ cần một hướng xử lý khác.

Chi phí ước tính theo mức độ giám sát

Quy mô giám sát Gói phù hợp Thread Giá
Vài sự kiện, kiểm tra mỗi 15–30 phút BASIC 5 $15/tháng
Vài chục sự kiện song song STANDARD 15 $30/tháng
Nhiều sự kiện, tần suất cao (2–5 phút) ADVANCE 50 $90/tháng

Mỗi thread giải không giới hạn số CAPTCHA trong tháng — chi phí tăng theo số lượng kiểm tra đồng thời, không theo tổng số lần giải.


Cần chuẩn bị gì trước khi code

Yêu cầu Chi tiết
Khóa API CaptchaAI captchaai.com
Python 3.8+ Với requests
Proxy đa dạng nguồn yêu cầu được đề xuất

Cài thư viện

pip install requests

Hàm giải CAPTCHA dùng chung

Hàm dưới đây gửi task tới in.php, chờ khoảng thời gian khởi tạo phù hợp với từng loại, rồi polling res.php cho tới khi có token — dùng lại được cho cả reCAPTCHA lẫn Turnstile:

import requests
import time

API_KEY = "YOUR_API_KEY"

def solve_captcha(method, params):
    """Generic CaptchaAI solver for any supported method."""
    params["key"] = API_KEY
    params["json"] = 1

    submit = requests.post("https://ocr.captchaai.com/in.php", data=params).json()

    if submit.get("status") != 1:
        raise RuntimeError(f"Submit error: {submit.get('request')}")

    task_id = submit["request"]
    initial_wait = 10 if method == "turnstile" else 20
    time.sleep(initial_wait)

    for _ in range(30):
        result = requests.get("https://ocr.captchaai.com/res.php", params={
            "key": API_KEY, "action": "get", "id": task_id, "json": 1
        }).json()
        if result.get("status") == 1:
            return result["request"]
        if result.get("request") != "CAPCHA_NOT_READY":
            raise RuntimeError(f"Solve error: {result['request']}")
        time.sleep(5)
    raise TimeoutError("Solve timed out")

Class TicketMonitor: kiểm tra, giải CAPTCHA, so sánh trạng thái

TicketMonitor gói toàn bộ luồng: mở phiên có proxy tuỳ chọn, phát hiện reCAPTCHA hoặc Turnstile trên trang, gọi solve_captcha ở trên để lấy token, gửi lại request với token đó, rồi so sánh kết quả với lần kiểm tra trước để quyết định có cảnh báo hay không:

from datetime import datetime
import json

class TicketMonitor:
    def __init__(self, proxy=None):
        self.session = requests.Session()
        self.session.headers.update({
            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
        })
        if proxy:
            self.session.proxies = {
                "http": f"http://{proxy}",
                "https": f"http://{proxy}"
            }
        self.last_status = {}

    def check_event(self, event):
        """Check ticket availability for an event, solving CAPTCHAs if needed."""
        url = event["url"]
        response = self.session.get(url)

        # Handle CAPTCHA if detected
        if "g-recaptcha" in response.text or "recaptcha" in response.text:
            sitekey = self._extract_sitekey(response.text)
            if sitekey:
                token = solve_captcha("userrecaptcha", {
                    "method": "userrecaptcha",
                    "googlekey": sitekey,
                    "pageurl": url
                })
                response = self.session.post(url, data={
                    "g-recaptcha-response": token
                })

        elif "cf-turnstile" in response.text:
            sitekey = self._extract_turnstile_key(response.text)
            if sitekey:
                token = solve_captcha("turnstile", {
                    "method": "turnstile",
                    "sitekey": sitekey,
                    "pageurl": url
                })
                response = self.session.post(url, data={
                    "cf-turnstile-response": token
                })

        # Parse availability
        availability = self._parse_availability(response.text, event)

        # Check for changes
        event_key = event["name"]
        if event_key in self.last_status:
            if availability != self.last_status[event_key]:
                self._send_alert(event, availability)

        self.last_status[event_key] = availability
        return availability

    def _extract_sitekey(self, html):
        if 'data-sitekey="' in html:
            start = html.index('data-sitekey="') + 14
            end = html.index('"', start)
            return html[start:end]
        return None

    def _extract_turnstile_key(self, html):
        if 'data-sitekey="' in html:
            start = html.index('data-sitekey="') + 14
            end = html.index('"', start)
            return html[start:end]
        return None

    def _parse_availability(self, html, event):
        """Parse ticket availability. Customize per ticketing site."""
        available = "sold out" not in html.lower()
        return {
            "event": event["name"],
            "available": available,
            "checked_at": datetime.now().isoformat()
        }

    def _send_alert(self, event, availability):
        """Send availability change notification."""
        status = "AVAILABLE" if availability["available"] else "SOLD OUT"
        print(f"[ALERT] {event['name']}: {status}")

    def monitor_all(self, events):
        """Check all events and return results."""
        results = []
        for event in events:
            try:
                result = self.check_event(event)
                results.append(result)
                print(f"[OK] {event['name']}: {'available' if result['available'] else 'sold out'}")
            except Exception as e:
                print(f"[ERROR] {event['name']}: {e}")
        return results

# Usage
events = [
    {
        "name": "Concert - Madison Square Garden - Aug 15",
        "url": "https://example-tickets.com/event/12345"
    },
    {
        "name": "Basketball Finals - Game 7",
        "url": "https://example-tickets.com/event/67890"
    }
]

monitor = TicketMonitor(proxy="user:[email protected]:8080")
results = monitor.monitor_all(events)

for r in results:
    print(json.dumps(r, indent=2))

Chạy thử với hai sự kiện mẫu, bạn sẽ thấy kết quả dạng:

[OK] Concert - Madison Square Garden - Aug 15: available
[OK] Basketball Finals - Game 7: sold out

Lên lịch chạy tự động bằng cron

Đặt script chạy nền theo chu kỳ cố định thay vì gọi thủ công:

# Check every 15 minutes
*/15 * * * * cd /path/to/project && python ticket_monitor.py >> /var/log/tickets.log 2>&1

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

Giám sát vé sự kiện tốn bao nhiêu chi phí CaptchaAI mỗi tháng?

CaptchaAI tính phí theo thread (số CAPTCHA giải đồng thời), không theo số lần giải — mỗi thread được giải không giới hạn trong tháng. Xem bảng ước tính theo quy mô ở phần trên; hầu hết script giám sát vài chục sự kiện chạy vừa trong gói STANDARD.

Nên đặt tần suất kiểm tra bao lâu một lần?

  • Theo dõi thông thường: 10–30 phút một lần.
  • Sự kiện nhu cầu cao: 2–5 phút một lần, nhưng CAPTCHA sẽ xuất hiện nhiều hơn.
  • Lưu ý: tần suất càng cao, nguy cơ bị chặn IP càng tăng — cân bằng với chi phí thread ở trên.

Script này có tự động mua vé giúp tôi không?

Không. Script trong bài chỉ kiểm tra và cảnh báo khi tình trạng vé đổi, không tự động điền form thanh toán hay bấm mua. Việc mua vé vẫn do bạn thực hiện thủ công sau khi nhận cảnh báo — tự động hóa bước thanh toán nằm ngoài phạm vi bài này và thường vi phạm điều khoản dịch vụ của nền tảng bán vé.

Có bắt buộc dùng đa dạng nguồn yêu cầu (proxy) không?

Gần như có. Trang bán vé chặn IP trung tâm dữ liệu khá tích cực, nên chạy toàn bộ traffic qua một IP cố định sẽ khiến CAPTCHA xuất hiện dày hơn và dễ bị khóa. Đa dạng nguồn yêu cầu giúp giảm tần suất CAPTCHA, nhưng không thay thế được việc giữ phiên và giãn thời gian kiểm tra hợp lý.

Giải CAPTCHA mất bao lâu, có làm chậm việc phát hiện vé không?

Không đáng kể so với chu kỳ kiểm tra 10–30 phút:

  • reCAPTCHA v2: thường giải xong trong dưới 60 giây.
  • Cloudflare Turnstile: dưới 10 giây.
  • Cả hai loại đều có tỷ lệ giải thành công cao trên các loại được hỗ trợ, và vòng lặp polling trong solve_captcha đã tính sẵn thời gian chờ trước khi trả token về cho TicketMonitor.

Xử lý sự cố thường gặp

  • CAPTCHA xuất hiện ở mọi lần kiểm tra — nguyên nhân thường là cùng một IP, không giữ phiên. Dùng lại cookie phiên và đa dạng nguồn yêu cầu.
  • Bị chặn sau vài lần kiểm tra — do giới hạn tần suất request. Giãn khoảng cách giữa các lần kiểm tra và đa dạng nguồn yêu cầu.
  • Tình trạng vé đọc sai — cấu trúc trang đã đổi. Cập nhật lại phương thức _parse_availability cho khớp HTML mới.
  • Giải CAPTCHA chậm — tải trên hàng đợi giải cao vào giờ cao điểm. Thêm logic thử lại kèm thời gian chờ tăng dần (backoff) thay vì fail ngay.

Lấy API key CaptchaAI của bạn

  • Đăng ký tại captchaai.com và lấy API key.
  • Gắn API_KEY vào script ở trên, chạy thử với vài sự kiện mẫu trước khi đưa vào cron.
  • CaptchaAI xử lý phần CAPTCHA, script của bạn chỉ cần tập trung phát hiện thay đổi và gửi cảnh báo.

Bài viết liên quan

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