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ề choTicketMonitor.
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_availabilitycho 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_KEYvà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.