Bộ giải captcha bằng Java với HttpClient: ví dụ hoạt động (2026)
Một bộ giải captcha bằng Java chỉ là một lời gọi HTTP. Java 11 trở lên đi kèm java.net.http.HttpClient, nên phụ thuộc duy nhất hướng dẫn này cần là Gson, để xử lý JSON. Bạn gửi sitekey và URL trang đến API của Scarnox, đọc solution.token, và submit token vào form của website. Hướng dẫn này bao quát PopularCaptcha, loại mà Scarnox giải hôm nay theo kiểu proxyless.
Bắt đầu với tín dụng dùng thử miễn phí, không cần thẻ và thử mã trên một trang bạn kiểm soát trước khi dùng nó ở nơi khác.
Yêu cầu
- Java 17 trở lên (
java -version). - Gson 2.10 trở lên. Trong Maven:
com.google.code.gson:gson:2.10.1. - Một khóa API của Scarnox, đọc từ biến môi trường.
- Sitekey của widget PopularCaptcha trên trang. Để được hướng dẫn tìm nó, xem cách tìm sitekey của captcha.
Lớp bộ giải
Lớp bọc một HttpClient có giữ cookie, để một phiên có thể đi xuyên qua bước submit form. Phương thức giải đặt header Bearer, gửi thân JSON, và kiểm tra errorId:
// ScarnoxSolver.java
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import java.net.CookieManager;
import java.net.CookiePolicy;
import java.net.URI;
import java.net.URLEncoder;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets;
import java.time.Duration;
import java.util.LinkedHashMap;
import java.util.Map;
public class ScarnoxSolver {
private static final String API_URL = "https://api.scarnox.com/api/tasks/create";
private static final Gson GSON = new Gson();
private final String apiKey;
private final HttpClient http = HttpClient.newBuilder()
.connectTimeout(Duration.ofSeconds(10))
.cookieHandler(new CookieManager(null, CookiePolicy.ACCEPT_ALL))
.build();
public ScarnoxSolver(String apiKey) {
this.apiKey = apiKey;
}
/** Trả về token. Lời gọi bị chặn cho đến khi token sẵn sàng. */
public String solve(String sitekey, String pageUrl, boolean invisible) throws Exception {
Map<String, Object> body = new LinkedHashMap<>();
body.put("captcha_type", "PopularCaptchaTaskProxyless");
body.put("site_key", sitekey);
body.put("site_url", pageUrl);
if (invisible) {
body.put("is_invisible", true);
}
HttpRequest request = HttpRequest.newBuilder(URI.create(API_URL))
.timeout(Duration.ofSeconds(185))
.header("Authorization", "Bearer " + apiKey)
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(GSON.toJson(body)))
.build();
HttpResponse<String> response = http.send(request, HttpResponse.BodyHandlers.ofString());
JsonObject data;
try {
data = JsonParser.parseString(response.body()).getAsJsonObject();
} catch (RuntimeException e) {
throw new IllegalStateException("HTTP " + response.statusCode() + ": not JSON");
}
if (data.get("errorId").getAsInt() != 0) {
throw new IllegalStateException(
data.get("errorCode").getAsString() + ": "
+ data.get("errorDescription").getAsString());
}
return data.getAsJsonObject("solution").get("token").getAsString();
}
/** Gửi token vào form của website và trả về mã trạng thái HTTP. */
public int submit(String pageUrl, String email, String token) throws Exception {
// Tải trang trước để cookie phiên được đặt.
http.send(HttpRequest.newBuilder(URI.create(pageUrl)).GET().build(),
HttpResponse.BodyHandlers.discarding());
String form = "email=" + enc(email)
+ "&h-captcha-response=" + enc(token)
+ "&g-recaptcha-response=" + enc(token);
HttpRequest request = HttpRequest.newBuilder(URI.create(pageUrl))
.header("Content-Type", "application/x-www-form-urlencoded")
.POST(HttpRequest.BodyPublishers.ofString(form))
.build();
return http.send(request, HttpResponse.BodyHandlers.discarding()).statusCode();
}
private static String enc(String value) {
return URLEncoder.encode(value, StandardCharsets.UTF_8);
}
}
Header Authorization dùng tiền tố Bearer. Timeout của yêu cầu là 185 giây, vì API bị chặn cho đến khi token sẵn sàng. Không có bước polling.
Chương trình chính
Phương thức main giải với vài lần thử lại, rồi submit token:
// Main.java
public class Main {
public static void main(String[] args) throws Exception {
String apiKey = System.getenv("SCARNOX_API_KEY");
if (apiKey == null || apiKey.isBlank()) {
throw new IllegalStateException("Set SCARNOX_API_KEY");
}
String pageUrl = "https://example.com/signup";
String sitekey = "YOUR-SITEKEY-UUID";
ScarnoxSolver solver = new ScarnoxSolver(apiKey);
String token = null;
for (int attempt = 1; attempt <= 3 && token == null; attempt++) {
try {
token = solver.solve(sitekey, pageUrl, false);
} catch (IllegalStateException e) {
System.err.println("Attempt " + attempt + " failed: " + e.getMessage());
Thread.sleep(attempt * 1000L);
}
}
if (token == null) {
throw new IllegalStateException("No token after 3 attempts");
}
int status = solver.submit(pageUrl, "you@example.com", token);
System.out.println("Status: " + status);
}
}
Chạy nó:
export SCARNOX_API_KEY=scarnox_YOURAPIKEY
javac -cp gson-2.10.1.jar *.java
java -cp .:gson-2.10.1.jar Main
Vì sao được tổ chức như vậy
Một client cho mỗi bộ giải. HttpClient là thread-safe và được thiết kế để tái sử dụng. Tạo một cái cho mỗi yêu cầu sẽ lãng phí kết nối.
Bật cookie. CookieManager trên client giữ phiên đã tải form, nên token được gửi cùng cookie mà website mong đợi.
Kiểm tra lỗi tường minh. API trả về errorId là 0 khi thành công. Mọi giá trị khác bao gồm errorCode và errorDescription, và bộ giải ném ngoại lệ với nội dung đó. Token nằm tại solution.token.
Cả hai trường captcha. Form nhận h-captcha-response và g-recaptcha-response. Hầu hết website đọc một trong hai.
Thời gian
Token hết hạn trong khoảng hai phút. Hãy giải ngay trước khi submit, không phải ở đầu một công việc dài. Hết hạn token captcha giải thích cách xác định khoảng thời gian và phân biệt token hết hạn với token bị từ chối.
Widget ẩn
Truyền true làm đối số thứ ba của solve khi widget là ẩn. Khi đó yêu cầu có is_invisible: true. Nếu trang cần một callback JavaScript nhận token, client phía máy chủ không thể kích hoạt nó, và công cụ tự động hóa trình duyệt là lựa chọn tốt hơn. Hướng dẫn captcha ẩn liệt kê các mẫu thường gặp.
Xử lý lỗi
Thử lại bao quát các lỗi tạm thời. Hãy dừng thử lại với những lỗi sẽ không thay đổi, chẳng hạn sitekey sai hoặc URL trang mà widget không chạy trên đó, và ghi log để xem lại. Chính sách đầy đủ, bao gồm những mã nào nên dừng, nằm trong xử lý lỗi bộ giải captcha.
Thu thập dữ liệu có trách nhiệm
Nếu chương trình thu thập các trang công khai, hãy kiểm tra robots.txt và điều khoản của website trước. Thêm độ trễ giữa các yêu cầu và chỉ giữ dữ liệu cá nhân bạn cần. Về nền tảng pháp lý, xem web scraping có hợp pháp không.
Giá
Bạn trả tiền theo mỗi lần giải thành công, và các lần giải thất bại không bị tính phí. Xem bảng giá hiện tại để biết mức phí. Để bắt đầu, bắt đầu với tín dụng dùng thử miễn phí, không cần thẻ.