GeeTest v3 không phải captcha ảnh tĩnh: người dùng phải kéo mảnh ghép, chọn đúng icon hoặc ghép từ, và mỗi lần trang tải lại hệ thống sinh ra một challenge mới. Muốn giải bằng API, bạn phải trích xuất ba tham số (gt, challenge, api_server) trực tiếp từ trang web trước khi gửi — đây là điểm khác biệt lớn nhất so với reCAPTCHA, vốn chỉ cần sitekey.
Bài viết đi thẳng vào quy trình 4 bước: trích xuất tham số → gửi task → polling res.php → dùng kết quả, kèm code Python và Node.js chạy được ngay. Đây cũng là luồng nhiều đội QA outsourcing ở TP.HCM và Hà Nội dùng để kiểm thử form đăng nhập, checkout trên staging của ứng dụng thương mại điện tử gắn GeeTest v3, trước khi đưa build lên production.
Yêu cầu
Trước khi bắt đầu, bạn cần:
- API key CaptchaAI — lấy tại captchaai.com
- Giá trị GeeTest
gt— định danh tĩnh, cố định theo từng trang web - GeeTest
challenge— giá trị động, đổi theo mỗi phiên - URL trang nơi GeeTest hiển thị
- Python 3.7+ hoặc Node.js 14+
Bước 1: trích xuất tham số GeeTest
GeeTest cần ba tham số. gt cố định cho mọi request, còn challenge đổi theo từng phiên làm việc — nên bạn phải lấy challenge mới trước mỗi lần giải.
Cách 1 — tab Network:
| Bước | Thao tác |
|---|---|
| 1 | Mở DevTools → tab Network |
| 2 | Lọc theo register-slide, gettype.php hoặc get.php |
| 3 | Kích hoạt captcha trên trang và tìm request khởi tạo |
| 4 | Response trả về gt, challenge, và đôi khi cả api_server |
{
"success": 1,
"gt": "019924a82c70bb123aae90d483087f94",
"challenge": "12345678abc90def12345678abc90def",
"new_captcha": true
}
Cách 2 — đọc mã nguồn trang:
// Search page source for initGeetest or gt value
document.querySelectorAll('script').forEach(s => {
if (s.textContent.includes('initGeetest')) {
console.log(s.textContent);
}
});
Cách 3 — endpoint API riêng của trang:
Nhiều trang web tự lấy tham số GeeTest từ API riêng của họ:
# The site's registration endpoint
params_response = requests.get("https://example.com/api/captcha/register")
data = params_response.json()
gt = data["gt"]
challenge = data["challenge"]
Bước 2: gửi task tới CaptchaAI
Python:
import requests
import time
API_KEY = "YOUR_API_KEY"
response = requests.get("https://ocr.captchaai.com/in.php", params={
"key": API_KEY,
"method": "geetest",
"gt": "019924a82c70bb123aae90d483087f94",
"challenge": "12345678abc90def12345678abc90def",
"api_server": "api.geetest.com", # Optional, use if site specifies
"pageurl": "https://staging.example.com/qa-login",
"json": 1
})
data = response.json()
if data.get("status") != 1:
raise Exception(f"Submit error: {data.get('request')}")
task_id = data["request"]
print(f"Task submitted: {task_id}")
Node.js:
const axios = require('axios');
const API_KEY = 'YOUR_API_KEY';
async function submitGeeTest(gt, challenge, pageurl) {
const { data } = await axios.get('https://ocr.captchaai.com/in.php', {
params: {
key: API_KEY,
method: 'geetest',
gt,
challenge,
api_server: 'api.geetest.com',
pageurl,
json: 1
}
});
if (data.status !== 1) throw new Error(`Submit error: ${data.request}`);
return data.request;
}
Bước 3: polling để lấy kết quả
- CaptchaAI trả về ba giá trị khi giải xong:
challenge,validatevàseccode - Cứ mỗi 5 giây, bạn gọi lại
res.phpđể hỏi kết quả cho đến khi có phản hồi — đây là polling (chủ động hỏi định kỳ), không phải bỏ phiếu
Python:
def get_geetest_solution(task_id):
for attempt in range(30):
time.sleep(5)
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 Exception(f"Error: {result.get('request')}")
raise Exception("Timeout")
solution = get_geetest_solution(task_id)
# solution = {
# "geetest_challenge": "12345678abc90def12345678abc90def1a",
# "geetest_validate": "abcdef1234567890abcdef1234567890",
# "geetest_seccode": "abcdef1234567890abcdef1234567890|jordan"
# }
Node.js:
async function getGeeTestSolution(taskId) {
for (let i = 0; i < 30; i++) {
await new Promise(r => setTimeout(r, 5000));
const { data } = await axios.get('https://ocr.captchaai.com/res.php', {
params: { key: API_KEY, action: 'get', id: taskId, json: 1 }
});
if (data.status === 1) return data.request;
if (data.request !== 'CAPCHA_NOT_READY') throw new Error(data.request);
}
throw new Error('Timeout');
}
Bước 4: gửi kết quả về trang đích
- Gộp
geetest_challenge,geetest_validate,geetest_seccodecùng dữ liệu form đăng nhập - Gửi request
POSTchứa cả ba giá trị tới endpoint xác thực của trang web
# Submit the GeeTest solution with the form data
verify_response = requests.post("https://example.com/api/login", data={
"username": "[email protected]",
"password": "password123",
"geetest_challenge": solution["geetest_challenge"],
"geetest_validate": solution["geetest_validate"],
"geetest_seccode": solution["geetest_seccode"]
})
print(f"Login status: {verify_response.status_code}")
Ví dụ Python đầy đủ
import requests
import time
API_KEY = "YOUR_API_KEY"
SITE_URL = "https://staging.example.com/qa-login"
# 1. Get GeeTest parameters from the site
params = requests.get("https://example.com/api/captcha/register").json()
# 2. Submit to CaptchaAI
submit = requests.get("https://ocr.captchaai.com/in.php", params={
"key": API_KEY,
"method": "geetest",
"gt": params["gt"],
"challenge": params["challenge"],
"pageurl": SITE_URL,
"json": 1
}).json()
task_id = submit["request"]
# 3. Poll for solution
for _ in range(30):
time.sleep(5)
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:
solution = result["request"]
break
# 4. Submit to site
login = requests.post(SITE_URL, data={
"username": "[email protected]",
"password": "pass",
"geetest_challenge": solution["geetest_challenge"],
"geetest_validate": solution["geetest_validate"],
"geetest_seccode": solution["geetest_seccode"]
})
print(f"Result: {login.status_code}")
Khắc phục sự cố
ERROR_BAD_PARAMETERS— thiếugthoặcchallenge, trích xuất lại từ trangERROR_CAPTCHA_UNSOLVABLE— challenge hết hạn hoặc không hợp lệ, lấy challenge mới- Trang web từ chối kết quả — challenge cũ chỉ dùng một lần, lấy mới cho mỗi lần thử
geetest_validaterỗng — giải thất bại phía CaptchaAI, thử lại với challenge mới
Ví dụ đầy đủ chạy được ngay
Cần một dự án chạy được ngay, có sẵn thiết lập môi trường, polling, retry và xử lý lỗi?
Câu hỏi thường gặp
CaptchaAI có giải được GeeTest v4 không?
Chưa. GeeTest v4 dùng giao thức xác minh khác hoàn toàn so với v3, và CaptchaAI hiện chưa hỗ trợ — tính năng này đang trong lộ trình "sắp ra mắt". Nếu trang web bạn cần test đã nâng cấp lên v4, quy trình trong bài này chưa áp dụng được.
api_server dùng để làm gì và khi nào cần khai báo?
Tham số này chỉ định máy chủ GeeTest xử lý xác minh, phổ biến nhất là api.geetest.com hoặc api-na.geetest.com. Chỉ cần khai báo khi trang web dùng máy chủ tùy chỉnh khác với mặc định; nếu không chắc, bỏ trống và CaptchaAI vẫn xử lý được ở hầu hết trường hợp.
Giải GeeTest v3 qua CaptchaAI tốn bao nhiêu?
- CaptchaAI tính phí theo thread, không theo từng lần giải
- Gói BASIC ($15/tháng, 5 thread) đủ cho hầu hết dự án kiểm thử tích hợp
- Mỗi thread giải không giới hạn số lần trong tháng, chi phí không tăng theo số request gửi tới
in.php
Vì sao vẫn gặp ERROR_CAPTCHA_UNSOLVABLE dù gt và challenge đã trích xuất đúng?
- Nguyên nhân phổ biến nhất:
challengeđã dùng ở lần thử trước hoặc đã hết hạn, giá trị này chỉ dùng một lần - Luôn lấy
challengemới ngay trước khi gọiin.php, không tái sử dụng giá trị đã log lại
Nên dùng polling hay webhook để lấy kết quả GeeTest?
- Khối lượng nhỏ, script kiểm thử: polling
res.phpnhư trong bài là đủ và dễ triển khai - Hệ thống chạy liên tục, khối lượng lớn: callback (webhook) giảm request thừa vì CaptchaAI tự gửi kết quả về URL của bạn ngay khi giải xong