Một số trang web triển khai reCAPTCHA v2 bằng chức năng gọi lại thay vì trường ẩn g-recaptcha-response tiêu chuẩn. Khi bạn giải CAPTCHA và đưa mã thông báo vào trường ẩn, sẽ không có gì xảy ra — trang sẽ bỏ qua nó. Đó là vì trang web yêu cầu bạn gọi một hàm JavaScript bằng mã thông báo thay thế.
Hướng dẫn này chỉ cho bạn cách phát hiện reCAPTCHA v2 dựa trên lệnh gọi lại, giải quyết vấn đề đó thông qua API CaptchaAI và gọi lệnh gọi lại một cách chính xác. Lệnh gọi API giống hệt với reCAPTCHA v2 tiêu chuẩn — chỉ có bước chèn mã thông báo thay đổi.
Mới sử dụng reCAPTCHA v2? Bắt đầu vớiCách giải reCAPTCHA v2 bằng APIđối với quy trình tiêu chuẩn, sau đó quay lại đây để xem biến thể gọi lại.
Những gì bạn cần trước khi bắt đầu
| Yêu cầu | Chi tiết |
|---|---|
| Khóa API CaptchaAI | Nhận một cái từcaptchaai.com/api.php. Chuỗi 32 ký tự. |
| URL trang mục tiêu | URL đầy đủ nơi tiện ích reCAPTCHA v2 tải. |
| Khóa trang web reCAPTCHA v2 | Khóa chung được gắn với phiên bản widget. |
| Công cụ tự động hóa trình duyệt | Selenium, Puppeteer hoặc Playwright — bạn cần thực thi JavaScript để gọi lại lệnh gọi lại. |
| Tên hàm gọi lại | Chức năng JavaScript mà trang web mong đợi nhận được mã thông báo. |
Cách xác định việc triển khai gọi lại
reCAPTCHA v2 tiêu chuẩn ghi mã thông báo đã giải quyết vào vùng văn bản g-recaptcha-response ẩn. Việc triển khai gọi lại bỏ qua điều đó và gọi trực tiếp một hàm JavaScript. Đây là cách để phân biệt.
Cách 1: Kiểm tra thuộc tính data-callback
Kiểm tra div tiện ích reCAPTCHA trong nguồn trang:
<div class="g-recaptcha"
data-sitekey="6Le-wvkSAAAAAPBMRTvw0Q4Muexq9bi0DJwx_mJ-"
data-callback="SubmitToken">
</div>
Nếu data-callback tồn tại, trang web sẽ sử dụng lệnh gọi lại. Giá trị (SubmitToken) là tên hàm bạn cần.
Cách 2: Kiểm tra cuộc gọi grecaptcha.render()
Tìm kiếm grecaptcha.render trong JavaScript của trang:
grecaptcha.render('recaptcha-container', {
sitekey: '6Le-wvkSAAAAAPBMRTvw0Q4Muexq9bi0DJwx_mJ-',
callback: userVerified
});
Thuộc tính callback đặt tên cho hàm. Trong trường hợp này là userVerified.
Phương pháp 3: Kiểm tra cấu hình reCAPTCHA nội bộ
Mở bảng điều khiển trình duyệt trên trang đích và chạy:
___grecaptcha_cfg.clients[0]
Điều hướng cây đối tượng để tìm thuộc tính callback. Đường dẫn chính xác thay đổi tùy theo trang web - có thể là clients[0].aa.l.callback hoặc đường dẫn nào khác tùy thuộc vào phiên bản reCAPTCHA và quá trình rút gọn. Nếu trang có nhiều phiên bản reCAPTCHA, hãy kiểm tra clients[1], clients[2], v.v.
Kịch bản phát hiện nhanh
Chạy cái này trong bảng điều khiển trình duyệt để tự động tìm tên gọi lại:
// Check data-callback attributes
document.querySelectorAll('[data-callback]').forEach(el => {
console.log('data-callback:', el.getAttribute('data-callback'));
});
// Check internal config
if (typeof ___grecaptcha_cfg !== 'undefined') {
Object.keys(___grecaptcha_cfg.clients).forEach(key => {
const client = ___grecaptcha_cfg.clients[key];
console.log(`Client ${key}:`, JSON.stringify(client, null, 2));
});
}
Cách giải quyết cuộc gọi lại khác với v2 tiêu chuẩn
Lệnh gọi API tới CaptchaAI là giống hệt. Sự khác biệt duy nhất là những gì bạn làm với mã thông báo sau khi nhận được nó.
| Bước | Tiêu chuẩn v2 | Gọi lại v2 |
|---|---|---|
| 1. Gửi tới CaptchaAI | method=userrecaptcha + khóa trang web + url trang |
giống nhau |
| 2. Thăm dò kết quả | action=get + ID hình ảnh xác thực |
giống nhau |
| 3. Nhận mã thông báo | Định dạng mã thông báo giống nhau | giống nhau |
| 4. Tiêm mã thông báo | Đặt giá trị trường g-recaptcha-response |
Gọi hàm gọi lại bằng mã thông báo |
| 5. Gửi biểu mẫu | Gửi biểu mẫu kích hoạt | Thường là tự động — cuộc gọi lại xử lý nó |
Quan trọng: Không đặt
g-recaptcha-responsekhi triển khai dựa trên lệnh gọi lại. Trang bỏ qua trường đó và chờ chức năng gọi lại kích hoạt. Việc đặt trường này mà không gọi lại lệnh gọi lại sẽ khiến có vẻ như CAPTCHA chưa bao giờ được giải quyết.
Giải quyết dòng chảy
Page → extract sitekey + pageurl + callback name
↓
POST to in.php (method=userrecaptcha)
↓
receive captcha ID
↓
wait 15–20 seconds
↓
GET res.php (action=get, id=…)
↓ ↓
CAPCHA_NOT_READY status=1 → token
(wait 5s, retry) ↓
invoke callback(token)
↓
site processes token automatically
Triển khai Python (Selenium)
import time
import requests
from selenium import webdriver
from selenium.webdriver.common.by import By
API_KEY = "YOUR_CAPTCHAAI_API_KEY"
SITEKEY = "6Le-wvkSAAAAAPBMRTvw0Q4Muexq9bi0DJwx_mJ-"
PAGE_URL = "https://staging.example.com/qa-login"
CALLBACK_NAME = "SubmitToken" # The callback function name from the page
SUBMIT_URL = "https://ocr.captchaai.com/in.php"
RESULT_URL = "https://ocr.captchaai.com/res.php"
def solve_recaptcha_v2(api_key, sitekey, pageurl):
"""Submit a reCAPTCHA v2 task and return the solved token."""
# Step 1: Submit the captcha
submit_resp = requests.post(
SUBMIT_URL,
data={
"key": api_key,
"method": "userrecaptcha",
"googlekey": sitekey,
"pageurl": pageurl,
"json": 1,
},
timeout=30,
)
submit_resp.raise_for_status()
submit_data = submit_resp.json()
if submit_data.get("status") != 1:
raise RuntimeError(f"Submit failed: {submit_data}")
captcha_id = submit_data["request"]
print(f"Task created — captcha ID: {captcha_id}")
# Step 2: Wait before first poll
time.sleep(15)
# Step 3: Poll for result
for _ in range(60):
result_resp = requests.get(
RESULT_URL,
params={
"key": api_key,
"action": "get",
"id": captcha_id,
"json": 1,
},
timeout=30,
)
result_resp.raise_for_status()
result_data = result_resp.json()
if result_data.get("request") == "CAPCHA_NOT_READY":
time.sleep(5)
continue
if result_data.get("status") == 1:
return result_data["request"]
raise RuntimeError(f"Polling error: {result_data}")
raise TimeoutError("reCAPTCHA v2 solve timed out")
def detect_callback_name(driver):
"""Detect the reCAPTCHA callback function name from the page."""
# Try data-callback attribute first
callback = driver.execute_script("""
const el = document.querySelector('[data-callback]');
if (el) return el.getAttribute('data-callback');
return null;
""")
if callback:
return callback
# Try internal reCAPTCHA config
callback = driver.execute_script("""
if (typeof ___grecaptcha_cfg === 'undefined') return null;
const clients = ___grecaptcha_cfg.clients;
for (const key of Object.keys(clients)) {
const client = clients[key];
// Walk the object tree to find a callback function
const json = JSON.stringify(client);
const match = json.match(/"callback":"(\\w+)"/);
if (match) return match[1];
}
return null;
""")
return callback
# Main workflow
driver = webdriver.Chrome()
driver.get(PAGE_URL)
# Detect the callback name (or use the known name)
detected = detect_callback_name(driver)
callback_name = detected or CALLBACK_NAME
print(f"Using callback: {callback_name}")
# Solve the CAPTCHA
token = solve_recaptcha_v2(API_KEY, SITEKEY, PAGE_URL)
print(f"Solved token: {token[:80]}...")
# Invoke the callback with the token
driver.execute_script(f"{callback_name}(arguments[0]);", token)
print("Callback invoked — site should process the token automatically")
# Wait for the page to process
time.sleep(3)
driver.quit()
Việc này có tác dụng gì:
- Gửi khóa trang và url trang tới
in.phpbằngmethod=userrecaptcha— giống với phiên bản tiêu chuẩn v2. - Thăm dò
res.phpcứ sau 5 giây cho đến khi mã thông báo sẵn sàng. - Phát hiện tên hàm gọi lại từ trang DOM.
- Gọi hàm gọi lại với mã thông báo đã giải quyết bằng
execute_script. - JavaScript riêng của trang web sẽ xử lý phần còn lại - gửi biểu mẫu, xác thực hoặc chuyển hướng trang.
Triển khai Node.js (Puppeteer)
const puppeteer = require("puppeteer");
const API_KEY = "YOUR_CAPTCHAAI_API_KEY";
const SITEKEY = "6Le-wvkSAAAAAPBMRTvw0Q4Muexq9bi0DJwx_mJ-";
const PAGE_URL = "https://staging.example.com/qa-login";
const CALLBACK_NAME = "SubmitToken";
const SUBMIT_URL = "https://ocr.captchaai.com/in.php";
const RESULT_URL = "https://ocr.captchaai.com/res.php";
function sleep(ms) {
return new Promise((resolve) => setTimeout(resolve, ms));
}
async function solveRecaptchaV2(apiKey, sitekey, pageurl) {
// Step 1: Submit the captcha
const submitResp = await fetch(SUBMIT_URL, {
method: "POST",
headers: { "Content-Type": "application/x-www-form-urlencoded" },
body: new URLSearchParams({
key: apiKey,
method: "userrecaptcha",
googlekey: sitekey,
pageurl: pageurl,
json: "1",
}),
});
const submitData = await submitResp.json();
if (submitData.status !== 1) {
throw new Error(`Submit failed: ${JSON.stringify(submitData)}`);
}
const captchaId = submitData.request;
console.log(`Task created — captcha ID: ${captchaId}`);
// Step 2: Wait before first poll
await sleep(15_000);
// Step 3: Poll for result
for (let i = 0; i < 60; i++) {
const resultResp = await fetch(
`${RESULT_URL}?${new URLSearchParams({
key: apiKey,
action: "get",
id: captchaId,
json: "1",
})}`
);
const resultData = await resultResp.json();
if (resultData.request === "CAPCHA_NOT_READY") {
await sleep(5_000);
continue;
}
if (resultData.status === 1) {
return resultData.request;
}
throw new Error(`Polling error: ${JSON.stringify(resultData)}`);
}
throw new Error("reCAPTCHA v2 solve timed out");
}
async function detectCallbackName(page) {
return page.evaluate(() => {
// Try data-callback attribute
const el = document.querySelector("[data-callback]");
if (el) return el.getAttribute("data-callback");
// Try internal config
if (typeof ___grecaptcha_cfg !== "undefined") {
const clients = ___grecaptcha_cfg.clients;
for (const key of Object.keys(clients)) {
const json = JSON.stringify(clients[key]);
const match = json.match(/"callback":"(\w+)"/);
if (match) return match[1];
}
}
return null;
});
}
(async () => {
const browser = await puppeteer.launch({ headless: false });
const page = await browser.newPage();
await page.goto(PAGE_URL, { waitUntil: "networkidle2" });
// Detect callback
const detected = await detectCallbackName(page);
const callbackName = detected || CALLBACK_NAME;
console.log(`Using callback: ${callbackName}`);
// Solve the CAPTCHA
const token = await solveRecaptchaV2(API_KEY, SITEKEY, PAGE_URL);
console.log(`Solved token: ${token.slice(0, 80)}...`);
// Invoke the callback
await page.evaluate(
(name, tkn) => {
window[name](tkn);
},
callbackName,
token
);
console.log("Callback invoked — site should process the token automatically");
await sleep(3_000);
await browser.close();
})();
Triển khai PHP
Lệnh gọi API giống nhau trong PHP. Lệnh gọi lại yêu cầu ngữ cảnh trình duyệt, vì vậy ví dụ này đề cập đến cách giải quyết phía máy chủ. Sử dụng công cụ trình duyệt không có đầu (ví dụ: PHP WebDriver) cho bước chèn.
<?php
$apiKey = "YOUR_CAPTCHAAI_API_KEY";
$sitekey = "6Le-wvkSAAAAAPBMRTvw0Q4Muexq9bi0DJwx_mJ-";
$pageurl = "https://staging.example.com/qa-login";
// Step 1: Submit
$submit = file_get_contents("https://ocr.captchaai.com/in.php?" . http_build_query([
"key" => $apiKey,
"method" => "userrecaptcha",
"googlekey" => $sitekey,
"pageurl" => $pageurl,
"json" => 1,
]));
$submitData = json_decode($submit, true);
if ($submitData["status"] !== 1) {
die("Submit failed: " . $submit);
}
$captchaId = $submitData["request"];
echo "Task created — captcha ID: $captchaId\n";
// Step 2: Wait and poll
sleep(15);
for ($i = 0; $i < 60; $i++) {
$result = file_get_contents("https://ocr.captchaai.com/res.php?" . http_build_query([
"key" => $apiKey,
"action" => "get",
"id" => $captchaId,
"json" => 1,
]));
$resultData = json_decode($result, true);
if ($resultData["request"] === "CAPCHA_NOT_READY") {
sleep(5);
continue;
}
if ($resultData["status"] === 1) {
$token = $resultData["request"];
echo "Solved token: " . substr($token, 0, 80) . "...\n";
// Pass $token to your browser automation to invoke the callback
break;
}
die("Polling error: " . $result);
}
Sau khi nhận được mã thông báo bằng PHP, hãy sử dụng công cụ tự động hóa trình duyệt (ví dụ: php-webdriver) để thực thi:
SubmitToken("TOKEN_FROM_CAPTCHAAI");
Những lỗi thường gặp
| # | sai lầm | Chuyện gì xảy ra | sửa chữa |
|---|---|---|---|
| 1 | Đặt g-recaptcha-response thay vì gọi lại |
Trang bỏ qua mã thông báo — biểu mẫu không bao giờ gửi | Tìm tên gọi lại và gọi nó bằng mã thông báo |
| 2 | Tên hàm gọi lại sai | Lỗi JavaScript: hàm không được xác định | Kiểm tra lại data-callback, grecaptcha.render() hoặc cấu hình bên trong |
| 3 | Gọi lại nằm trên một chỉ mục ứng dụng khách khác | Phiên bản reCAPTCHA sai được nhắm mục tiêu trên các trang có nhiều tiện ích | Kiểm tra ___grecaptcha_cfg.clients[1], clients[2], v.v. |
| 4 | Gọi lại trước khi trang sẵn sàng | Chức năng chưa được xác định trong ngữ cảnh trang | Đợi DOMContentLoaded hoặc networkidle trước khi gọi |
| 5 | Sử dụng tên/minified khó hiểu | Tên gọi lại trong nguồn bị sai | Sử dụng bảng điều khiển trình duyệt thời gian chạy để tìm tham chiếu chức năng thực tế |
| 6 | Kết hợp gọi lại v2 với v2 vô hình | Một số triển khai vô hình cũng sử dụng lệnh gọi lại | Kiểm tra xem data-size="invisible" có hiện diện hay không - nếu có, hãy xemCách giải reCAPTCHA Invisible bằng API |
Khắc phục sự cố
Đã giải quyết mã thông báo nhưng trang không phản hồi
Nguyên nhân phổ biến nhất: bạn đặt g-recaptcha-response thay vì gọi lại. Kiểm tra xem tiện ích có data-callback hay callback trong grecaptcha.render(). Nếu có, bạn phải gọi hàm đó.
ReferenceError: SubmitToken is not defined
Chức năng gọi lại chưa được tải hoặc tên sai. Hãy thử:
- Xác nhận tên bằng cách kiểm tra
data-callbackhoặc cấu hình bên trong. - Đợi trang tải đầy đủ trước khi gọi.
- Trên các trang web được rút gọn, chức năng có thể được gán cho một biến - hãy kiểm tra
window.SubmitTokentrong bảng điều khiển.
Mã thông báo hoạt động trên tiêu chuẩn v2 nhưng không thành công trên trang này
Có thể bạn đang phải đối mặt với việc triển khai gọi lại. Theo dõibước phát hiệnở trên để xác nhận, sau đó chuyển sang gọi lại.
ERROR_BAD_TOKEN_OR_PAGEURL
Cặp sitekey/pageurl không hợp lệ. Đây là lỗi API, không liên quan đến gọi lại so với tiêu chuẩn. Trích xuất lại cả hai giá trị từ trang.
Trang có nhiều tiện ích reCAPTCHA
Mỗi widget có thể có lệnh gọi lại riêng. Kiểm tra từng div g-recaptcha hoặc kiểm tra ___grecaptcha_cfg.clients để tìm tất cả các phiên bản đã đăng ký. Hãy ghép tiện ích với biểu mẫu bạn đang nhắm mục tiêu.
ERROR_CAPTCHA_UNSOLVABLE
Thử thách không thể giải quyết được. Hãy thử lại với một yêu cầu mới. Đây không phải là cuộc gọi lại cụ thể.
Để tham khảo lỗi đầy đủ, hãy xemCác lỗi giải quyết reCAPTCHA v2 thường gặp.
Tại sao CaptchaAI hoạt động cho việc này
| Yếu tố | Chi tiết |
|---|---|
| ** Lệnh gọi API tương tự ** | Luồng submit/poll giống hệt với reCAPTCHA v2 tiêu chuẩn - không cần thêm tham số |
| Tỷ lệ thành công | 99,5%+ cho reCAPTCHA v2 (gọi lại và tiêu chuẩn sử dụng cùng một bộ giải) |
| Giải quyết tốc độ | Dưới 60 giây |
| Khả năng tương thích với mã thông báo | Mã thông báo được trả về hoạt động với cả lệnh gọi lại và chèn g-recaptcha-response |
| Giá cả | Các gói dựa trên chuỗi bắt đầu từ $15/month để giải quyết không giới hạn |
Mã thông báo CaptchaAI trả về giống nhau bất kể trang web triển khai reCAPTCHA v2 như thế nào. Sự khác biệt hoàn toàn nằm ở mã phía máy khách của bạn — cách bạn phân phối mã thông báo đến trang.
Ví dụ đầy đủ có thể chạy được
Bạn cần một dự án hoạt động hoàn chỉnh với thiết lập môi trường, bỏ phiếu, thử lại và xử lý lỗi?
Xem ví dụ có thể chạy đầy đủ trên GitHub →
Câu hỏi thường gặp
Lệnh gọi lại reCAPTCHA v2 là gì?
Lệnh gọi lại là một hàm JavaScript mà trang web đăng ký để nhận mã thông báo reCAPTCHA đã giải quyết. Thay vì ghi mã thông báo vào trường g-recaptcha-response ẩn, reCAPTCHA gọi hàm trực tiếp. Chức năng này thường kích hoạt gửi biểu mẫu, xác thực hoặc chuyển hướng trang.
Lệnh gọi lại khác với reCAPTCHA v2 tiêu chuẩn cho lệnh gọi API như thế nào?
Nó không khác chút nào. Bạn gửi cùng một yêu cầu method=userrecaptcha với cùng một khóa trang và url trang. Sự khác biệt duy nhất là những gì bạn làm với mã thông báo sau khi nhận được nó — bạn gọi hàm gọi lại thay vì đặt giá trị trường.
Làm cách nào để tìm tên hàm gọi lại?
Ba vị trí cần kiểm tra: (1) thuộc tính data-callback trên div reCAPTCHA, (2) thuộc tính callback trong lệnh gọi grecaptcha.render() trong trang JavaScript, (3) đối tượng ___grecaptcha_cfg.clients[0] trong bảng điều khiển trình duyệt — điều hướng cây để tìm thuộc tính callback.
Tôi có thể sử dụng mã thông báo bằng cả hai phương pháp không?
Bản thân mã thông báo hoạt động theo một trong hai cách. Nhưng nếu trang web mong đợi một lệnh gọi lại thì việc cài đặt g-recaptcha-response sẽ bị bỏ qua. Luôn kết hợp phương pháp tiêm với những gì trang web mong đợi.
Tôi có cần trình duyệt để gọi lại không?
Vâng. Lệnh gọi lại là một hàm JavaScript trong ngữ cảnh trang. Bạn cần Selenium, Puppeteer, Playwright hoặc một công cụ tương tự có thể chạy JavaScript trên trang mục tiêu.
Bắt đầu giải quyết cuộc gọi lại reCAPTCHA v2
- Nhận khóa API của bạn —captchaai.com/api.php
- Phát hiện tên gọi lại — kiểm tra
data-callback,grecaptcha.render()hoặc cấu hình bên trong - Sao chép mã Python hoặc Node.js ở trên — thay thế phần giữ chỗ bằng khóa, khóa trang, url trang và tên gọi lại của bạn
- Chạy — mã thông báo sẽ đến sau chưa đầy 60 giây, lệnh gọi lại sẽ kích hoạt và trang xử lý kết quả
- Bị kẹt? Bắt đầu vớiCác lỗi giải quyết reCAPTCHA v2 thường gặphoặc đọc toàn bộTài liệu API CaptchaAI
bài viết liên quan
- Giải quyết Recaptcha Python vô hình
- Xử lý cửa quay Recaptcha V2 trên cùng một trang web
- Recaptcha Enterprise Assessment Api Deep Dive