API CaptchaAI trả token trong vài giây, nhưng phần lớn độ trễ log không đến từ bộ giải — mà từ cách gửi request, polling và cấu hình proxy. Một lần giải đi qua bốn chặng: gửi task, chờ hàng đợi, bộ giải xử lý, lấy kết quả.
- Không đổi được: thời gian bộ giải xử lý.
- Đổi được: request, tần suất polling, có dùng callback hay không.
Độ trễ chuẩn theo từng loại CAPTCHA
| Loại CAPTCHA | Giới hạn theo SLA | Thực tế đạt được sau tối ưu |
|---|---|---|
| Hình ảnh/OCR | <0,5 giây | 0,2–0,4 giây |
| reCAPTCHA v2 | <60 giây | 10–20 giây |
| reCAPTCHA v3 | <4 giây | 1–3 giây |
| Cloudflare Turnstile | <10 giây | 4–8 giây |
| GeeTest v3 | <12 giây | 6–10 giây |
Cột "thực tế đạt được sau tối ưu" là kết quả đo được, không phải cam kết cho mọi trang đích.
1. Giảm độ trễ bằng polling thích ứng
Khoảng polling (chủ động hỏi kết quả định kỳ) mặc định 5 giây lãng phí thời gian nếu bộ giải xong sau 2 giây. Dùng polling thích ứng — hỏi dồn dập lúc đầu, rồi giãn ra:
Python
import time
import requests
API_KEY = "YOUR_API_KEY"
RESULT_URL = "https://ocr.captchaai.com/res.php"
def adaptive_poll(task_id, timeout=120):
"""Start polling at 3s, increase to 5s after 4 polls."""
start = time.time()
interval = 3 # start aggressive
polls = 0
while time.time() - start < timeout:
time.sleep(interval)
polls += 1
resp = requests.get(RESULT_URL, params={
"key": API_KEY, "action": "get",
"id": task_id, "json": "1"
}).json()
if resp["status"] == 1:
elapsed = time.time() - start
print(f"Solved in {elapsed:.1f}s ({polls} polls)")
return resp["request"]
if resp["request"] != "CAPCHA_NOT_READY":
raise Exception(resp["request"])
# Back off after initial fast polls
if polls >= 4:
interval = 5
raise TimeoutError(f"Task {task_id} timed out")
JavaScript
async function adaptivePoll(taskId, apiKey, timeout = 120000) {
const start = Date.now();
let interval = 3000;
let polls = 0;
while (Date.now() - start < timeout) {
await new Promise(r => setTimeout(r, interval));
polls++;
const resp = await fetch(
`https://ocr.captchaai.com/res.php?key=${apiKey}&action=get&id=${taskId}&json=1`
);
const data = await resp.json();
if (data.status === 1) {
console.log(`Solved in ${((Date.now() - start) / 1000).toFixed(1)}s (${polls} polls)`);
return data.request;
}
if (data.request !== 'CAPCHA_NOT_READY') {
throw new Error(data.request);
}
if (polls >= 4) interval = 5000;
}
throw new Error(`Task ${taskId} timed out`);
}
So với khoảng cố định 5 giây:
- Tiết kiệm trung bình 1–4 giây/lần.
- Không tốn request thừa khi giải xong sớm.
2. Tái sử dụng kết nối HTTP (connection pooling)
Mở kết nối TCP/TLS mới cho mỗi lần polling tốn bắt tay không cần thiết. Dùng lại kết nối HTTP thay vì mở mới:
Python
session = requests.Session()
# Use session.get() and session.post() instead of requests.get/post
# The session reuses TCP connections automatically
JavaScript (Node.js)
const { Agent } = require('http');
const axios = require('axios');
const client = axios.create({
httpAgent: new Agent({ keepAlive: true, maxSockets: 10 }),
timeout: 10000,
});
// Use client.get() and client.post() for all API calls
- Tiết kiệm ~50–100 mili giây/request nhờ bỏ qua bắt tay TCP/TLS.
- Đáng làm nhất khi polling nhiều lần cho cùng một task.
3. Gửi trước CAPTCHA cho trang kế tiếp (prefetch)
Gửi task trước khi thực sự cần token. Trong lúc xử lý trang N, gửi luôn CAPTCHA của trang N+1:
from concurrent.futures import ThreadPoolExecutor
SUBMIT_URL = "https://ocr.captchaai.com/in.php"
def prefetch_submit(sitekey, page_url):
resp = session.post(SUBMIT_URL, data={
"key": API_KEY,
"method": "userrecaptcha",
"googlekey": sitekey,
"pageurl": page_url,
"json": "1",
})
data = resp.json()
if data["status"] == 1:
return data["request"]
raise Exception(data["request"])
# Submit next page's CAPTCHA while processing current page
with ThreadPoolExecutor(max_workers=2) as pool:
# Submit CAPTCHA for page 2 while processing page 1
future_task = pool.submit(prefetch_submit, "6Le-SITEKEY", "https://example.com/page/2")
# Process page 1...
process_page(current_data)
# Now get the pre-submitted task ID and poll
task_id = future_task.result()
token = adaptive_poll(task_id)
Cách này gần như xóa sổ thời gian chờ vì việc giải diễn ra song song với lúc xử lý trang hiện tại, miễn là:
- Biết trước sitekey và URL trang kế tiếp.
- Bước xử lý đủ dài để "che" hết thời gian giải.
Ví dụ: đội scraping theo dõi giá sàn thương mại điện tử
Một đội tại TP.HCM theo dõi giá Shopee và Lazada mỗi giờ cho hàng chục nghìn SKU. Trước khi dùng prefetch, mỗi trang tốn thêm chục giây chờ token; sau khi đổi sang gửi task song song, thời gian chờ gần như biến mất khỏi batch.
4. Chọn đúng phương thức cho từng tình huống
CaptchaAI đôi khi có phương thức nhanh hơn:
| Tình huống | Cách chậm | Cách nhanh hơn |
|---|---|---|
| reCAPTCHA v2 đã biết trước callback URL | userrecaptcha + polling |
userrecaptcha kèm pingback |
| CAPTCHA chữ/số dạng ảnh | base64 độ phân giải cao |
base64 kèm numeric=1 |
- Xem tài liệu API trước khi tối ưu polling thủ công.
5. Chỉ dùng proxy khi thực sự cần
Định tuyến qua proxy luôn cộng thêm độ trễ. Chỉ gửi tham số này khi trang đích yêu cầu IP cụ thể:
# Without proxy — faster for most use cases
data = {
"key": API_KEY,
"method": "userrecaptcha",
"googlekey": sitekey,
"pageurl": page_url,
"json": "1",
}
# With proxy — only when required
data["proxy"] = "user:[email protected]:8080"
data["proxytype"] = "HTTP"
- Vẫn cần proxy khi trang đích chặn theo khu vực hoặc giới hạn theo IP.
6. Dùng callback (pingback) thay vì polling
Xóa hẳn vòng lặp polling bằng tham số pingback:
resp = session.post(SUBMIT_URL, data={
"key": API_KEY,
"method": "userrecaptcha",
"googlekey": sitekey,
"pageurl": page_url,
"json": "1",
"pingback": "https://your-server.com/captcha-callback",
})
CaptchaAI tự gửi kết quả về URL của bạn ngay khi giải xong — không cần vòng polling nào cả.
7. Đo lại hiệu quả bằng benchmark
Đừng đoán mức cải thiện — đo lại sau khi áp dụng các thay đổi trên:
import statistics
def benchmark(solve_func, iterations=20):
times = []
for i in range(iterations):
start = time.time()
try:
solve_func()
times.append(time.time() - start)
except Exception:
pass
if times:
print(f"Samples: {len(times)}/{iterations}")
print(f"Mean: {statistics.mean(times):.1f}s")
print(f"Median: {statistics.median(times):.1f}s")
print(f"P95: {sorted(times)[int(len(times)*0.95)]:.1f}s")
print(f"Min: {min(times):.1f}s")
print(f"Max: {max(times):.1f}s")
Xử lý sự cố thường gặp
Kiểm tra bốn nguyên nhân này trước:
| Vấn đề | Nguyên nhân | Cách xử lý |
|---|---|---|
| Độ trễ polling không đổi | Vẫn dùng requests.get() không qua session |
Chuyển sang session.get() |
| Token prefetch hết hạn trước khi dùng | Bước xử lý phía sau mất quá lâu | Rút ngắn thời gian prefetch |
| Callback URL không nhận được dữ liệu | Server không truy cập được từ CaptchaAI | Đảm bảo URL public, đúng rule firewall |
| Polling dày hơn lại bị rate limit | Gọi API quá dồn dập (dưới 2 giây/lần) | Giữ khoảng polling tối thiểu 3 giây |
Nếu vẫn chậm sau khi kiểm tra cả bốn, khả năng cao nghẽn ở scraper, không phải ở API.
Câu hỏi thường gặp
Tối ưu nào tiết kiệm độ trễ nhiều nhất?
Prefetch. Nó chồng thời gian giải lên thời gian xử lý trang hiện tại, nên độ trễ gần như biến mất khỏi luồng tuần tự.
Nên polling hay dùng callback cho hệ thống production?
Dùng cả hai: pingback là đường chính, polling dãn cách dài là phương án dự phòng khi callback bị lỡ.
Proxy có luôn làm chậm request tới CaptchaAI không?
Có thêm chút độ trễ, không đáng kể nếu proxy ổn định. Vấn đề thường là gửi proxy cho trang không cần — bỏ tham số này là cách tối ưu rẻ nhất trong bài.
Polling thích ứng có giúp ích cho CAPTCHA hình ảnh không?
Ít thôi. Ảnh/OCR giải xong dưới nửa giây nên lần polling đầu ở giây thứ 3 đã kịp bắt kết quả. Cải thiện rõ hơn với reCAPTCHA v2 (SLA tới 60 giây).
Bắt đầu tối ưu API CaptchaAI
- Lấy API key tại captchaai.com.
- Áp dụng polling thích ứng hoặc callback ngay trong lần gọi API tiếp theo.