JavaでreCAPTCHA Enterpriseを解く

著者:solvethree読了時間:1分

Java の HttpClient でトークンをリクエストし、Gson で JSON レスポンスを読み取ります。この例では REST API を呼び出し、タスクの完了を待って、reCAPTCHA Enterprise の解決結果を返します。

このページの内容

サイトと環境を設定する

Java 21 以降を使用してください。コンソールで対象の有効なサイトプロファイルを作成し、Java を起動する環境で SOLVETHREE_API_KEY と SOLVETHREE_PROXY を設定します。

accounts.example.com をプロファイルに登録したホスト名に、login をページで使用されているアクションに置き換えてください。site フィールドには、スキームやパスを含めずにホスト名を指定します。

Solve.java を保存して実行する

Java 21+ · Solve.java(Gson依存関係)
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import java.net.URI;
import java.net.URLEncoder;
import java.net.http.*;
import java.nio.charset.StandardCharsets;
import java.time.Duration;
import java.util.UUID;

public class Solve {
    static final HttpClient HTTP = HttpClient.newBuilder()
        .connectTimeout(Duration.ofSeconds(15)).build();
    static final String KEY = System.getenv("SOLVETHREE_API_KEY");

    static JsonObject api(String path, JsonObject body, long deadline) throws Exception {
        long remaining = deadline - System.nanoTime();
        if (remaining <= 0) throw new IllegalStateException("Keep the task ID and resume polling");
        var builder = HttpRequest.newBuilder(URI.create("https://api.solvethree.com/v1" + path))
            .timeout(Duration.ofNanos(Math.min(remaining, Duration.ofSeconds(30).toNanos())))
            .header("Authorization", "Bearer " + KEY)
            .header("Content-Type", "application/json");
        if (body == null) builder.GET();
        else builder.POST(HttpRequest.BodyPublishers.ofString(body.toString()));
        var response = HTTP.send(builder.build(), HttpResponse.BodyHandlers.ofString());
        if (response.statusCode() < 200 || response.statusCode() >= 300)
            throw new IllegalStateException("API HTTP " + response.statusCode());
        return JsonParser.parseString(response.body()).getAsJsonObject();
    }
    public static void main(String[] args) throws Exception {
        String proxy = System.getenv("SOLVETHREE_PROXY");
        if (KEY == null || proxy == null) throw new IllegalArgumentException("Set the API key and proxy");
        var input = new JsonObject();
        input.addProperty("site", "accounts.example.com");
        input.addProperty("action", "login");
        input.addProperty("proxy", proxy);
        input.addProperty("requestId", UUID.randomUUID().toString());
        // Save input before creation if the task must be recovered after restart.
        long deadline = System.nanoTime() + Duration.ofSeconds(180).toNanos();
        var task = api("/tasks?waitMs=0", input, deadline);
        while (task.get("status").getAsString().equals("pending") || task.get("status").getAsString().equals("solving")) {
            String id = URLEncoder.encode(task.get("id").getAsString(), StandardCharsets.UTF_8);
            task = api("/tasks/" + id + "?waitMs=15000", null, deadline);
            if (task.get("status").getAsString().equals("pending") || task.get("status").getAsString().equals("solving"))
                Thread.sleep(1000);
        }
        if (!task.get("status").getAsString().equals("ready"))
            throw new IllegalStateException("Task failed: " + task.get("errorCode")
                + ": " + task.get("error"));
        var solution = task.getAsJsonObject("solution");
        // Submit solution.token with userAgent/secChUa and the original proxy.
        System.out.println("Ready task: " + task.get("id").getAsString());
    }
}

Solve.java があるディレクトリで、Gson JAR をダウンロードし、コンパイルして実行します。

macOS/Linux · Gsonを取得してSolve.javaを実行
curl --fail --location --output gson-2.15.0.jar \
  https://repo.maven.apache.org/maven2/com/google/code/gson/gson/2.15.0/gson-2.15.0.jar
javac -cp gson-2.15.0.jar Solve.java
java -cp .:gson-2.15.0.jar Solve

これらのコマンドでは、macOS/Linux のクラスパス区切り文字 : を使用しています。Windows では、カレントディレクトリと Gson JAR の間に ; を使用してください。

結果からトークンを読み取る

作成時は waitMs=0 を使用します。ループは pending または solving の間、同じタスク ID を取得し続け、ready または failed で停止します。各 GET は最大 15 秒待機できます。呼び出し元の全体の制限時間は 180 秒です。

solution.get("token").getAsString() でトークンを読み取ります。対象へのリクエストでは、返された userAgent と secChUa を使用し、同じプロキシを経由してください。プログラムが出力するのはトークンではなく、タスク ID です。

送信後に対象のレスポンスを確認してください。準備完了のタスクは、解決結果が生成されたことを示しますが、アプリケーションがそれを受け入れたことを意味するわけではありません。

エラーと中断されたリクエスト

ヘルパーは、成功以外の HTTP レスポンスを受け取ると停止します。失敗で終了したタスクは errorCode と error を報告し、失敗した解決処理は返金されます。API エラーリファレンスで修正すべき点を確認してください。

再起動後に復旧する必要がある場合は、生成された requestId と正確な入力を保存してください。作成がタイムアウトした場合は、同じ ID でその入力を再送信します。すでにタスク ID がある場合は、そのタスクを取得してください。このプログラムを再起動すると別の UUID が生成され、課金対象のタスクがもう 1 件作成される可能性があります。

最初のタスクを実行しましょう。

$5のワークスペースクレジットで始められます。

ワークスペースを作成
JavaでreCAPTCHA Enterpriseを解く · solvethree