diff --git a/README.md b/README.md index dcded63..f614d94 100644 --- a/README.md +++ b/README.md @@ -221,9 +221,7 @@ Internal factory scripts, tools, and templates are intentionally not part of thi | [how-to-solve-cloudflare-challenge-using-api](articles/how-to-solve-cloudflare-challenge-using-api/) | Cloudflare Challenge | 🟡 Standard | Python, Node.js, PHP, Go, Java, C#, Ruby, Rust, Kotlin, Bash | [Blog](https://blog.captchaai.com/how-to-solve-cloudflare-challenge-using-api) | | [how-to-solve-cloudflare-turnstile-using-api](articles/how-to-solve-cloudflare-turnstile-using-api/) | Cloudflare Turnstile | 🟢 Verified | Python, Node.js, PHP, Go, Java, C#, Ruby, Rust, Kotlin, Bash | [Blog](https://blog.captchaai.com/how-to-solve-cloudflare-turnstile-using-api) | | [how-to-solve-geetest-v3-using-api](articles/how-to-solve-geetest-v3-using-api/) | GeeTest v3 | 🟡 Standard | Python, Node.js, PHP, Go, Java, C#, Ruby, Rust, Kotlin, Bash | [Blog](https://blog.captchaai.com/how-to-solve-geetest-v3-using-api) | -| [how-to-solve-geetest-v4-using-api](articles/how-to-solve-geetest-v4-using-api/) | GeeTest v4 | 🟡 Standard | Python, Node.js, PHP, Go, Java, C#, Ruby, Rust, Kotlin, Bash | [Blog](https://blog.captchaai.com/how-to-solve-geetest-v4-using-api) | | [how-to-solve-grid-image-captcha-automatically](articles/how-to-solve-grid-image-captcha-automatically/) | Grid Image CAPTCHA | 🟡 Standard | Python, Node.js, PHP, Go, Java, C#, Ruby, Rust, Kotlin, Bash | [Blog](https://blog.captchaai.com/how-to-solve-grid-image-captcha-automatically) | -| [how-to-solve-hcaptcha-using-api](articles/how-to-solve-hcaptcha-using-api/) | hCaptcha | 🟡 Standard | Python, Node.js, PHP, Go, Java, C#, Ruby, Rust, Kotlin, Bash | [Blog](https://blog.captchaai.com/how-to-solve-hcaptcha-using-api) | | [how-to-solve-recaptcha-invisible-using-api](articles/how-to-solve-recaptcha-invisible-using-api/) | reCAPTCHA Invisible | 🟡 Standard | Python, Node.js, PHP, Go, Java, C#, Ruby, Rust, Kotlin, Bash | [Blog](https://blog.captchaai.com/how-to-solve-recaptcha-invisible-using-api) | | [how-to-solve-recaptcha-v2-callback-using-api](articles/how-to-solve-recaptcha-v2-callback-using-api/) | reCAPTCHA v2 | 🟢 Verified | Python, Node.js, PHP, Go, Java, C#, Ruby, Rust, Kotlin, Bash | [Blog](https://blog.captchaai.com/how-to-solve-recaptcha-v2-callback-using-api) | | [how-to-solve-recaptcha-v2-enterprise-using-api](articles/how-to-solve-recaptcha-v2-enterprise-using-api/) | reCAPTCHA v2 Enterprise | 🟢 Verified | Python, Node.js, PHP, Go, Java, C#, Ruby, Rust, Kotlin, Bash | [Blog](https://blog.captchaai.com/how-to-solve-recaptcha-v2-enterprise-using-api) | diff --git a/articles/how-to-solve-geetest-v4-using-api/.env.example b/articles/how-to-solve-geetest-v4-using-api/.env.example deleted file mode 100644 index 27825c9..0000000 --- a/articles/how-to-solve-geetest-v4-using-api/.env.example +++ /dev/null @@ -1,13 +0,0 @@ -# CaptchaAI API credentials -# Get your API key from https://captchaai.com/dashboard -CAPTCHAAI_API_KEY=YOUR_API_KEY - -# Target page configuration -# GeeTest v4 captcha_id value from the target page -CAPTCHA_GT=YOUR_GT_VALUE -# Full URL of the page -CAPTCHA_PAGEURL=https://example.com - -# Polling configuration (optional) -POLL_INTERVAL=5 -MAX_TIMEOUT=120 diff --git a/articles/how-to-solve-geetest-v4-using-api/.gitignore b/articles/how-to-solve-geetest-v4-using-api/.gitignore deleted file mode 100644 index 8a0d20d..0000000 --- a/articles/how-to-solve-geetest-v4-using-api/.gitignore +++ /dev/null @@ -1,25 +0,0 @@ -.env -__pycache__/ -*.pyc -node_modules/ -vendor/ -composer.lock -package-lock.json -.DS_Store -Thumbs.db -# Go -go.sum -# Java -*.class -# C# -bin/ -obj/ -# Ruby -Gemfile.lock -# Rust -target/ -Cargo.lock -# Kotlin -*.jar -# Bash -*.log diff --git a/articles/how-to-solve-geetest-v4-using-api/README.md b/articles/how-to-solve-geetest-v4-using-api/README.md deleted file mode 100644 index f4c57f0..0000000 --- a/articles/how-to-solve-geetest-v4-using-api/README.md +++ /dev/null @@ -1,129 +0,0 @@ -# GeeTest v4 — CaptchaAI Example Pack - -Full working example for solving GeeTest v4 using the CaptchaAI API. - -**Languages:** Python, Node.js, PHP, Go, Java, C#, Ruby, Rust, Kotlin, Bash - -## Related article - -This example accompanies the blog article: -**[How to Solve GeeTest v4 Using API](https://blog.captchaai.com/how-to-solve-geetest-v4-using-api)** - -## Prerequisites - -- A CaptchaAI account with API key ([get one here](https://captchaai.com)) -- A target page with GeeTest v4 for testing -- One or more of: Python 3.8+, Node.js 16+, PHP 8.0+, Go 1.21+, Java 11+, .NET 8+, Ruby 3.0+, Rust 1.70+, Kotlin 1.9+, or Bash with curl and jq - -## GeeTest v4 parameters - -| Parameter | Required | Description | -|-----------|----------|-------------| -| `gt` | Yes | The `captcha_id` — GeeTest v4 identifier for the site (find in page source or GeeTest v4 init call) | -| `version` | Yes | Must be `4` for GeeTest v4 | -| `pageurl` | Yes | Full URL of the page with the GeeTest v4 widget | - -> **Note:** Unlike GeeTest v3, GeeTest v4 does **not** require a `challenge` parameter. - -## Response - -The API returns five values that must be submitted together to the site's GeeTest v4 verification endpoint: - -- `captcha_id` — the GeeTest captcha identifier -- `lot_number` — the lot number for this solve -- `pass_token` — the pass token -- `gen_time` — the generation timestamp -- `captcha_output` — the captcha output value - -## Setup - -1. Clone the repository: - ```bash - git clone https://github.com/CaptchaAI/CaptchaAI-Examples.git - cd CaptchaAI-Examples/articles/how-to-solve-geetest-v4-using-api - ``` - -2. Copy the environment file and add your credentials: - ```bash - cp .env.example .env - ``` - -3. Edit `.env` with your API key and target page details. - -4. Follow the language-specific setup below. - -### Python - -```bash -cd python -pip install -r requirements.txt -python solve.py -``` - -### Node.js - -```bash -cd node -npm install -node solve.js -``` - -### PHP - -```bash -cd php -composer install -php solve.php -``` - -### Go - -```bash -cd go -go run solve.go -``` - -### Java - -```bash -cd java -javac Solve.java -java Solve -``` - -### C# - -```bash -cd csharp -dotnet run -``` - -### Ruby - -```bash -cd ruby -ruby solve.rb -``` - -### Rust - -```bash -cd rust -cargo run -``` - -### Kotlin - -```bash -cd kotlin -kotlinc solve.kt -include-runtime -d solve.jar -java -jar solve.jar -``` - -### Bash - -```bash -cd bash -chmod +x solve.sh -bash solve.sh -``` diff --git a/articles/how-to-solve-geetest-v4-using-api/bash/solve.sh b/articles/how-to-solve-geetest-v4-using-api/bash/solve.sh deleted file mode 100644 index fb3152a..0000000 --- a/articles/how-to-solve-geetest-v4-using-api/bash/solve.sh +++ /dev/null @@ -1,195 +0,0 @@ -#!/usr/bin/env bash -# Solve GeeTest v4 using the CaptchaAI API. -# -# Usage: -# chmod +x solve.sh -# bash solve.sh - -set -euo pipefail - -SUBMIT_URL="https://ocr.captchaai.com/in.php" -RESULT_URL="https://ocr.captchaai.com/res.php" - -# Load .env -ENV_FILE="$(dirname "$0")/../.env" -if [[ -f "$ENV_FILE" ]]; then - set -a - # shellcheck disable=SC1090 - source "$ENV_FILE" - set +a -fi - -API_KEY="${CAPTCHAAI_API_KEY:-}" -GT="${CAPTCHA_GT:-}" -PAGEURL="${CAPTCHA_PAGEURL:-}" -POLL_INTERVAL="${POLL_INTERVAL:-5}" -MAX_TIMEOUT="${MAX_TIMEOUT:-120}" - -# Validate -if [[ -z "$API_KEY" || "$API_KEY" == "YOUR_API_KEY" ]]; then - echo "[!] ERROR: CAPTCHAAI_API_KEY is not set." - echo " Copy .env.example to .env and add your real API key." - exit 1 -fi -if [[ -z "$GT" || "$GT" == "YOUR_CAPTCHA_ID" ]]; then - echo "[!] ERROR: CAPTCHA_GT is not set." - echo " Find the captcha_id in the page source or GeeTest v4 initialization call." - exit 1 -fi -if [[ -z "$PAGEURL" || "$PAGEURL" == "https://example.com" ]]; then - echo "[!] WARNING: CAPTCHA_PAGEURL may not be set correctly." - echo " Make sure it points to the actual target page." -fi - -# JSON helpers -json_str() { - local json="$1" key="$2" - echo "$json" | grep -oP "\"${key}\":\s*\"\\K[^\"]*" || echo "" -} -json_int() { - local json="$1" key="$2" - echo "$json" | grep -oP "\"${key}\":\s*\\K[0-9]+" || echo "0" -} - -# Error handler -handle_error() { - local error="$1" - case "$error" in - ERROR_WRONG_USER_KEY|ERROR_KEY_DOES_NOT_EXIST|IP_BANNED) - echo "[!] Authentication error: $error" - echo " Check your API key at https://captchaai.com/dashboard" - ;; - ERROR_ZERO_BALANCE) - echo "[!] Balance error: $error" - echo " Top up your account at https://captchaai.com" - ;; - ERROR_PAGEURL|ERROR_WRONG_GOOGLEKEY|ERROR_BAD_PARAMETERS|ERROR_BAD_TOKEN_OR_PAGEURL) - echo "[!] Input error: $error" - echo " Verify your gt (captcha_id) and page URL are correct." - ;; - ERROR_BAD_PROXY|ERROR_PROXY_CONNECTION_FAILED) - echo "[!] Proxy error: $error" - echo " Check your proxy configuration or try a different proxy." - ;; - *) - echo "[!] Submission failed: $error" - ;; - esac -} - -# Submit task -echo "[*] Submitting GeeTest v4 task..." -ENCODED_KEY=$(python3 -c "import urllib.parse; print(urllib.parse.quote('$API_KEY'))" 2>/dev/null || echo "$API_KEY") -ENCODED_GT=$(python3 -c "import urllib.parse; print(urllib.parse.quote('$GT'))" 2>/dev/null || echo "$GT") -ENCODED_PAGEURL=$(python3 -c "import urllib.parse; print(urllib.parse.quote('$PAGEURL'))" 2>/dev/null || echo "$PAGEURL") - -SUBMIT_QUERY="key=${ENCODED_KEY}&method=geetest>=${ENCODED_GT}&pageurl=${ENCODED_PAGEURL}&version=4&json=1" - -SUBMIT_RESP=$(curl -sS --max-time 30 "${SUBMIT_URL}?${SUBMIT_QUERY}") - -if [[ -z "$SUBMIT_RESP" ]]; then - echo "[!] Network error during submission." - exit 1 -fi - -SUBMIT_STATUS=$(json_int "$SUBMIT_RESP" "status") -SUBMIT_REQUEST=$(json_str "$SUBMIT_RESP" "request") - -if [[ "$SUBMIT_STATUS" -ne 1 ]]; then - handle_error "$SUBMIT_REQUEST" - exit 1 -fi - -TASK_ID="$SUBMIT_REQUEST" -echo "[+] Task submitted. ID: $TASK_ID" - -# Poll for result -echo "[*] Waiting 15s before first poll..." -sleep 15 - -ELAPSED=15 -ATTEMPT=0 -BACKOFF="$POLL_INTERVAL" - -while [[ "$ELAPSED" -lt "$MAX_TIMEOUT" ]]; do - ATTEMPT=$((ATTEMPT + 1)) - echo "[*] Polling for result (attempt $ATTEMPT)..." - - POLL_RESP=$(curl -sS --max-time 30 \ - "${RESULT_URL}?key=${ENCODED_KEY}&action=get&id=${TASK_ID}&json=1" 2>/dev/null || echo "") - - if [[ -z "$POLL_RESP" ]]; then - echo "[!] Network error during polling." - sleep "$BACKOFF" - ELAPSED=$((ELAPSED + BACKOFF)) - BACKOFF=$((BACKOFF * 2)) - [[ "$BACKOFF" -gt 30 ]] && BACKOFF=30 - continue - fi - - STATUS=$(json_int "$POLL_RESP" "status") - - if [[ "$STATUS" -eq 1 ]]; then - # Extract the 5 GeeTest v4 values from the response - CAPTCHA_ID_VAL=$(echo "$POLL_RESP" | grep -oP '"captcha_id"\s*:\s*"\\K[^"]*' || echo "") - LOT_NUMBER=$(echo "$POLL_RESP" | grep -oP '"lot_number"\s*:\s*"\\K[^"]*' || echo "") - PASS_TOKEN=$(echo "$POLL_RESP" | grep -oP '"pass_token"\s*:\s*"\\K[^"]*' || echo "") - GEN_TIME=$(echo "$POLL_RESP" | grep -oP '"gen_time"\s*:\s*"\\K[^"]*' || echo "") - CAPTCHA_OUTPUT=$(echo "$POLL_RESP" | grep -oP '"captcha_output"\s*:\s*"\\K[^"]*' || echo "") - - # If values are empty, the request might be a JSON string — try extracting from unescaped content - if [[ -z "$CAPTCHA_ID_VAL" ]]; then - REQUEST_VALUE=$(json_str "$POLL_RESP" "request") - # Unescape the JSON string and extract values - UNESCAPED=$(echo "$REQUEST_VALUE" | sed 's/\\"/"/g; s/\\\\/\\/g') - CAPTCHA_ID_VAL=$(echo "$UNESCAPED" | grep -oP '"captcha_id"\s*:\s*"\\K[^"]*' || echo "") - LOT_NUMBER=$(echo "$UNESCAPED" | grep -oP '"lot_number"\s*:\s*"\\K[^"]*' || echo "") - PASS_TOKEN=$(echo "$UNESCAPED" | grep -oP '"pass_token"\s*:\s*"\\K[^"]*' || echo "") - GEN_TIME=$(echo "$UNESCAPED" | grep -oP '"gen_time"\s*:\s*"\\K[^"]*' || echo "") - CAPTCHA_OUTPUT=$(echo "$UNESCAPED" | grep -oP '"captcha_output"\s*:\s*"\\K[^"]*' || echo "") - fi - - echo "[+] Solved!" - echo "[+] captcha_id: $CAPTCHA_ID_VAL" - echo "[+] lot_number: $LOT_NUMBER" - echo "[+] pass_token: $PASS_TOKEN" - echo "[+] gen_time: $GEN_TIME" - echo "[+] captcha_output: $CAPTCHA_OUTPUT" - echo - echo "Next step: submit these five values to the site's" - echo "GeeTest v4 verification endpoint." - exit 0 - fi - - REQUEST=$(json_str "$POLL_RESP" "request") - - if [[ "$REQUEST" == "CAPCHA_NOT_READY" ]]; then - echo "[*] Not ready yet, waiting ${POLL_INTERVAL}s..." - sleep "$POLL_INTERVAL" - ELAPSED=$((ELAPSED + POLL_INTERVAL)) - BACKOFF="$POLL_INTERVAL" - continue - fi - - case "$REQUEST" in - ERROR_SERVER_ERROR|ERROR_INTERNAL_SERVER_ERROR) - echo "[!] Transient error: $REQUEST, retrying in ${BACKOFF}s..." - sleep "$BACKOFF" - ELAPSED=$((ELAPSED + BACKOFF)) - BACKOFF=$((BACKOFF * 2)) - [[ "$BACKOFF" -gt 30 ]] && BACKOFF=30 - continue - ;; - ERROR_CAPTCHA_UNSOLVABLE) - echo "[!] Solve error: $REQUEST" - echo " The CAPTCHA could not be solved. Verify parameters and retry." - exit 1 - ;; - esac - - echo "[!] Unexpected error: $REQUEST" - exit 1 -done - -echo "[!] Timeout: no solution received within ${MAX_TIMEOUT} seconds." -exit 1 diff --git a/articles/how-to-solve-geetest-v4-using-api/csharp/Solve.cs b/articles/how-to-solve-geetest-v4-using-api/csharp/Solve.cs deleted file mode 100644 index b950017..0000000 --- a/articles/how-to-solve-geetest-v4-using-api/csharp/Solve.cs +++ /dev/null @@ -1,230 +0,0 @@ -// Solve GeeTest v4 using the CaptchaAI API. -// -// Usage: -// dotnet run - -using System; -using System.Collections.Generic; -using System.IO; -using System.Net.Http; -using System.Text.Json; -using System.Threading.Tasks; - -const string SubmitUrl = "https://ocr.captchaai.com/in.php"; -const string ResultUrl = "https://ocr.captchaai.com/res.php"; - -var authErrors = new HashSet { "ERROR_WRONG_USER_KEY", "ERROR_KEY_DOES_NOT_EXIST", "IP_BANNED" }; -var balanceErrors = new HashSet { "ERROR_ZERO_BALANCE" }; -var inputErrors = new HashSet { "ERROR_PAGEURL", "ERROR_WRONG_GOOGLEKEY", "ERROR_BAD_PARAMETERS", "ERROR_BAD_TOKEN_OR_PAGEURL" }; -var transientErrors = new HashSet { "ERROR_SERVER_ERROR", "ERROR_INTERNAL_SERVER_ERROR" }; -var solveErrors = new HashSet { "ERROR_CAPTCHA_UNSOLVABLE" }; -var proxyErrors = new HashSet { "ERROR_BAD_PROXY", "ERROR_PROXY_CONNECTION_FAILED" }; - -var env = LoadEnv(Path.Combine("..", ".env")); -string apiKey = GetEnv(env, "CAPTCHAAI_API_KEY", ""); -string gt = GetEnv(env, "CAPTCHA_GT", ""); -string pageurl = GetEnv(env, "CAPTCHA_PAGEURL", ""); -int pollInterval = int.Parse(GetEnv(env, "POLL_INTERVAL", "5")); -int maxTimeout = int.Parse(GetEnv(env, "MAX_TIMEOUT", "120")); - -// Validate -if (string.IsNullOrEmpty(apiKey) || apiKey == "YOUR_API_KEY") -{ - Console.WriteLine("[!] ERROR: CAPTCHAAI_API_KEY is not set."); - Console.WriteLine(" Copy .env.example to .env and add your real API key."); - Environment.Exit(1); -} -if (string.IsNullOrEmpty(gt) || gt == "YOUR_CAPTCHA_ID") -{ - Console.WriteLine("[!] ERROR: CAPTCHA_GT is not set."); - Console.WriteLine(" Find the captcha_id in the page source or GeeTest v4 initialization call."); - Environment.Exit(1); -} -if (string.IsNullOrEmpty(pageurl) || pageurl == "https://example.com") -{ - Console.WriteLine("[!] WARNING: CAPTCHA_PAGEURL may not be set correctly."); - Console.WriteLine(" Make sure it points to the actual target page."); -} - -using var client = new HttpClient { Timeout = TimeSpan.FromSeconds(30) }; - -// Submit task -Console.WriteLine("[*] Submitting GeeTest v4 task..."); -var submitQuery = $"key={Uri.EscapeDataString(apiKey)}&method=geetest>={Uri.EscapeDataString(gt)}&pageurl={Uri.EscapeDataString(pageurl)}&version=4&json=1"; - -string submitBody; -try -{ - submitBody = await client.GetStringAsync($"{SubmitUrl}?{submitQuery}"); -} -catch (Exception ex) -{ - Console.WriteLine($"[!] Network error during submission: {ex.Message}"); - Environment.Exit(1); - return; -} - -using var submitDoc = JsonDocument.Parse(submitBody); -int submitStatus = submitDoc.RootElement.GetProperty("status").GetInt32(); -string submitRequest = submitDoc.RootElement.GetProperty("request").GetString() ?? ""; - -if (submitStatus != 1) -{ - HandleError(submitRequest, authErrors, balanceErrors, inputErrors, proxyErrors); - Environment.Exit(1); -} - -string taskId = submitRequest; -Console.WriteLine($"[+] Task submitted. ID: {taskId}"); - -// Poll for result -Console.WriteLine("[*] Waiting 15s before first poll..."); -await Task.Delay(15000); - -int elapsed = 15; -int attempt = 0; -int backoff = pollInterval; - -while (elapsed < maxTimeout) -{ - attempt++; - Console.WriteLine($"[*] Polling for result (attempt {attempt})..."); - - var pollQuery = $"key={Uri.EscapeDataString(apiKey)}&action=get&id={Uri.EscapeDataString(taskId)}&json=1"; - - string resultBody; - try - { - resultBody = await client.GetStringAsync($"{ResultUrl}?{pollQuery}"); - } - catch (Exception ex) - { - Console.WriteLine($"[!] Network error during polling: {ex.Message}"); - await Task.Delay(backoff * 1000); - elapsed += backoff; - backoff = Math.Min(backoff * 2, 30); - continue; - } - - using var resultDoc = JsonDocument.Parse(resultBody); - int status = resultDoc.RootElement.GetProperty("status").GetInt32(); - var requestElement = resultDoc.RootElement.GetProperty("request"); - - if (status == 1) - { - // The request field contains a JSON string or object with the 5 GeeTest v4 values - JsonDocument solutionDoc; - if (requestElement.ValueKind == JsonValueKind.String) - { - solutionDoc = JsonDocument.Parse(requestElement.GetString()!); - } - else - { - solutionDoc = JsonDocument.Parse(requestElement.GetRawText()); - } - - string captchaId = solutionDoc.RootElement.GetProperty("captcha_id").GetString() ?? ""; - string lotNumber = solutionDoc.RootElement.GetProperty("lot_number").GetString() ?? ""; - string passToken = solutionDoc.RootElement.GetProperty("pass_token").GetString() ?? ""; - string genTime = solutionDoc.RootElement.GetProperty("gen_time").GetString() ?? ""; - string captchaOutput = solutionDoc.RootElement.GetProperty("captcha_output").GetString() ?? ""; - solutionDoc.Dispose(); - - Console.WriteLine("[+] Solved!"); - Console.WriteLine($"[+] captcha_id: {captchaId}"); - Console.WriteLine($"[+] lot_number: {lotNumber}"); - Console.WriteLine($"[+] pass_token: {passToken}"); - Console.WriteLine($"[+] gen_time: {genTime}"); - Console.WriteLine($"[+] captcha_output: {captchaOutput}"); - Console.WriteLine(); - Console.WriteLine("Next step: submit these five values to the site's"); - Console.WriteLine("GeeTest v4 verification endpoint."); - return; - } - - string request = requestElement.ValueKind == JsonValueKind.String - ? requestElement.GetString() ?? "" - : ""; - - if (request == "CAPCHA_NOT_READY") - { - Console.WriteLine($"[*] Not ready yet, waiting {pollInterval}s..."); - await Task.Delay(pollInterval * 1000); - elapsed += pollInterval; - backoff = pollInterval; - continue; - } - - if (transientErrors.Contains(request)) - { - Console.WriteLine($"[!] Transient error: {request}, retrying in {backoff}s..."); - await Task.Delay(backoff * 1000); - elapsed += backoff; - backoff = Math.Min(backoff * 2, 30); - continue; - } - - if (solveErrors.Contains(request)) - { - Console.WriteLine($"[!] Solve error: {request}"); - Console.WriteLine(" The CAPTCHA could not be solved. Verify parameters and retry."); - Environment.Exit(1); - } - - Console.WriteLine($"[!] Unexpected error: {request}"); - Environment.Exit(1); -} - -Console.WriteLine($"[!] Timeout: no solution received within {maxTimeout} seconds."); -Environment.Exit(1); - -static Dictionary LoadEnv(string path) -{ - var dict = new Dictionary(); - if (!File.Exists(path)) return dict; - foreach (var line in File.ReadAllLines(path)) - { - var trimmed = line.Trim(); - if (string.IsNullOrEmpty(trimmed) || trimmed.StartsWith('#')) continue; - var eq = trimmed.IndexOf('='); - if (eq > 0) - dict[trimmed[..eq].Trim()] = trimmed[(eq + 1)..].Trim(); - } - return dict; -} - -static string GetEnv(Dictionary env, string key, string fallback) -{ - if (env.TryGetValue(key, out var v) && !string.IsNullOrEmpty(v)) return v; - v = Environment.GetEnvironmentVariable(key); - if (!string.IsNullOrEmpty(v)) return v; - return fallback; -} - -static void HandleError(string error, HashSet auth, HashSet balance, HashSet input, HashSet proxy) -{ - if (auth.Contains(error)) - { - Console.WriteLine($"[!] Authentication error: {error}"); - Console.WriteLine(" Check your API key at https://captchaai.com/dashboard"); - } - else if (balance.Contains(error)) - { - Console.WriteLine($"[!] Balance error: {error}"); - Console.WriteLine(" Top up your account at https://captchaai.com"); - } - else if (input.Contains(error)) - { - Console.WriteLine($"[!] Input error: {error}"); - Console.WriteLine(" Verify your gt (captcha_id) and page URL are correct."); - } - else if (proxy.Contains(error)) - { - Console.WriteLine($"[!] Proxy error: {error}"); - Console.WriteLine(" Check your proxy configuration or try a different proxy."); - } - else - { - Console.WriteLine($"[!] Submission failed: {error}"); - } -} diff --git a/articles/how-to-solve-geetest-v4-using-api/csharp/Solve.csproj b/articles/how-to-solve-geetest-v4-using-api/csharp/Solve.csproj deleted file mode 100644 index dd4b568..0000000 --- a/articles/how-to-solve-geetest-v4-using-api/csharp/Solve.csproj +++ /dev/null @@ -1,6 +0,0 @@ - - - Exe - net8.0 - - diff --git a/articles/how-to-solve-geetest-v4-using-api/go/go.mod b/articles/how-to-solve-geetest-v4-using-api/go/go.mod deleted file mode 100644 index 36f97d4..0000000 --- a/articles/how-to-solve-geetest-v4-using-api/go/go.mod +++ /dev/null @@ -1,3 +0,0 @@ -module captchaai-geetest-v4-example - -go 1.21 diff --git a/articles/how-to-solve-geetest-v4-using-api/go/solve.go b/articles/how-to-solve-geetest-v4-using-api/go/solve.go deleted file mode 100644 index 93fdb5c..0000000 --- a/articles/how-to-solve-geetest-v4-using-api/go/solve.go +++ /dev/null @@ -1,283 +0,0 @@ -// Solve GeeTest v4 using the CaptchaAI API. -// -// Usage: -// go run solve.go - -package main - -import ( - "bufio" - "encoding/json" - "fmt" - "io" - "net/http" - "net/url" - "os" - "path/filepath" - "strconv" - "strings" - "time" -) - -const submitURL = "https://ocr.captchaai.com/in.php" -const resultURL = "https://ocr.captchaai.com/res.php" - -var authErrors = map[string]bool{"ERROR_WRONG_USER_KEY": true, "ERROR_KEY_DOES_NOT_EXIST": true, "IP_BANNED": true} -var balanceErrors = map[string]bool{"ERROR_ZERO_BALANCE": true} -var inputErrors = map[string]bool{"ERROR_PAGEURL": true, "ERROR_WRONG_GOOGLEKEY": true, "ERROR_BAD_PARAMETERS": true, "ERROR_BAD_TOKEN_OR_PAGEURL": true} -var transientErrors = map[string]bool{"ERROR_SERVER_ERROR": true, "ERROR_INTERNAL_SERVER_ERROR": true} -var solveErrors = map[string]bool{"ERROR_CAPTCHA_UNSOLVABLE": true} -var proxyErrors = map[string]bool{"ERROR_BAD_PROXY": true, "ERROR_PROXY_CONNECTION_FAILED": true} - -type apiResponse struct { - Status int `json:"status"` - Request any `json:"request"` -} - -type geetestV4Solution struct { - CaptchaID string `json:"captcha_id"` - LotNumber string `json:"lot_number"` - PassToken string `json:"pass_token"` - GenTime string `json:"gen_time"` - CaptchaOutput string `json:"captcha_output"` -} - -func requestValue(value any) string { - switch v := value.(type) { - case nil: - return "" - case string: - return v - case float64: - return strconv.FormatInt(int64(v), 10) - case json.Number: - return v.String() - default: - return fmt.Sprintf("%v", v) - } -} - -func handleError(error string) { - if authErrors[error] { - fmt.Printf("[!] Authentication error: %s\n", error) - fmt.Println(" Check your API key at https://captchaai.com/dashboard") - } else if balanceErrors[error] { - fmt.Printf("[!] Balance error: %s\n", error) - fmt.Println(" Top up your account at https://captchaai.com") - } else if inputErrors[error] { - fmt.Printf("[!] Input error: %s\n", error) - fmt.Println(" Verify your gt (captcha_id) and page URL are correct.") - } else if proxyErrors[error] { - fmt.Printf("[!] Proxy error: %s\n", error) - fmt.Println(" Check your proxy configuration or try a different proxy.") - } else { - fmt.Printf("[!] Submission failed: %s\n", error) - } -} - -func getRequestString(raw any) string { - switch v := raw.(type) { - case nil: - return "" - case string: - return v - case float64: - return strconv.FormatInt(int64(v), 10) - case json.Number: - return v.String() - case map[string]any: - data, err := json.Marshal(v) - if err == nil { - return string(data) - } - case []any: - data, err := json.Marshal(v) - if err == nil { - return string(data) - } - case json.RawMessage: - var s string - if err := json.Unmarshal(v, &s); err == nil { - return s - } - return string(v) - } - return fmt.Sprintf("%v", raw) -} - -func loadEnv() map[string]string { - path := filepath.Join("..", ".env") - env := make(map[string]string) - f, err := os.Open(path) - if err != nil { - return env - } - defer f.Close() - - scanner := bufio.NewScanner(f) - for scanner.Scan() { - line := strings.TrimSpace(scanner.Text()) - if line == "" || strings.HasPrefix(line, "#") { - continue - } - parts := strings.SplitN(line, "=", 2) - if len(parts) == 2 { - env[strings.TrimSpace(parts[0])] = strings.TrimSpace(parts[1]) - } - } - - return env -} - -func getEnv(env map[string]string, key, fallback string) string { - if value, ok := env[key]; ok && value != "" { - return value - } - if value := os.Getenv(key); value != "" { - return value - } - return fallback -} - -func main() { - env := loadEnv() - apiKey := getEnv(env, "CAPTCHAAI_API_KEY", "") - gt := getEnv(env, "CAPTCHA_GT", "") - pageurl := getEnv(env, "CAPTCHA_PAGEURL", "") - pollInterval, _ := strconv.Atoi(getEnv(env, "POLL_INTERVAL", "5")) - maxTimeout, _ := strconv.Atoi(getEnv(env, "MAX_TIMEOUT", "120")) - - if apiKey == "" || apiKey == "YOUR_API_KEY" { - fmt.Println("[!] ERROR: CAPTCHAAI_API_KEY is not set.") - fmt.Println(" Copy .env.example to .env and add your real API key.") - os.Exit(1) - } - if gt == "" || gt == "YOUR_CAPTCHA_ID" { - fmt.Println("[!] ERROR: CAPTCHA_GT is not set.") - fmt.Println(" Find the captcha_id in the page source or GeeTest v4 initialization call.") - os.Exit(1) - } - if pageurl == "" || pageurl == "https://example.com" { - fmt.Println("[!] WARNING: CAPTCHA_PAGEURL may not be set correctly.") - fmt.Println(" Make sure it points to the actual target page.") - } - - client := &http.Client{Timeout: 30 * time.Second} - - // Submit task - fmt.Println("[*] Submitting GeeTest v4 task...") - params := url.Values{ - "key": {apiKey}, - "method": {"geetest"}, - "gt": {gt}, - "pageurl": {pageurl}, - "version": {"4"}, - "json": {"1"}, - } - - resp, err := client.Get(submitURL + "?" + params.Encode()) - if err != nil { - fmt.Printf("[!] Network error during submission: %v\n", err) - os.Exit(1) - } - defer resp.Body.Close() - - body, _ := io.ReadAll(resp.Body) - var submitResp apiResponse - json.Unmarshal(body, &submitResp) - - if submitResp.Status != 1 { - handleError(getRequestString(submitResp.Request)) - os.Exit(1) - } - - taskID := getRequestString(submitResp.Request) - fmt.Printf("[+] Task submitted. ID: %s\n", taskID) - - // Poll for result - fmt.Println("[*] Waiting 15s before first poll...") - time.Sleep(15 * time.Second) - - elapsed := 15 - attempt := 0 - backoff := pollInterval - - for elapsed < maxTimeout { - attempt++ - fmt.Printf("[*] Polling for result (attempt %d)...\n", attempt) - - pollParams := url.Values{ - "key": {apiKey}, - "action": {"get"}, - "id": {taskID}, - "json": {"1"}, - } - - resp, err := client.Get(resultURL + "?" + pollParams.Encode()) - if err != nil { - fmt.Printf("[!] Network error during polling: %v\n", err) - time.Sleep(time.Duration(backoff) * time.Second) - elapsed += backoff - if backoff < 30 { - backoff *= 2 - } - continue - } - - body, _ := io.ReadAll(resp.Body) - resp.Body.Close() - var result apiResponse - json.Unmarshal(body, &result) - - if result.Status == 1 { - var solution geetestV4Solution - solutionPayload := getRequestString(result.Request) - if err := json.Unmarshal([]byte(solutionPayload), &solution); err != nil { - fmt.Printf("[!] Failed to parse GeeTest v4 solution: %v\n", err) - os.Exit(1) - } - fmt.Println("[+] Solved!") - fmt.Printf("[+] captcha_id: %s\n", solution.CaptchaID) - fmt.Printf("[+] lot_number: %s\n", solution.LotNumber) - fmt.Printf("[+] pass_token: %s\n", solution.PassToken) - fmt.Printf("[+] gen_time: %s\n", solution.GenTime) - fmt.Printf("[+] captcha_output: %s\n", solution.CaptchaOutput) - fmt.Println() - fmt.Println("Next step: submit these five values to the site's") - fmt.Println("GeeTest v4 verification endpoint.") - return - } - - reqStr := getRequestString(result.Request) - - if reqStr == "CAPCHA_NOT_READY" { - fmt.Printf("[*] Not ready yet, waiting %ds...\n", pollInterval) - time.Sleep(time.Duration(pollInterval) * time.Second) - elapsed += pollInterval - backoff = pollInterval - continue - } - - if transientErrors[reqStr] { - fmt.Printf("[!] Transient error: %s, retrying in %ds...\n", reqStr, backoff) - time.Sleep(time.Duration(backoff) * time.Second) - elapsed += backoff - if backoff < 30 { - backoff *= 2 - } - continue - } - - if solveErrors[reqStr] { - fmt.Printf("[!] Solve error: %s\n", reqStr) - fmt.Println(" The CAPTCHA could not be solved. Verify parameters and retry.") - os.Exit(1) - } - - fmt.Printf("[!] Unexpected error: %s\n", reqStr) - os.Exit(1) - } - - fmt.Printf("[!] Timeout: no solution received within %d seconds.\n", maxTimeout) - os.Exit(1) -} diff --git a/articles/how-to-solve-geetest-v4-using-api/java/Solve.java b/articles/how-to-solve-geetest-v4-using-api/java/Solve.java deleted file mode 100644 index 94a22aa..0000000 --- a/articles/how-to-solve-geetest-v4-using-api/java/Solve.java +++ /dev/null @@ -1,265 +0,0 @@ -import java.io.*; -import java.net.*; -import java.nio.file.*; -import java.util.*; - -/** - * Solve GeeTest v4 using the CaptchaAI API. - * - * Usage: - * javac Solve.java - * java Solve - */ -public class Solve { - static final String SUBMIT_URL = "https://ocr.captchaai.com/in.php"; - static final String RESULT_URL = "https://ocr.captchaai.com/res.php"; - - static final Set AUTH_ERRORS = Set.of("ERROR_WRONG_USER_KEY", "ERROR_KEY_DOES_NOT_EXIST", "IP_BANNED"); - static final Set BALANCE_ERRORS = Set.of("ERROR_ZERO_BALANCE"); - static final Set INPUT_ERRORS = Set.of("ERROR_PAGEURL", "ERROR_WRONG_GOOGLEKEY", "ERROR_BAD_PARAMETERS", "ERROR_BAD_TOKEN_OR_PAGEURL"); - static final Set TRANSIENT_ERRORS = Set.of("ERROR_SERVER_ERROR", "ERROR_INTERNAL_SERVER_ERROR"); - static final Set SOLVE_ERRORS = Set.of("ERROR_CAPTCHA_UNSOLVABLE"); - static final Set PROXY_ERRORS = Set.of("ERROR_BAD_PROXY", "ERROR_PROXY_CONNECTION_FAILED"); - - static Map env = new HashMap<>(); - - public static void main(String[] args) throws Exception { - loadEnv(); - String apiKey = getEnv("CAPTCHAAI_API_KEY", ""); - String gt = getEnv("CAPTCHA_GT", ""); - String pageurl = getEnv("CAPTCHA_PAGEURL", ""); - int pollInterval = Integer.parseInt(getEnv("POLL_INTERVAL", "5")); - int maxTimeout = Integer.parseInt(getEnv("MAX_TIMEOUT", "120")); - - // Validate - if (apiKey.isEmpty() || apiKey.equals("YOUR_API_KEY")) { - System.out.println("[!] ERROR: CAPTCHAAI_API_KEY is not set."); - System.out.println(" Copy .env.example to .env and add your real API key."); - System.exit(1); - } - if (gt.isEmpty() || gt.equals("YOUR_CAPTCHA_ID")) { - System.out.println("[!] ERROR: CAPTCHA_GT is not set."); - System.out.println(" Find the captcha_id in the page source or GeeTest v4 initialization call."); - System.exit(1); - } - if (pageurl.isEmpty() || pageurl.equals("https://example.com")) { - System.out.println("[!] WARNING: CAPTCHA_PAGEURL may not be set correctly."); - System.out.println(" Make sure it points to the actual target page."); - } - - // Submit task - System.out.println("[*] Submitting GeeTest v4 task..."); - String submitParams = String.format( - "key=%s&method=geetest>=%s&pageurl=%s&version=4&json=1", - enc(apiKey), enc(gt), enc(pageurl) - ); - - String submitResp = httpGet(SUBMIT_URL + "?" + submitParams); - int submitStatus = jsonInt(submitResp, "status"); - String submitRequest = jsonStr(submitResp, "request"); - - if (submitStatus != 1) { - handleError(submitRequest); - System.exit(1); - } - - String taskId = submitRequest; - System.out.println("[+] Task submitted. ID: " + taskId); - - // Poll for result - System.out.println("[*] Waiting 15s before first poll..."); - Thread.sleep(15000); - - int elapsed = 15; - int attempt = 0; - int backoff = pollInterval; - - while (elapsed < maxTimeout) { - attempt++; - System.out.println("[*] Polling for result (attempt " + attempt + ")..."); - - String pollParams = String.format( - "key=%s&action=get&id=%s&json=1", - enc(apiKey), enc(taskId) - ); - - String resultResp; - try { - resultResp = httpGet(RESULT_URL + "?" + pollParams); - } catch (Exception e) { - System.out.println("[!] Network error during polling: " + e.getMessage()); - Thread.sleep(backoff * 1000L); - elapsed += backoff; - backoff = Math.min(backoff * 2, 30); - continue; - } - - int status = jsonInt(resultResp, "status"); - - if (status == 1) { - // The request field contains a JSON object with the 5 GeeTest v4 values - String requestValue = extractRequestValue(resultResp); - String captchaId = jsonStr(requestValue, "captcha_id"); - String lotNumber = jsonStr(requestValue, "lot_number"); - String passToken = jsonStr(requestValue, "pass_token"); - String genTime = jsonStr(requestValue, "gen_time"); - String captchaOutput = jsonStr(requestValue, "captcha_output"); - System.out.println("[+] Solved!"); - System.out.println("[+] captcha_id: " + captchaId); - System.out.println("[+] lot_number: " + lotNumber); - System.out.println("[+] pass_token: " + passToken); - System.out.println("[+] gen_time: " + genTime); - System.out.println("[+] captcha_output: " + captchaOutput); - System.out.println(); - System.out.println("Next step: submit these five values to the site's"); - System.out.println("GeeTest v4 verification endpoint."); - return; - } - - String request = jsonStr(resultResp, "request"); - - if ("CAPCHA_NOT_READY".equals(request)) { - System.out.println("[*] Not ready yet, waiting " + pollInterval + "s..."); - Thread.sleep(pollInterval * 1000L); - elapsed += pollInterval; - backoff = pollInterval; - continue; - } - - if (TRANSIENT_ERRORS.contains(request)) { - System.out.println("[!] Transient error: " + request + ", retrying in " + backoff + "s..."); - Thread.sleep(backoff * 1000L); - elapsed += backoff; - backoff = Math.min(backoff * 2, 30); - continue; - } - - if (SOLVE_ERRORS.contains(request)) { - System.out.println("[!] Solve error: " + request); - System.out.println(" The CAPTCHA could not be solved. Verify parameters and retry."); - System.exit(1); - } - - System.out.println("[!] Unexpected error: " + request); - System.exit(1); - } - - System.out.println("[!] Timeout: no solution received within " + maxTimeout + " seconds."); - System.exit(1); - } - - static void loadEnv() { - try { - Path envPath = Paths.get("..", ".env"); - if (!Files.exists(envPath)) return; - for (String line : Files.readAllLines(envPath)) { - line = line.trim(); - if (line.isEmpty() || line.startsWith("#")) continue; - int eq = line.indexOf('='); - if (eq > 0) { - env.put(line.substring(0, eq).trim(), line.substring(eq + 1).trim()); - } - } - } catch (IOException ignored) {} - } - - static String getEnv(String key, String fallback) { - String v = env.get(key); - if (v != null && !v.isEmpty()) return v; - v = System.getenv(key); - if (v != null && !v.isEmpty()) return v; - return fallback; - } - - static String httpGet(String urlStr) throws Exception { - URL url = new URL(urlStr); - HttpURLConnection conn = (HttpURLConnection) url.openConnection(); - conn.setConnectTimeout(30000); - conn.setReadTimeout(30000); - BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream())); - StringBuilder sb = new StringBuilder(); - String line; - while ((line = reader.readLine()) != null) sb.append(line); - reader.close(); - return sb.toString(); - } - - static String enc(String s) throws Exception { - return URLEncoder.encode(s, "UTF-8"); - } - - static int jsonInt(String json, String key) { - String pattern = "\"" + key + "\":"; - int idx = json.indexOf(pattern); - if (idx < 0) return 0; - int start = idx + pattern.length(); - StringBuilder sb = new StringBuilder(); - for (int i = start; i < json.length(); i++) { - char c = json.charAt(i); - if (c == ',' || c == '}') break; - if (c != ' ') sb.append(c); - } - try { return Integer.parseInt(sb.toString()); } catch (Exception e) { return 0; } - } - - static String jsonStr(String json, String key) { - String pattern = "\"" + key + "\":\""; - int idx = json.indexOf(pattern); - if (idx < 0) return ""; - int start = idx + pattern.length(); - int end = json.indexOf("\"", start); - if (end < 0) return ""; - return json.substring(start, end); - } - - static String extractRequestValue(String json) { - // Find "request": and extract the value — could be a JSON string or JSON object - String pattern = "\"request\":"; - int idx = json.indexOf(pattern); - if (idx < 0) return ""; - int start = idx + pattern.length(); - // Skip whitespace - while (start < json.length() && json.charAt(start) == ' ') start++; - if (start >= json.length()) return ""; - - if (json.charAt(start) == '"') { - // It's a JSON string — extract and unescape - int end = start + 1; - while (end < json.length()) { - if (json.charAt(end) == '\\') { end += 2; continue; } - if (json.charAt(end) == '"') break; - end++; - } - String inner = json.substring(start + 1, end); - return inner.replace("\\\"", "\"").replace("\\\\", "\\"); - } else if (json.charAt(start) == '{') { - // It's a JSON object — find matching brace - int depth = 0; - int end = start; - for (; end < json.length(); end++) { - if (json.charAt(end) == '{') depth++; - else if (json.charAt(end) == '}') { depth--; if (depth == 0) { end++; break; } } - } - return json.substring(start, end); - } - return ""; - } - - static void handleError(String error) { - if (AUTH_ERRORS.contains(error)) { - System.out.println("[!] Authentication error: " + error); - System.out.println(" Check your API key at https://captchaai.com/dashboard"); - } else if (BALANCE_ERRORS.contains(error)) { - System.out.println("[!] Balance error: " + error); - System.out.println(" Top up your account at https://captchaai.com"); - } else if (INPUT_ERRORS.contains(error)) { - System.out.println("[!] Input error: " + error); - System.out.println(" Verify your gt (captcha_id) and page URL are correct."); - } else if (PROXY_ERRORS.contains(error)) { - System.out.println("[!] Proxy error: " + error); - System.out.println(" Check your proxy configuration or try a different proxy."); - } else { - System.out.println("[!] Submission failed: " + error); - } - } -} diff --git a/articles/how-to-solve-geetest-v4-using-api/kotlin/solve.kt b/articles/how-to-solve-geetest-v4-using-api/kotlin/solve.kt deleted file mode 100644 index f2ff0f9..0000000 --- a/articles/how-to-solve-geetest-v4-using-api/kotlin/solve.kt +++ /dev/null @@ -1,250 +0,0 @@ -// Solve GeeTest v4 using the CaptchaAI API. -// -// Usage: -// kotlinc solve.kt -include-runtime -d solve.jar -// java -jar solve.jar - -import java.io.BufferedReader -import java.io.InputStreamReader -import java.net.HttpURLConnection -import java.net.URL -import java.net.URLEncoder -import java.io.File - -val SUBMIT_URL = "https://ocr.captchaai.com/in.php" -val RESULT_URL = "https://ocr.captchaai.com/res.php" - -val AUTH_ERRORS = setOf("ERROR_WRONG_USER_KEY", "ERROR_KEY_DOES_NOT_EXIST", "IP_BANNED") -val BALANCE_ERRORS = setOf("ERROR_ZERO_BALANCE") -val INPUT_ERRORS = setOf("ERROR_PAGEURL", "ERROR_WRONG_GOOGLEKEY", "ERROR_BAD_PARAMETERS", "ERROR_BAD_TOKEN_OR_PAGEURL") -val TRANSIENT_ERRORS = setOf("ERROR_SERVER_ERROR", "ERROR_INTERNAL_SERVER_ERROR") -val SOLVE_ERRORS = setOf("ERROR_CAPTCHA_UNSOLVABLE") -val PROXY_ERRORS = setOf("ERROR_BAD_PROXY", "ERROR_PROXY_CONNECTION_FAILED") - -fun loadEnv(path: String): Map { - val env = mutableMapOf() - val file = File(path) - if (!file.exists()) return env - file.readLines().forEach { line -> - val trimmed = line.trim() - if (trimmed.isNotEmpty() && !trimmed.startsWith("#")) { - val eq = trimmed.indexOf('=') - if (eq > 0) { - env[trimmed.substring(0, eq).trim()] = trimmed.substring(eq + 1).trim() - } - } - } - return env -} - -fun getEnv(env: Map, key: String, fallback: String = ""): String { - val v = env[key] - if (!v.isNullOrEmpty()) return v - val sv = System.getenv(key) - if (!sv.isNullOrEmpty()) return sv - return fallback -} - -fun httpGet(urlStr: String): String { - val conn = URL(urlStr).openConnection() as HttpURLConnection - conn.connectTimeout = 30000 - conn.readTimeout = 30000 - val reader = BufferedReader(InputStreamReader(conn.inputStream)) - val result = reader.readText() - reader.close() - return result -} - -fun jsonStr(json: String, key: String): String { - val pattern = "\"$key\":\"" - val idx = json.indexOf(pattern) - if (idx < 0) return "" - val start = idx + pattern.length - val end = json.indexOf("\"", start) - if (end < 0) return "" - return json.substring(start, end) -} - -fun jsonInt(json: String, key: String): Int { - val pattern = "\"$key\":" - val idx = json.indexOf(pattern) - if (idx < 0) return 0 - val start = idx + pattern.length - val numStr = json.substring(start).takeWhile { it.isDigit() || it == '-' } - return numStr.toIntOrNull() ?: 0 -} - -fun extractRequestJson(json: String): String { - val pattern = "\"request\":" - val idx = json.indexOf(pattern) - if (idx < 0) return "" - val rest = json.substring(idx + pattern.length).trimStart() - if (rest.startsWith("\"")) { - // JSON string — find closing quote with escape handling - val inner = rest.substring(1) - var end = 0 - while (end < inner.length) { - if (inner[end] == '\\') { end += 2; continue } - if (inner[end] == '"') break - end++ - } - return inner.substring(0, end).replace("\\\"", "\"").replace("\\\\", "\\") - } else if (rest.startsWith("{")) { - // JSON object — find matching brace - var depth = 0 - for (i in rest.indices) { - if (rest[i] == '{') depth++ - else if (rest[i] == '}') { depth--; if (depth == 0) return rest.substring(0, i + 1) } - } - } - return "" -} - -fun handleError(error: String) { - when { - error in AUTH_ERRORS -> { - println("[!] Authentication error: $error") - println(" Check your API key at https://captchaai.com/dashboard") - } - error in BALANCE_ERRORS -> { - println("[!] Balance error: $error") - println(" Top up your account at https://captchaai.com") - } - error in INPUT_ERRORS -> { - println("[!] Input error: $error") - println(" Verify your gt (captcha_id) and page URL are correct.") - } - error in PROXY_ERRORS -> { - println("[!] Proxy error: $error") - println(" Check your proxy configuration or try a different proxy.") - } - else -> println("[!] Submission failed: $error") - } -} - -fun enc(s: String) = URLEncoder.encode(s, "UTF-8") - -fun main() { - val env = loadEnv("../.env") - val apiKey = getEnv(env, "CAPTCHAAI_API_KEY") - val gt = getEnv(env, "CAPTCHA_GT") - val pageurl = getEnv(env, "CAPTCHA_PAGEURL") - val pollInterval = getEnv(env, "POLL_INTERVAL", "5").toInt() - val maxTimeout = getEnv(env, "MAX_TIMEOUT", "120").toInt() - - // Validate - if (apiKey.isEmpty() || apiKey == "YOUR_API_KEY") { - println("[!] ERROR: CAPTCHAAI_API_KEY is not set.") - println(" Copy .env.example to .env and add your real API key.") - System.exit(1) - } - if (gt.isEmpty() || gt == "YOUR_CAPTCHA_ID") { - println("[!] ERROR: CAPTCHA_GT is not set.") - println(" Find the captcha_id in the page source or GeeTest v4 initialization call.") - System.exit(1) - } - if (pageurl.isEmpty() || pageurl == "https://example.com") { - println("[!] WARNING: CAPTCHA_PAGEURL may not be set correctly.") - println(" Make sure it points to the actual target page.") - } - - // Submit task - println("[*] Submitting GeeTest v4 task...") - val submitParams = "key=${enc(apiKey)}&method=geetest>=${enc(gt)}&pageurl=${enc(pageurl)}&version=4&json=1" - - val submitResp = try { - httpGet("$SUBMIT_URL?$submitParams") - } catch (e: Exception) { - println("[!] Network error during submission: ${e.message}") - System.exit(1) - return - } - - val submitStatus = jsonInt(submitResp, "status") - val submitRequest = jsonStr(submitResp, "request") - - if (submitStatus != 1) { - handleError(submitRequest) - System.exit(1) - } - - val taskId = submitRequest - println("[+] Task submitted. ID: $taskId") - - // Poll for result - println("[*] Waiting 15s before first poll...") - Thread.sleep(15000) - - var elapsed = 15 - var attempt = 0 - var backoff = pollInterval - - while (elapsed < maxTimeout) { - attempt++ - println("[*] Polling for result (attempt $attempt)...") - - val pollParams = "key=${enc(apiKey)}&action=get&id=${enc(taskId)}&json=1" - - val resultResp = try { - httpGet("$RESULT_URL?$pollParams") - } catch (e: Exception) { - println("[!] Network error during polling: ${e.message}") - Thread.sleep(backoff * 1000L) - elapsed += backoff - backoff = minOf(backoff * 2, 30) - continue - } - - val status = jsonInt(resultResp, "status") - - if (status == 1) { - // The request field contains a JSON string or object with the 5 GeeTest v4 values - val solutionJson = extractRequestJson(resultResp) - val captchaId = jsonStr(solutionJson, "captcha_id") - val lotNumber = jsonStr(solutionJson, "lot_number") - val passToken = jsonStr(solutionJson, "pass_token") - val genTime = jsonStr(solutionJson, "gen_time") - val captchaOutput = jsonStr(solutionJson, "captcha_output") - println("[+] Solved!") - println("[+] captcha_id: $captchaId") - println("[+] lot_number: $lotNumber") - println("[+] pass_token: $passToken") - println("[+] gen_time: $genTime") - println("[+] captcha_output: $captchaOutput") - println() - println("Next step: submit these five values to the site's") - println("GeeTest v4 verification endpoint.") - return - } - - val request = jsonStr(resultResp, "request") - - if (request == "CAPCHA_NOT_READY") { - println("[*] Not ready yet, waiting ${pollInterval}s...") - Thread.sleep(pollInterval * 1000L) - elapsed += pollInterval - backoff = pollInterval - continue - } - - if (request in TRANSIENT_ERRORS) { - println("[!] Transient error: $request, retrying in ${backoff}s...") - Thread.sleep(backoff * 1000L) - elapsed += backoff - backoff = minOf(backoff * 2, 30) - continue - } - - if (request in SOLVE_ERRORS) { - println("[!] Solve error: $request") - println(" The CAPTCHA could not be solved. Verify parameters and retry.") - System.exit(1) - } - - println("[!] Unexpected error: $request") - System.exit(1) - } - - println("[!] Timeout: no solution received within ${maxTimeout} seconds.") - System.exit(1) -} diff --git a/articles/how-to-solve-geetest-v4-using-api/node/package.json b/articles/how-to-solve-geetest-v4-using-api/node/package.json deleted file mode 100644 index d63fd8a..0000000 --- a/articles/how-to-solve-geetest-v4-using-api/node/package.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "name": "captchaai-geetest-v4-example", - "version": "1.0.0", - "description": "Solve GeeTest v4 using CaptchaAI API", - "main": "solve.js", - "scripts": { - "start": "node solve.js" - }, - "dependencies": { - "axios": "^1.6.0", - "dotenv": "^16.3.0" - }, - "license": "MIT" -} diff --git a/articles/how-to-solve-geetest-v4-using-api/node/solve.js b/articles/how-to-solve-geetest-v4-using-api/node/solve.js deleted file mode 100644 index 6ac8f6a..0000000 --- a/articles/how-to-solve-geetest-v4-using-api/node/solve.js +++ /dev/null @@ -1,177 +0,0 @@ -/** - * Solve GeeTest v4 using the CaptchaAI API. - * - * Usage: - * npm install - * cp ../.env.example ../.env // then edit with your credentials - * node solve.js - */ - -require("dotenv").config({ path: require("path").join(__dirname, "..", ".env") }); -const axios = require("axios"); - -const SUBMIT_URL = "https://ocr.captchaai.com/in.php"; -const RESULT_URL = "https://ocr.captchaai.com/res.php"; - -const API_KEY = process.env.CAPTCHAAI_API_KEY || ""; -const CAPTCHA_GT = process.env.CAPTCHA_GT || ""; -const CAPTCHA_PAGEURL = process.env.CAPTCHA_PAGEURL || ""; -const POLL_INTERVAL = parseInt(process.env.POLL_INTERVAL || "5", 10); -const MAX_TIMEOUT = parseInt(process.env.MAX_TIMEOUT || "120", 10); - -const AUTH_ERRORS = new Set(["ERROR_WRONG_USER_KEY", "ERROR_KEY_DOES_NOT_EXIST", "IP_BANNED"]); -const BALANCE_ERRORS = new Set(["ERROR_ZERO_BALANCE"]); -const INPUT_ERRORS = new Set(["ERROR_PAGEURL", "ERROR_WRONG_GOOGLEKEY", "ERROR_BAD_PARAMETERS", "ERROR_BAD_TOKEN_OR_PAGEURL"]); -const TRANSIENT_ERRORS = new Set(["ERROR_SERVER_ERROR", "ERROR_INTERNAL_SERVER_ERROR"]); -const SOLVE_ERRORS = new Set(["ERROR_CAPTCHA_UNSOLVABLE"]); -const PROXY_ERRORS = new Set(["ERROR_BAD_PROXY", "ERROR_PROXY_CONNECTION_FAILED"]); - -function sleep(seconds) { - return new Promise((resolve) => setTimeout(resolve, seconds * 1000)); -} - -function validateConfig() { - if (!API_KEY || API_KEY === "YOUR_API_KEY") { - console.log("[!] ERROR: CAPTCHAAI_API_KEY is not set."); - console.log(" Copy .env.example to .env and add your real API key."); - process.exit(1); - } - if (!CAPTCHA_GT || CAPTCHA_GT === "YOUR_CAPTCHA_ID") { - console.log("[!] ERROR: CAPTCHA_GT is not set."); - console.log(" Find the captcha_id in the page source or GeeTest v4 initialization call."); - process.exit(1); - } - if (!CAPTCHA_PAGEURL || CAPTCHA_PAGEURL === "https://example.com") { - console.log("[!] WARNING: CAPTCHA_PAGEURL may not be set correctly."); - console.log(" Make sure it points to the actual target page."); - } -} - -async function submitTask() { - console.log("[*] Submitting GeeTest v4 task..."); - - const params = { - key: API_KEY, - method: "geetest", - gt: CAPTCHA_GT, - pageurl: CAPTCHA_PAGEURL, - version: "4", - json: "1", - }; - - let resp; - try { - resp = await axios.get(SUBMIT_URL, { params, timeout: 30000 }); - } catch (err) { - console.log(`[!] Network error during submission: ${err.message}`); - process.exit(1); - } - - const data = resp.data; - if (data.status !== 1) { - const error = data.request || "UNKNOWN_ERROR"; - if (AUTH_ERRORS.has(error)) { - console.log(`[!] Authentication error: ${error}`); - console.log(" Check your API key at https://captchaai.com/dashboard"); - } else if (BALANCE_ERRORS.has(error)) { - console.log(`[!] Balance error: ${error}`); - console.log(" Top up your account at https://captchaai.com"); - } else if (INPUT_ERRORS.has(error)) { - console.log(`[!] Input error: ${error}`); - console.log(" Verify your gt (captcha_id) and page URL are correct."); - } else if (PROXY_ERRORS.has(error)) { - console.log(`[!] Proxy error: ${error}`); - console.log(" Check your proxy configuration or try a different proxy."); - } else { - console.log(`[!] Submission failed: ${error}`); - } - process.exit(1); - } - - const taskId = data.request; - console.log(`[+] Task submitted. ID: ${taskId}`); - return taskId; -} - -async function pollResult(taskId) { - console.log("[*] Waiting 15s before first poll..."); - await sleep(15); - - const params = { key: API_KEY, action: "get", id: taskId, json: "1" }; - let elapsed = 15; - let attempt = 0; - let backoff = POLL_INTERVAL; - - while (elapsed < MAX_TIMEOUT) { - attempt++; - console.log(`[*] Polling for result (attempt ${attempt})...`); - - let resp; - try { - resp = await axios.get(RESULT_URL, { params, timeout: 30000 }); - } catch (err) { - console.log(`[!] Network error during polling: ${err.message}`); - await sleep(backoff); - elapsed += backoff; - backoff = Math.min(backoff * 2, 30); - continue; - } - - const data = resp.data; - - if (data.status === 1) { - // The request field contains a JSON string with the 5 GeeTest v4 values - let solution = data.request; - if (typeof solution === "string") { - solution = JSON.parse(solution); - } - return solution; - } - - const error = data.request || ""; - if (error === "CAPCHA_NOT_READY") { - console.log(`[*] Not ready yet, waiting ${POLL_INTERVAL}s...`); - await sleep(POLL_INTERVAL); - elapsed += POLL_INTERVAL; - backoff = POLL_INTERVAL; - continue; - } - - if (TRANSIENT_ERRORS.has(error)) { - console.log(`[!] Transient error: ${error}, retrying in ${backoff}s...`); - await sleep(backoff); - elapsed += backoff; - backoff = Math.min(backoff * 2, 30); - continue; - } - - if (SOLVE_ERRORS.has(error)) { - console.log(`[!] Solve error: ${error}`); - console.log(" The CAPTCHA could not be solved. Verify parameters and retry."); - process.exit(1); - } - - console.log(`[!] Unexpected error: ${error}`); - process.exit(1); - } - - console.log(`[!] Timeout: no solution received within ${MAX_TIMEOUT} seconds.`); - process.exit(1); -} - -async function main() { - validateConfig(); - const taskId = await submitTask(); - const solution = await pollResult(taskId); - console.log("[+] Solved!"); - console.log(`[+] captcha_id: ${solution.captcha_id}`); - console.log(`[+] lot_number: ${solution.lot_number}`); - console.log(`[+] pass_token: ${solution.pass_token}`); - console.log(`[+] gen_time: ${solution.gen_time}`); - console.log(`[+] captcha_output: ${solution.captcha_output}`); - console.log(); - console.log("Next step: submit these five values to the site's"); - console.log("GeeTest v4 verification endpoint."); -} - -main(); diff --git a/articles/how-to-solve-geetest-v4-using-api/php/composer.json b/articles/how-to-solve-geetest-v4-using-api/php/composer.json deleted file mode 100644 index 1dfca82..0000000 --- a/articles/how-to-solve-geetest-v4-using-api/php/composer.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "name": "captchaai/geetest-v4-example", - "description": "Solve GeeTest v4 using CaptchaAI API", - "require": { - "vlucas/phpdotenv": "^5.5" - } -} diff --git a/articles/how-to-solve-geetest-v4-using-api/php/solve.php b/articles/how-to-solve-geetest-v4-using-api/php/solve.php deleted file mode 100644 index f283cd2..0000000 --- a/articles/how-to-solve-geetest-v4-using-api/php/solve.php +++ /dev/null @@ -1,167 +0,0 @@ -load(); - -define('SUBMIT_URL', 'https://ocr.captchaai.com/in.php'); -define('RESULT_URL', 'https://ocr.captchaai.com/res.php'); - -$apiKey = $_ENV['CAPTCHAAI_API_KEY'] ?? ''; -$gt = $_ENV['CAPTCHA_GT'] ?? ''; -$pageurl = $_ENV['CAPTCHA_PAGEURL'] ?? ''; -$pollInterval = (int)($_ENV['POLL_INTERVAL'] ?? 5); -$maxTimeout = (int)($_ENV['MAX_TIMEOUT'] ?? 120); - -$authErrors = ['ERROR_WRONG_USER_KEY', 'ERROR_KEY_DOES_NOT_EXIST', 'IP_BANNED']; -$balanceErrors = ['ERROR_ZERO_BALANCE']; -$inputErrors = ['ERROR_PAGEURL', 'ERROR_WRONG_GOOGLEKEY', 'ERROR_BAD_PARAMETERS', 'ERROR_BAD_TOKEN_OR_PAGEURL']; -$transientErrors = ['ERROR_SERVER_ERROR', 'ERROR_INTERNAL_SERVER_ERROR']; -$solveErrors = ['ERROR_CAPTCHA_UNSOLVABLE']; -$proxyErrors = ['ERROR_BAD_PROXY', 'ERROR_PROXY_CONNECTION_FAILED']; - -// --- Validate configuration --- -if (empty($apiKey) || $apiKey === 'YOUR_API_KEY') { - echo "[!] ERROR: CAPTCHAAI_API_KEY is not set.\n"; - echo " Copy .env.example to .env and add your real API key.\n"; - exit(1); -} -if (empty($gt) || $gt === 'YOUR_CAPTCHA_ID') { - echo "[!] ERROR: CAPTCHA_GT is not set.\n"; - echo " Find the captcha_id in the page source or GeeTest v4 initialization call.\n"; - exit(1); -} -if (empty($pageurl) || $pageurl === 'https://example.com') { - echo "[!] WARNING: CAPTCHA_PAGEURL may not be set correctly.\n"; - echo " Make sure it points to the actual target page.\n"; -} - -// --- Submit task --- -echo "[*] Submitting GeeTest v4 task...\n"; -$submitParams = [ - 'key' => $apiKey, - 'method' => 'geetest', - 'gt' => $gt, - 'pageurl' => $pageurl, - 'version' => '4', - 'json' => '1', -]; -$submitQuery = http_build_query($submitParams); - -$ctx = stream_context_create(['http' => ['timeout' => 30]]); -$submitResponse = @file_get_contents(SUBMIT_URL . '?' . $submitQuery, false, $ctx); -if ($submitResponse === false) { - echo "[!] Network error during submission.\n"; - exit(1); -} - -$submitData = json_decode($submitResponse, true); -if (($submitData['status'] ?? 0) !== 1) { - $error = $submitData['request'] ?? 'UNKNOWN_ERROR'; - if (in_array($error, $authErrors)) { - echo "[!] Authentication error: $error\n"; - echo " Check your API key at https://captchaai.com/dashboard\n"; - } elseif (in_array($error, $balanceErrors)) { - echo "[!] Balance error: $error\n"; - echo " Top up your account at https://captchaai.com\n"; - } elseif (in_array($error, $inputErrors)) { - echo "[!] Input error: $error\n"; - echo " Verify your gt (captcha_id) and page URL are correct.\n"; - } elseif (in_array($error, $proxyErrors)) { - echo "[!] Proxy error: $error\n"; - echo " Check your proxy configuration or try a different proxy.\n"; - } else { - echo "[!] Submission failed: $error\n"; - } - exit(1); -} - -$taskId = $submitData['request']; -echo "[+] Task submitted. ID: $taskId\n"; - -// --- Poll for result --- -echo "[*] Waiting 15s before first poll...\n"; -sleep(15); - -$elapsed = 15; -$attempt = 0; -$backoff = $pollInterval; - -while ($elapsed < $maxTimeout) { - $attempt++; - echo "[*] Polling for result (attempt $attempt)...\n"; - - $resultParams = http_build_query([ - 'key' => $apiKey, - 'action' => 'get', - 'id' => $taskId, - 'json' => '1', - ]); - - $resultResponse = @file_get_contents(RESULT_URL . '?' . $resultParams, false, $ctx); - if ($resultResponse === false) { - echo "[!] Network error during polling.\n"; - sleep($backoff); - $elapsed += $backoff; - $backoff = min($backoff * 2, 30); - continue; - } - - $resultData = json_decode($resultResponse, true); - - if (($resultData['status'] ?? 0) === 1) { - // The request field contains a JSON string with the 5 GeeTest v4 values - $solution = $resultData['request']; - if (is_string($solution)) { - $solution = json_decode($solution, true); - } - echo "[+] Solved!\n"; - echo "[+] captcha_id: " . $solution['captcha_id'] . "\n"; - echo "[+] lot_number: " . $solution['lot_number'] . "\n"; - echo "[+] pass_token: " . $solution['pass_token'] . "\n"; - echo "[+] gen_time: " . $solution['gen_time'] . "\n"; - echo "[+] captcha_output: " . $solution['captcha_output'] . "\n"; - echo "\n"; - echo "Next step: submit these five values to the site's\n"; - echo "GeeTest v4 verification endpoint.\n"; - exit(0); - } - - $error = $resultData['request'] ?? ''; - if ($error === 'CAPCHA_NOT_READY') { - echo "[*] Not ready yet, waiting {$pollInterval}s...\n"; - sleep($pollInterval); - $elapsed += $pollInterval; - $backoff = $pollInterval; - continue; - } - - if (in_array($error, $transientErrors)) { - echo "[!] Transient error: $error, retrying in {$backoff}s...\n"; - sleep($backoff); - $elapsed += $backoff; - $backoff = min($backoff * 2, 30); - continue; - } - - if (in_array($error, $solveErrors)) { - echo "[!] Solve error: $error\n"; - echo " The CAPTCHA could not be solved. Verify parameters and retry.\n"; - exit(1); - } - - echo "[!] Unexpected error: $error\n"; - exit(1); -} - -echo "[!] Timeout: no solution received within {$maxTimeout} seconds.\n"; -exit(1); diff --git a/articles/how-to-solve-geetest-v4-using-api/python/requirements.txt b/articles/how-to-solve-geetest-v4-using-api/python/requirements.txt deleted file mode 100644 index f49b6b8..0000000 --- a/articles/how-to-solve-geetest-v4-using-api/python/requirements.txt +++ /dev/null @@ -1,2 +0,0 @@ -requests>=2.28.0 -python-dotenv>=1.0.0 diff --git a/articles/how-to-solve-geetest-v4-using-api/python/solve.py b/articles/how-to-solve-geetest-v4-using-api/python/solve.py deleted file mode 100644 index 9974040..0000000 --- a/articles/how-to-solve-geetest-v4-using-api/python/solve.py +++ /dev/null @@ -1,179 +0,0 @@ -"""Solve GeeTest v4 using the CaptchaAI API. - -Usage: - pip install -r requirements.txt - cp ../.env.example ../.env # then edit with your credentials - python solve.py -""" - -import os -import sys -import time -import json - -import requests -from dotenv import load_dotenv - -# Load environment variables from the parent .env file -load_dotenv(dotenv_path=os.path.join(os.path.dirname(__file__), "..", ".env")) - -SUBMIT_URL = "https://ocr.captchaai.com/in.php" -RESULT_URL = "https://ocr.captchaai.com/res.php" - -API_KEY = os.getenv("CAPTCHAAI_API_KEY", "") -CAPTCHA_GT = os.getenv("CAPTCHA_GT", "") -CAPTCHA_PAGEURL = os.getenv("CAPTCHA_PAGEURL", "") -POLL_INTERVAL = int(os.getenv("POLL_INTERVAL", "5")) -MAX_TIMEOUT = int(os.getenv("MAX_TIMEOUT", "120")) - -# --- Error categories --- -AUTH_ERRORS = {"ERROR_WRONG_USER_KEY", "ERROR_KEY_DOES_NOT_EXIST", "IP_BANNED"} -BALANCE_ERRORS = {"ERROR_ZERO_BALANCE"} -INPUT_ERRORS = {"ERROR_PAGEURL", "ERROR_WRONG_GOOGLEKEY", "ERROR_BAD_PARAMETERS", "ERROR_BAD_TOKEN_OR_PAGEURL"} -TRANSIENT_ERRORS = {"ERROR_SERVER_ERROR", "ERROR_INTERNAL_SERVER_ERROR"} -SOLVE_ERRORS = {"ERROR_CAPTCHA_UNSOLVABLE"} -PROXY_ERRORS = {"ERROR_BAD_PROXY", "ERROR_PROXY_CONNECTION_FAILED"} - - -def validate_config() -> None: - """Check that required environment variables are set.""" - if not API_KEY or API_KEY == "YOUR_API_KEY": - print("[!] ERROR: CAPTCHAAI_API_KEY is not set.") - print(" Copy .env.example to .env and add your real API key.") - sys.exit(1) - if not CAPTCHA_GT or CAPTCHA_GT == "YOUR_CAPTCHA_ID": - print("[!] ERROR: CAPTCHA_GT is not set.") - print(" Find the captcha_id in the page source or GeeTest v4 initialization call.") - sys.exit(1) - if not CAPTCHA_PAGEURL or CAPTCHA_PAGEURL == "https://example.com": - print("[!] WARNING: CAPTCHA_PAGEURL may not be set correctly.") - print(" Make sure it points to the actual target page.") - - -def submit_task() -> str: - """Submit the CAPTCHA task and return the task ID.""" - print("[*] Submitting GeeTest v4 task...") - payload = { - "key": API_KEY, - "method": "geetest", - "gt": CAPTCHA_GT, - "pageurl": CAPTCHA_PAGEURL, - "version": "4", - "json": "1", - } - - try: - resp = requests.get(SUBMIT_URL, params=payload, timeout=30) - resp.raise_for_status() - except requests.RequestException as exc: - print(f"[!] Network error during submission: {exc}") - sys.exit(1) - - data = resp.json() - - if data.get("status") != 1: - error = data.get("request", "UNKNOWN_ERROR") - if error in AUTH_ERRORS: - print(f"[!] Authentication error: {error}") - print(" Check your API key at https://captchaai.com/dashboard") - elif error in BALANCE_ERRORS: - print(f"[!] Balance error: {error}") - print(" Top up your account at https://captchaai.com") - elif error in INPUT_ERRORS: - print(f"[!] Input error: {error}") - print(" Verify your gt (captcha_id) and page URL are correct.") - elif error in PROXY_ERRORS: - print(f"[!] Proxy error: {error}") - print(" Check your proxy configuration or try a different proxy.") - else: - print(f"[!] Submission failed: {error}") - sys.exit(1) - - task_id = data["request"] - print(f"[+] Task submitted. ID: {task_id}") - return task_id - - -def poll_result(task_id: str) -> dict: - """Poll for the CAPTCHA solution with timeout and retry logic.""" - print("[*] Waiting 15s before first poll...") - time.sleep(15) - - params = { - "key": API_KEY, - "action": "get", - "id": task_id, - "json": "1", - } - - elapsed = 15 - attempt = 0 - backoff = POLL_INTERVAL - - while elapsed < MAX_TIMEOUT: - attempt += 1 - print(f"[*] Polling for result (attempt {attempt})...") - - try: - resp = requests.get(RESULT_URL, params=params, timeout=30) - resp.raise_for_status() - except requests.RequestException as exc: - print(f"[!] Network error during polling: {exc}") - time.sleep(backoff) - elapsed += backoff - backoff = min(backoff * 2, 30) - continue - - data = resp.json() - - if data.get("status") == 1: - # The request field contains a JSON string with the 5 GeeTest v4 values - solution = data["request"] - if isinstance(solution, str): - solution = json.loads(solution) - return solution - - error = data.get("request", "") - if error == "CAPCHA_NOT_READY": - print(f"[*] Not ready yet, waiting {POLL_INTERVAL}s...") - time.sleep(POLL_INTERVAL) - elapsed += POLL_INTERVAL - backoff = POLL_INTERVAL - continue - - if error in TRANSIENT_ERRORS: - print(f"[!] Transient error: {error}, retrying in {backoff}s...") - time.sleep(backoff) - elapsed += backoff - backoff = min(backoff * 2, 30) - continue - - if error in SOLVE_ERRORS: - print(f"[!] Solve error: {error}") - print(" The CAPTCHA could not be solved. Verify parameters and retry.") - sys.exit(1) - - print(f"[!] Unexpected error: {error}") - sys.exit(1) - - print(f"[!] Timeout: no solution received within {MAX_TIMEOUT} seconds.") - sys.exit(1) - - -def main() -> None: - validate_config() - task_id = submit_task() - solution = poll_result(task_id) - print("[+] Solved!") - print(f"[+] captcha_id: {solution['captcha_id']}") - print(f"[+] lot_number: {solution['lot_number']}") - print(f"[+] pass_token: {solution['pass_token']}") - print(f"[+] gen_time: {solution['gen_time']}") - print(f"[+] captcha_output: {solution['captcha_output']}") - print() - print("Next step: submit these five values to the site's") - print("GeeTest v4 verification endpoint.") - - -if __name__ == "__main__": - main() diff --git a/articles/how-to-solve-geetest-v4-using-api/ruby/Gemfile b/articles/how-to-solve-geetest-v4-using-api/ruby/Gemfile deleted file mode 100644 index 05a677e..0000000 --- a/articles/how-to-solve-geetest-v4-using-api/ruby/Gemfile +++ /dev/null @@ -1,2 +0,0 @@ -source "https://rubygems.org" -# No external gems needed — uses Ruby stdlib (net/http, json, uri) diff --git a/articles/how-to-solve-geetest-v4-using-api/ruby/solve.rb b/articles/how-to-solve-geetest-v4-using-api/ruby/solve.rb deleted file mode 100644 index 6627d61..0000000 --- a/articles/how-to-solve-geetest-v4-using-api/ruby/solve.rb +++ /dev/null @@ -1,191 +0,0 @@ -# Solve GeeTest v4 using the CaptchaAI API. -# -# Usage: -# ruby solve.rb - -require "net/http" -require "json" -require "uri" - -SUBMIT_URL = "https://ocr.captchaai.com/in.php" -RESULT_URL = "https://ocr.captchaai.com/res.php" - -AUTH_ERRORS = %w[ERROR_WRONG_USER_KEY ERROR_KEY_DOES_NOT_EXIST IP_BANNED].freeze -BALANCE_ERRORS = %w[ERROR_ZERO_BALANCE].freeze -INPUT_ERRORS = %w[ERROR_PAGEURL ERROR_WRONG_GOOGLEKEY ERROR_BAD_PARAMETERS ERROR_BAD_TOKEN_OR_PAGEURL].freeze -TRANSIENT_ERRORS = %w[ERROR_SERVER_ERROR ERROR_INTERNAL_SERVER_ERROR].freeze -SOLVE_ERRORS = %w[ERROR_CAPTCHA_UNSOLVABLE].freeze -PROXY_ERRORS = %w[ERROR_BAD_PROXY ERROR_PROXY_CONNECTION_FAILED].freeze - -def load_env(path) - env = {} - return env unless File.exist?(path) - File.readlines(path).each do |line| - line = line.strip - next if line.empty? || line.start_with?("#") - key, value = line.split("=", 2) - env[key.strip] = value&.strip || "" - end - env -end - -def get_env(env, key, fallback = "") - v = env[key] - return v if v && !v.empty? - v = ENV[key] - return v if v && !v.empty? - fallback -end - -env = load_env(File.join(__dir__, "..", ".env")) -api_key = get_env(env, "CAPTCHAAI_API_KEY") -gt = get_env(env, "CAPTCHA_GT") -pageurl = get_env(env, "CAPTCHA_PAGEURL") -poll_interval = get_env(env, "POLL_INTERVAL", "5").to_i -max_timeout = get_env(env, "MAX_TIMEOUT", "120").to_i - -# Validate -if api_key.empty? || api_key == "YOUR_API_KEY" - puts "[!] ERROR: CAPTCHAAI_API_KEY is not set." - puts " Copy .env.example to .env and add your real API key." - exit 1 -end -if gt.empty? || gt == "YOUR_CAPTCHA_ID" - puts "[!] ERROR: CAPTCHA_GT is not set." - puts " Find the captcha_id in the page source or GeeTest v4 initialization call." - exit 1 -end -if pageurl.empty? || pageurl == "https://example.com" - puts "[!] WARNING: CAPTCHA_PAGEURL may not be set correctly." - puts " Make sure it points to the actual target page." -end - -def handle_error(error) - if AUTH_ERRORS.include?(error) - puts "[!] Authentication error: #{error}" - puts " Check your API key at https://captchaai.com/dashboard" - elsif BALANCE_ERRORS.include?(error) - puts "[!] Balance error: #{error}" - puts " Top up your account at https://captchaai.com" - elsif INPUT_ERRORS.include?(error) - puts "[!] Input error: #{error}" - puts " Verify your gt (captcha_id) and page URL are correct." - elsif PROXY_ERRORS.include?(error) - puts "[!] Proxy error: #{error}" - puts " Check your proxy configuration or try a different proxy." - else - puts "[!] Submission failed: #{error}" - end -end - -def http_get(url_str) - uri = URI(url_str) - http = Net::HTTP.new(uri.host, uri.port) - http.use_ssl = true - http.open_timeout = 30 - http.read_timeout = 30 - response = http.get("#{uri.path}?#{uri.query}") - JSON.parse(response.body) -end - -# Submit task -puts "[*] Submitting GeeTest v4 task..." -submit_params = { - key: api_key, - method: "geetest", - gt: gt, - pageurl: pageurl, - version: "4", - json: "1" -} -params = URI.encode_www_form(submit_params) - -begin - submit_data = http_get("#{SUBMIT_URL}?#{params}") -rescue StandardError => e - puts "[!] Network error during submission: #{e.message}" - exit 1 -end - -unless submit_data["status"] == 1 - handle_error(submit_data["request"] || "UNKNOWN_ERROR") - exit 1 -end - -task_id = submit_data["request"] -puts "[+] Task submitted. ID: #{task_id}" - -# Poll for result -puts "[*] Waiting 15s before first poll..." -sleep 15 - -elapsed = 15 -attempt = 0 -backoff = poll_interval - -while elapsed < max_timeout - attempt += 1 - puts "[*] Polling for result (attempt #{attempt})..." - - poll_params = URI.encode_www_form( - key: api_key, - action: "get", - id: task_id, - json: "1" - ) - - begin - result_data = http_get("#{RESULT_URL}?#{poll_params}") - rescue StandardError => e - puts "[!] Network error during polling: #{e.message}" - sleep backoff - elapsed += backoff - backoff = [backoff * 2, 30].min - next - end - - if result_data["status"] == 1 - # The request field contains a JSON string or object with the 5 GeeTest v4 values - solution = result_data["request"] - solution = JSON.parse(solution) if solution.is_a?(String) - puts "[+] Solved!" - puts "[+] captcha_id: #{solution['captcha_id']}" - puts "[+] lot_number: #{solution['lot_number']}" - puts "[+] pass_token: #{solution['pass_token']}" - puts "[+] gen_time: #{solution['gen_time']}" - puts "[+] captcha_output: #{solution['captcha_output']}" - puts - puts "Next step: submit these five values to the site's" - puts "GeeTest v4 verification endpoint." - exit 0 - end - - error = result_data["request"] || "" - if error == "CAPCHA_NOT_READY" - puts "[*] Not ready yet, waiting #{poll_interval}s..." - sleep poll_interval - elapsed += poll_interval - backoff = poll_interval - next - end - - if TRANSIENT_ERRORS.include?(error) - puts "[!] Transient error: #{error}, retrying in #{backoff}s..." - sleep backoff - elapsed += backoff - backoff = [backoff * 2, 30].min - next - end - - if SOLVE_ERRORS.include?(error) - puts "[!] Solve error: #{error}" - puts " The CAPTCHA could not be solved. Verify parameters and retry." - exit 1 - end - - puts "[!] Unexpected error: #{error}" - exit 1 -end - -puts "[!] Timeout: no solution received within #{max_timeout} seconds." -exit 1 diff --git a/articles/how-to-solve-geetest-v4-using-api/rust/Cargo.toml b/articles/how-to-solve-geetest-v4-using-api/rust/Cargo.toml deleted file mode 100644 index 8c10bc5..0000000 --- a/articles/how-to-solve-geetest-v4-using-api/rust/Cargo.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -name = "captchaai-geetest-v4-example" -version = "1.0.0" -edition = "2021" - -[dependencies] -ureq = "2" -serde_json = "1" -urlencoding = "2" diff --git a/articles/how-to-solve-geetest-v4-using-api/rust/src/main.rs b/articles/how-to-solve-geetest-v4-using-api/rust/src/main.rs deleted file mode 100644 index 06d2f68..0000000 --- a/articles/how-to-solve-geetest-v4-using-api/rust/src/main.rs +++ /dev/null @@ -1,260 +0,0 @@ -// Solve GeeTest v4 using the CaptchaAI API. -// -// Usage: -// cargo run - -use std::collections::HashMap; -use std::fs; -use std::thread; -use std::time::Duration; - -const SUBMIT_URL: &str = "https://ocr.captchaai.com/in.php"; -const RESULT_URL: &str = "https://ocr.captchaai.com/res.php"; - -fn load_env(path: &str) -> HashMap { - let mut env = HashMap::new(); - if let Ok(content) = fs::read_to_string(path) { - for line in content.lines() { - let trimmed = line.trim(); - if trimmed.is_empty() || trimmed.starts_with('#') { - continue; - } - if let Some((key, value)) = trimmed.split_once('=') { - env.insert(key.trim().to_string(), value.trim().to_string()); - } - } - } - env -} - -fn get_env(env: &HashMap, key: &str, fallback: &str) -> String { - if let Some(v) = env.get(key) { - if !v.is_empty() { - return v.clone(); - } - } - if let Ok(v) = std::env::var(key) { - if !v.is_empty() { - return v; - } - } - fallback.to_string() -} - -fn json_str(json: &str, key: &str) -> String { - let pattern = format!("\"{}\":\"", key); - if let Some(idx) = json.find(&pattern) { - let start = idx + pattern.len(); - if let Some(end) = json[start..].find('"') { - return json[start..start + end].to_string(); - } - } - String::new() -} - -fn json_int(json: &str, key: &str) -> i32 { - let pattern = format!("\"{}\":", key); - if let Some(idx) = json.find(&pattern) { - let start = idx + pattern.len(); - let num_str: String = json[start..] - .chars() - .take_while(|c| c.is_ascii_digit() || *c == '-') - .collect(); - return num_str.parse().unwrap_or(0); - } - 0 -} - -fn extract_request_json(json: &str) -> String { - let pattern = "\"request\":"; - if let Some(idx) = json.find(pattern) { - let start = idx + pattern.len(); - let rest = json[start..].trim_start(); - if rest.starts_with('"') { - // JSON string — find closing quote, handle escapes - let inner = &rest[1..]; - let mut end = 0; - let chars: Vec = inner.chars().collect(); - while end < chars.len() { - if chars[end] == '\\' { end += 2; continue; } - if chars[end] == '"' { break; } - end += 1; - } - let s: String = inner.chars().take(end).collect(); - return s.replace("\\\"", "\"").replace("\\\\", "\\"); - } else if rest.starts_with('{') { - // JSON object — find matching brace - let mut depth = 0; - let mut end = 0; - for (i, c) in rest.char_indices() { - if c == '{' { depth += 1; } - else if c == '}' { depth -= 1; if depth == 0 { end = i + 1; break; } } - } - return rest[..end].to_string(); - } - } - String::new() -} - -fn handle_error(error: &str) { - let auth = ["ERROR_WRONG_USER_KEY", "ERROR_KEY_DOES_NOT_EXIST", "IP_BANNED"]; - let balance = ["ERROR_ZERO_BALANCE"]; - let input = ["ERROR_PAGEURL", "ERROR_WRONG_GOOGLEKEY", "ERROR_BAD_PARAMETERS", "ERROR_BAD_TOKEN_OR_PAGEURL"]; - let proxy = ["ERROR_BAD_PROXY", "ERROR_PROXY_CONNECTION_FAILED"]; - - if auth.contains(&error) { - println!("[!] Authentication error: {}", error); - println!(" Check your API key at https://captchaai.com/dashboard"); - } else if balance.contains(&error) { - println!("[!] Balance error: {}", error); - println!(" Top up your account at https://captchaai.com"); - } else if input.contains(&error) { - println!("[!] Input error: {}", error); - println!(" Verify your gt (captcha_id) and page URL are correct."); - } else if proxy.contains(&error) { - println!("[!] Proxy error: {}", error); - println!(" Check your proxy configuration or try a different proxy."); - } else { - println!("[!] Submission failed: {}", error); - } -} - -fn main() { - let env = load_env("../.env"); - let api_key = get_env(&env, "CAPTCHAAI_API_KEY", ""); - let gt = get_env(&env, "CAPTCHA_GT", ""); - let pageurl = get_env(&env, "CAPTCHA_PAGEURL", ""); - let poll_interval: u64 = get_env(&env, "POLL_INTERVAL", "5").parse().unwrap_or(5); - let max_timeout: u64 = get_env(&env, "MAX_TIMEOUT", "120").parse().unwrap_or(120); - - // Validate - if api_key.is_empty() || api_key == "YOUR_API_KEY" { - println!("[!] ERROR: CAPTCHAAI_API_KEY is not set."); - println!(" Copy .env.example to .env and add your real API key."); - std::process::exit(1); - } - if gt.is_empty() || gt == "YOUR_CAPTCHA_ID" { - println!("[!] ERROR: CAPTCHA_GT is not set."); - println!(" Find the captcha_id in the page source or GeeTest v4 initialization call."); - std::process::exit(1); - } - if pageurl.is_empty() || pageurl == "https://example.com" { - println!("[!] WARNING: CAPTCHA_PAGEURL may not be set correctly."); - println!(" Make sure it points to the actual target page."); - } - - // Submit task - println!("[*] Submitting GeeTest v4 task..."); - let submit_url = format!( - "{}?key={}&method=geetest>={}&pageurl={}&version=4&json=1", - SUBMIT_URL, - urlencoding::encode(&api_key), - urlencoding::encode(>), - urlencoding::encode(&pageurl) - ); - - let submit_resp = match ureq::get(&submit_url).call() { - Ok(r) => r.into_string().unwrap_or_default(), - Err(e) => { - println!("[!] Network error during submission: {}", e); - std::process::exit(1); - } - }; - - let submit_status = json_int(&submit_resp, "status"); - let submit_request = json_str(&submit_resp, "request"); - - if submit_status != 1 { - handle_error(&submit_request); - std::process::exit(1); - } - - let task_id = submit_request; - println!("[+] Task submitted. ID: {}", task_id); - - // Poll for result - println!("[*] Waiting 15s before first poll..."); - thread::sleep(Duration::from_secs(15)); - - let mut elapsed: u64 = 15; - let mut attempt = 0; - let mut backoff = poll_interval; - - let transient = ["ERROR_SERVER_ERROR", "ERROR_INTERNAL_SERVER_ERROR"]; - let solve = ["ERROR_CAPTCHA_UNSOLVABLE"]; - - while elapsed < max_timeout { - attempt += 1; - println!("[*] Polling for result (attempt {})...", attempt); - - let poll_url = format!( - "{}?key={}&action=get&id={}&json=1", - RESULT_URL, - urlencoding::encode(&api_key), - urlencoding::encode(&task_id) - ); - - let result_resp = match ureq::get(&poll_url).call() { - Ok(r) => r.into_string().unwrap_or_default(), - Err(e) => { - println!("[!] Network error during polling: {}", e); - thread::sleep(Duration::from_secs(backoff)); - elapsed += backoff; - backoff = std::cmp::min(backoff * 2, 30); - continue; - } - }; - - let status = json_int(&result_resp, "status"); - - if status == 1 { - // The request field contains a JSON string or object with the 5 GeeTest v4 values - let solution_json = extract_request_json(&result_resp); - let captcha_id = json_str(&solution_json, "captcha_id"); - let lot_number = json_str(&solution_json, "lot_number"); - let pass_token = json_str(&solution_json, "pass_token"); - let gen_time = json_str(&solution_json, "gen_time"); - let captcha_output = json_str(&solution_json, "captcha_output"); - println!("[+] Solved!"); - println!("[+] captcha_id: {}", captcha_id); - println!("[+] lot_number: {}", lot_number); - println!("[+] pass_token: {}", pass_token); - println!("[+] gen_time: {}", gen_time); - println!("[+] captcha_output: {}", captcha_output); - println!(); - println!("Next step: submit these five values to the site's"); - println!("GeeTest v4 verification endpoint."); - return; - } - - let request = json_str(&result_resp, "request"); - - if request == "CAPCHA_NOT_READY" { - println!("[*] Not ready yet, waiting {}s...", poll_interval); - thread::sleep(Duration::from_secs(poll_interval)); - elapsed += poll_interval; - backoff = poll_interval; - continue; - } - - if transient.contains(&request.as_str()) { - println!("[!] Transient error: {}, retrying in {}s...", request, backoff); - thread::sleep(Duration::from_secs(backoff)); - elapsed += backoff; - backoff = std::cmp::min(backoff * 2, 30); - continue; - } - - if solve.contains(&request.as_str()) { - println!("[!] Solve error: {}", request); - println!(" The CAPTCHA could not be solved. Verify parameters and retry."); - std::process::exit(1); - } - - println!("[!] Unexpected error: {}", request); - std::process::exit(1); - } - - println!("[!] Timeout: no solution received within {} seconds.", max_timeout); - std::process::exit(1); -} diff --git a/articles/how-to-solve-hcaptcha-using-api/.env.example b/articles/how-to-solve-hcaptcha-using-api/.env.example deleted file mode 100644 index e6ff2ad..0000000 --- a/articles/how-to-solve-hcaptcha-using-api/.env.example +++ /dev/null @@ -1,13 +0,0 @@ -# CaptchaAI API credentials -# Get your API key from https://captchaai.com/dashboard -CAPTCHAAI_API_KEY=YOUR_API_KEY - -# Target page configuration -# hCaptcha sitekey from the target page -CAPTCHA_SITEKEY=YOUR_SITE_KEY -# Full URL of the page -CAPTCHA_PAGEURL=https://example.com/login - -# Polling configuration (optional) -POLL_INTERVAL=5 -MAX_TIMEOUT=120 diff --git a/articles/how-to-solve-hcaptcha-using-api/.gitignore b/articles/how-to-solve-hcaptcha-using-api/.gitignore deleted file mode 100644 index e9504be..0000000 --- a/articles/how-to-solve-hcaptcha-using-api/.gitignore +++ /dev/null @@ -1,20 +0,0 @@ -.env -__pycache__/ -*.pyc -node_modules/ -vendor/ -composer.lock -package-lock.json -.DS_Store -Thumbs.db -# Go -go.sum -# Java -*.class -# C# -bin/ -obj/ -# Ruby -Gemfile.lock -# Rust -target/ diff --git a/articles/how-to-solve-hcaptcha-using-api/README.md b/articles/how-to-solve-hcaptcha-using-api/README.md deleted file mode 100644 index 6d2b694..0000000 --- a/articles/how-to-solve-hcaptcha-using-api/README.md +++ /dev/null @@ -1,120 +0,0 @@ -# hCaptcha — CaptchaAI Example Pack - -Full working example for solving hCaptcha using the CaptchaAI API. - -**Languages:** Python, Node.js, PHP, Go, Java, C#, Ruby, Rust, Kotlin, Bash - -## Related article - -This example accompanies the blog article: -**[How to Solve hCaptcha Using API](https://blog.captchaai.com/how-to-solve-hcaptcha-using-api)** - -## Prerequisites - -- A CaptchaAI account with API key ([get one here](https://captchaai.com)) -- A target page with hCaptcha for testing -- One or more of: Python 3.8+, Node.js 16+, PHP 8.0+, Go 1.21+, Java 11+, .NET 8+, Ruby 3.0+, Rust 1.70+, Kotlin 1.9+, or Bash with curl and jq - -## Setup - -1. Clone the repository: - ```bash - git clone https://github.com/CaptchaAI/CaptchaAI-Examples.git - cd CaptchaAI-Examples/articles/how-to-solve-hcaptcha-using-api - ``` - -2. Copy the environment file and add your credentials: - ```bash - cp .env.example .env - ``` - -3. Edit `.env` with your API key and target page details. - -4. Follow the language-specific setup below. - -### Python - -```bash -cd python -pip install -r requirements.txt -python solve.py -``` - -### Node.js - -```bash -cd node -npm install -node solve.js -``` - -### PHP - -```bash -cd php -composer install -php solve.php -``` - -### Go - -```bash -cd go -go run solve.go -``` - -### Java - -```bash -cd java -javac Solve.java -java Solve -``` - -### C# - -```bash -cd csharp -dotnet run -``` - -### Ruby - -```bash -cd ruby -bundle install # optional — uses stdlib only -ruby solve.rb -``` - -### Rust - -```bash -cd rust -cargo run -``` - -### Kotlin - -```bash -cd kotlin -kotlinc solve.kt -include-runtime -d solve.jar -java -jar solve.jar -``` - -### Bash - -```bash -cd bash -chmod +x solve.sh -bash solve.sh -``` - -## Environment variables - -| Variable | Description | -|---|---| -| `CAPTCHAAI_API_KEY` | Your CaptchaAI API key | -| `CAPTCHA_SITEKEY` | hCaptcha sitekey from the target page | -| `CAPTCHA_PAGEURL` | Full URL of the target page | -| `POLL_INTERVAL` | Seconds between polls (default: 5) | -| `MAX_TIMEOUT` | Maximum wait in seconds (default: 120) | diff --git a/articles/how-to-solve-hcaptcha-using-api/bash/solve.sh b/articles/how-to-solve-hcaptcha-using-api/bash/solve.sh deleted file mode 100644 index 2534283..0000000 --- a/articles/how-to-solve-hcaptcha-using-api/bash/solve.sh +++ /dev/null @@ -1,171 +0,0 @@ -#!/usr/bin/env bash -# Solve hCaptcha using the CaptchaAI API. -# -# Usage: -# chmod +x solve.sh -# bash solve.sh - -set -euo pipefail - -SUBMIT_URL="https://ocr.captchaai.com/in.php" -RESULT_URL="https://ocr.captchaai.com/res.php" - -# Load .env -ENV_FILE="$(dirname "$0")/../.env" -if [[ -f "$ENV_FILE" ]]; then - set -a - # shellcheck disable=SC1090 - source "$ENV_FILE" - set +a -fi - -API_KEY="${CAPTCHAAI_API_KEY:-}" -SITEKEY="${CAPTCHA_SITEKEY:-}" -PAGEURL="${CAPTCHA_PAGEURL:-}" -POLL_INTERVAL="${POLL_INTERVAL:-5}" -MAX_TIMEOUT="${MAX_TIMEOUT:-120}" - -# Validate -if [[ -z "$API_KEY" || "$API_KEY" == "YOUR_API_KEY" ]]; then - echo "[!] ERROR: CAPTCHAAI_API_KEY is not set." - echo " Copy .env.example to .env and add your real API key." - exit 1 -fi -if [[ -z "$SITEKEY" || "$SITEKEY" == "YOUR_SITE_KEY" ]]; then - echo "[!] ERROR: CAPTCHA_SITEKEY is not set." - echo " Add the hCaptcha sitekey from your target page to .env" - exit 1 -fi -if [[ -z "$PAGEURL" || "$PAGEURL" == "https://example.com/login" ]]; then - echo "[!] WARNING: CAPTCHA_PAGEURL may not be set correctly." - echo " Make sure it points to the actual target page." -fi - -# JSON helpers -json_str() { - local json="$1" key="$2" - echo "$json" | grep -oP "\"${key}\":\s*\"\\K[^\"]*" || echo "" -} -json_int() { - local json="$1" key="$2" - echo "$json" | grep -oP "\"${key}\":\s*\\K[0-9]+" || echo "0" -} - -# Error handler -handle_error() { - local error="$1" - case "$error" in - ERROR_WRONG_USER_KEY|ERROR_KEY_DOES_NOT_EXIST|IP_BANNED) - echo "[!] Authentication error: $error" - echo " Check your API key at https://captchaai.com/dashboard" - ;; - ERROR_ZERO_BALANCE) - echo "[!] Balance error: $error" - echo " Top up your account at https://captchaai.com" - ;; - ERROR_PAGEURL|ERROR_WRONG_GOOGLEKEY|ERROR_BAD_PARAMETERS|ERROR_BAD_TOKEN_OR_PAGEURL) - echo "[!] Input error: $error" - echo " Verify your sitekey and page URL are correct." - ;; - ERROR_BAD_PROXY|ERROR_PROXY_CONNECTION_FAILED) - echo "[!] Proxy error: $error" - echo " Check your proxy configuration or try a different proxy." - ;; - *) - echo "[!] Submission failed: $error" - ;; - esac -} - -# Submit task -echo "[*] Submitting hCaptcha task..." -ENCODED_KEY=$(python3 -c "import urllib.parse; print(urllib.parse.quote('$API_KEY'))" 2>/dev/null || echo "$API_KEY") -ENCODED_SITEKEY=$(python3 -c "import urllib.parse; print(urllib.parse.quote('$SITEKEY'))" 2>/dev/null || echo "$SITEKEY") -ENCODED_PAGEURL=$(python3 -c "import urllib.parse; print(urllib.parse.quote('$PAGEURL'))" 2>/dev/null || echo "$PAGEURL") - -SUBMIT_RESP=$(curl -sS --max-time 30 \ - "${SUBMIT_URL}?key=${ENCODED_KEY}&method=hcaptcha&sitekey=${ENCODED_SITEKEY}&pageurl=${ENCODED_PAGEURL}&json=1") - -if [[ -z "$SUBMIT_RESP" ]]; then - echo "[!] Network error during submission." - exit 1 -fi - -SUBMIT_STATUS=$(json_int "$SUBMIT_RESP" "status") -SUBMIT_REQUEST=$(json_str "$SUBMIT_RESP" "request") - -if [[ "$SUBMIT_STATUS" -ne 1 ]]; then - handle_error "$SUBMIT_REQUEST" - exit 1 -fi - -TASK_ID="$SUBMIT_REQUEST" -echo "[+] Task submitted. ID: $TASK_ID" - -# Poll for result -echo "[*] Waiting 15s before first poll..." -sleep 15 - -ELAPSED=15 -ATTEMPT=0 -BACKOFF="$POLL_INTERVAL" - -while [[ "$ELAPSED" -lt "$MAX_TIMEOUT" ]]; do - ATTEMPT=$((ATTEMPT + 1)) - echo "[*] Polling for result (attempt $ATTEMPT)..." - - POLL_RESP=$(curl -sS --max-time 30 \ - "${RESULT_URL}?key=${ENCODED_KEY}&action=get&id=${TASK_ID}&json=1" 2>/dev/null || echo "") - - if [[ -z "$POLL_RESP" ]]; then - echo "[!] Network error during polling." - sleep "$BACKOFF" - ELAPSED=$((ELAPSED + BACKOFF)) - BACKOFF=$((BACKOFF * 2)) - [[ "$BACKOFF" -gt 30 ]] && BACKOFF=30 - continue - fi - - STATUS=$(json_int "$POLL_RESP" "status") - REQUEST=$(json_str "$POLL_RESP" "request") - - if [[ "$STATUS" -eq 1 ]]; then - DISPLAY="${REQUEST:0:50}" - echo "[+] Solved! Token: ${DISPLAY}..." - echo "[+] Full token length: ${#REQUEST} characters" - echo - echo "Next step: inject this token into the target page's" - echo "h-captcha-response hidden field and submit the form." - exit 0 - fi - - if [[ "$REQUEST" == "CAPCHA_NOT_READY" ]]; then - echo "[*] Not ready yet, waiting ${POLL_INTERVAL}s..." - sleep "$POLL_INTERVAL" - ELAPSED=$((ELAPSED + POLL_INTERVAL)) - BACKOFF="$POLL_INTERVAL" - continue - fi - - case "$REQUEST" in - ERROR_SERVER_ERROR|ERROR_INTERNAL_SERVER_ERROR) - echo "[!] Transient error: $REQUEST, retrying in ${BACKOFF}s..." - sleep "$BACKOFF" - ELAPSED=$((ELAPSED + BACKOFF)) - BACKOFF=$((BACKOFF * 2)) - [[ "$BACKOFF" -gt 30 ]] && BACKOFF=30 - continue - ;; - ERROR_CAPTCHA_UNSOLVABLE) - echo "[!] Solve error: $REQUEST" - echo " The CAPTCHA could not be solved. Verify parameters and retry." - exit 1 - ;; - esac - - echo "[!] Unexpected error: $REQUEST" - exit 1 -done - -echo "[!] Timeout: no solution received within $MAX_TIMEOUT seconds." -exit 1 diff --git a/articles/how-to-solve-hcaptcha-using-api/csharp/Solve.cs b/articles/how-to-solve-hcaptcha-using-api/csharp/Solve.cs deleted file mode 100644 index c71da03..0000000 --- a/articles/how-to-solve-hcaptcha-using-api/csharp/Solve.cs +++ /dev/null @@ -1,205 +0,0 @@ -// Solve hCaptcha using the CaptchaAI API. -// -// Usage: -// dotnet run - -using System; -using System.Collections.Generic; -using System.IO; -using System.Net.Http; -using System.Text.Json; -using System.Threading.Tasks; - -const string SubmitUrl = "https://ocr.captchaai.com/in.php"; -const string ResultUrl = "https://ocr.captchaai.com/res.php"; - -var authErrors = new HashSet { "ERROR_WRONG_USER_KEY", "ERROR_KEY_DOES_NOT_EXIST", "IP_BANNED" }; -var balanceErrors = new HashSet { "ERROR_ZERO_BALANCE" }; -var inputErrors = new HashSet { "ERROR_PAGEURL", "ERROR_WRONG_GOOGLEKEY", "ERROR_BAD_PARAMETERS", "ERROR_BAD_TOKEN_OR_PAGEURL" }; -var transientErrors = new HashSet { "ERROR_SERVER_ERROR", "ERROR_INTERNAL_SERVER_ERROR" }; -var solveErrors = new HashSet { "ERROR_CAPTCHA_UNSOLVABLE" }; -var proxyErrors = new HashSet { "ERROR_BAD_PROXY", "ERROR_PROXY_CONNECTION_FAILED" }; - -var env = LoadEnv(Path.Combine("..", ".env")); -string apiKey = GetEnv(env, "CAPTCHAAI_API_KEY", ""); -string sitekey = GetEnv(env, "CAPTCHA_SITEKEY", ""); -string pageurl = GetEnv(env, "CAPTCHA_PAGEURL", ""); -int pollInterval = int.Parse(GetEnv(env, "POLL_INTERVAL", "5")); -int maxTimeout = int.Parse(GetEnv(env, "MAX_TIMEOUT", "120")); - -// Validate -if (string.IsNullOrEmpty(apiKey) || apiKey == "YOUR_API_KEY") -{ - Console.WriteLine("[!] ERROR: CAPTCHAAI_API_KEY is not set."); - Console.WriteLine(" Copy .env.example to .env and add your real API key."); - Environment.Exit(1); -} -if (string.IsNullOrEmpty(sitekey) || sitekey == "YOUR_SITE_KEY") -{ - Console.WriteLine("[!] ERROR: CAPTCHA_SITEKEY is not set."); - Console.WriteLine(" Add the hCaptcha sitekey from your target page to .env"); - Environment.Exit(1); -} -if (string.IsNullOrEmpty(pageurl) || pageurl == "https://example.com/login") -{ - Console.WriteLine("[!] WARNING: CAPTCHA_PAGEURL may not be set correctly."); - Console.WriteLine(" Make sure it points to the actual target page."); -} - -using var client = new HttpClient { Timeout = TimeSpan.FromSeconds(30) }; - -// Submit task -Console.WriteLine("[*] Submitting hCaptcha task..."); -var submitQuery = $"key={Uri.EscapeDataString(apiKey)}&method=hcaptcha&sitekey={Uri.EscapeDataString(sitekey)}&pageurl={Uri.EscapeDataString(pageurl)}&json=1"; - -string submitBody; -try -{ - submitBody = await client.GetStringAsync($"{SubmitUrl}?{submitQuery}"); -} -catch (Exception ex) -{ - Console.WriteLine($"[!] Network error during submission: {ex.Message}"); - Environment.Exit(1); - return; -} - -using var submitDoc = JsonDocument.Parse(submitBody); -int submitStatus = submitDoc.RootElement.GetProperty("status").GetInt32(); -string submitRequest = submitDoc.RootElement.GetProperty("request").GetString() ?? ""; - -if (submitStatus != 1) -{ - HandleError(submitRequest, authErrors, balanceErrors, inputErrors, proxyErrors); - Environment.Exit(1); -} - -string taskId = submitRequest; -Console.WriteLine($"[+] Task submitted. ID: {taskId}"); - -// Poll for result -Console.WriteLine("[*] Waiting 15s before first poll..."); -await Task.Delay(15000); - -int elapsed = 15; -int attempt = 0; -int backoff = pollInterval; - -while (elapsed < maxTimeout) -{ - attempt++; - Console.WriteLine($"[*] Polling for result (attempt {attempt})..."); - - var pollQuery = $"key={Uri.EscapeDataString(apiKey)}&action=get&id={Uri.EscapeDataString(taskId)}&json=1"; - - string resultBody; - try - { - resultBody = await client.GetStringAsync($"{ResultUrl}?{pollQuery}"); - } - catch (Exception ex) - { - Console.WriteLine($"[!] Network error during polling: {ex.Message}"); - await Task.Delay(backoff * 1000); - elapsed += backoff; - backoff = Math.Min(backoff * 2, 30); - continue; - } - - using var resultDoc = JsonDocument.Parse(resultBody); - int status = resultDoc.RootElement.GetProperty("status").GetInt32(); - string request = resultDoc.RootElement.GetProperty("request").GetString() ?? ""; - - if (status == 1) - { - string display = request.Length > 50 ? request[..50] : request; - Console.WriteLine($"[+] Solved! Token: {display}..."); - Console.WriteLine($"[+] Full token length: {request.Length} characters"); - Console.WriteLine(); - Console.WriteLine("Next step: inject this token into the target page's"); - Console.WriteLine("h-captcha-response hidden field and submit the form."); - return; - } - - if (request == "CAPCHA_NOT_READY") - { - Console.WriteLine($"[*] Not ready yet, waiting {pollInterval}s..."); - await Task.Delay(pollInterval * 1000); - elapsed += pollInterval; - backoff = pollInterval; - continue; - } - - if (transientErrors.Contains(request)) - { - Console.WriteLine($"[!] Transient error: {request}, retrying in {backoff}s..."); - await Task.Delay(backoff * 1000); - elapsed += backoff; - backoff = Math.Min(backoff * 2, 30); - continue; - } - - if (solveErrors.Contains(request)) - { - Console.WriteLine($"[!] Solve error: {request}"); - Console.WriteLine(" The CAPTCHA could not be solved. Verify parameters and retry."); - Environment.Exit(1); - } - - Console.WriteLine($"[!] Unexpected error: {request}"); - Environment.Exit(1); -} - -Console.WriteLine($"[!] Timeout: no solution received within {maxTimeout} seconds."); -Environment.Exit(1); - -static Dictionary LoadEnv(string path) -{ - var dict = new Dictionary(); - if (!File.Exists(path)) return dict; - foreach (var line in File.ReadAllLines(path)) - { - var trimmed = line.Trim(); - if (string.IsNullOrEmpty(trimmed) || trimmed.StartsWith('#')) continue; - var eq = trimmed.IndexOf('='); - if (eq > 0) - dict[trimmed[..eq].Trim()] = trimmed[(eq + 1)..].Trim(); - } - return dict; -} - -static string GetEnv(Dictionary env, string key, string fallback) -{ - if (env.TryGetValue(key, out var v) && !string.IsNullOrEmpty(v)) return v; - v = Environment.GetEnvironmentVariable(key); - if (!string.IsNullOrEmpty(v)) return v; - return fallback; -} - -static void HandleError(string error, HashSet auth, HashSet balance, HashSet input, HashSet proxy) -{ - if (auth.Contains(error)) - { - Console.WriteLine($"[!] Authentication error: {error}"); - Console.WriteLine(" Check your API key at https://captchaai.com/dashboard"); - } - else if (balance.Contains(error)) - { - Console.WriteLine($"[!] Balance error: {error}"); - Console.WriteLine(" Top up your account at https://captchaai.com"); - } - else if (input.Contains(error)) - { - Console.WriteLine($"[!] Input error: {error}"); - Console.WriteLine(" Verify your sitekey and page URL are correct."); - } - else if (proxy.Contains(error)) - { - Console.WriteLine($"[!] Proxy error: {error}"); - Console.WriteLine(" Check your proxy configuration or try a different proxy."); - } - else - { - Console.WriteLine($"[!] Submission failed: {error}"); - } -} diff --git a/articles/how-to-solve-hcaptcha-using-api/csharp/Solve.csproj b/articles/how-to-solve-hcaptcha-using-api/csharp/Solve.csproj deleted file mode 100644 index dd4b568..0000000 --- a/articles/how-to-solve-hcaptcha-using-api/csharp/Solve.csproj +++ /dev/null @@ -1,6 +0,0 @@ - - - Exe - net8.0 - - diff --git a/articles/how-to-solve-hcaptcha-using-api/go/go.mod b/articles/how-to-solve-hcaptcha-using-api/go/go.mod deleted file mode 100644 index 9d0e8ad..0000000 --- a/articles/how-to-solve-hcaptcha-using-api/go/go.mod +++ /dev/null @@ -1,3 +0,0 @@ -module captchaai-hcaptcha-example - -go 1.21 diff --git a/articles/how-to-solve-hcaptcha-using-api/go/solve.go b/articles/how-to-solve-hcaptcha-using-api/go/solve.go deleted file mode 100644 index 40b000a..0000000 --- a/articles/how-to-solve-hcaptcha-using-api/go/solve.go +++ /dev/null @@ -1,238 +0,0 @@ -// Solve hCaptcha using the CaptchaAI API. -// -// Usage: -// go run solve.go - -package main - -import ( - "bufio" - "encoding/json" - "fmt" - "io" - "net/http" - "net/url" - "os" - "path/filepath" - "strconv" - "strings" - "time" -) - -const submitURL = "https://ocr.captchaai.com/in.php" -const resultURL = "https://ocr.captchaai.com/res.php" - -var authErrors = map[string]bool{"ERROR_WRONG_USER_KEY": true, "ERROR_KEY_DOES_NOT_EXIST": true, "IP_BANNED": true} -var balanceErrors = map[string]bool{"ERROR_ZERO_BALANCE": true} -var inputErrors = map[string]bool{"ERROR_PAGEURL": true, "ERROR_WRONG_GOOGLEKEY": true, "ERROR_BAD_PARAMETERS": true, "ERROR_BAD_TOKEN_OR_PAGEURL": true} -var transientErrors = map[string]bool{"ERROR_SERVER_ERROR": true, "ERROR_INTERNAL_SERVER_ERROR": true} -var solveErrors = map[string]bool{"ERROR_CAPTCHA_UNSOLVABLE": true} -var proxyErrors = map[string]bool{"ERROR_BAD_PROXY": true, "ERROR_PROXY_CONNECTION_FAILED": true} - -type apiResponse struct { - Status int `json:"status"` - Request any `json:"request"` -} - -func requestValue(value any) string { - switch v := value.(type) { - case nil: - return "" - case string: - return v - case float64: - return strconv.FormatInt(int64(v), 10) - case json.Number: - return v.String() - default: - return fmt.Sprintf("%v", v) - } -} - -func loadEnv() map[string]string { - path := filepath.Join("..", ".env") - env := make(map[string]string) - f, err := os.Open(path) - if err != nil { - return env - } - defer f.Close() - - scanner := bufio.NewScanner(f) - for scanner.Scan() { - line := strings.TrimSpace(scanner.Text()) - if line == "" || strings.HasPrefix(line, "#") { - continue - } - parts := strings.SplitN(line, "=", 2) - if len(parts) == 2 { - env[strings.TrimSpace(parts[0])] = strings.TrimSpace(parts[1]) - } - } - - return env -} - -func getEnv(env map[string]string, key, fallback string) string { - if value, ok := env[key]; ok && value != "" { - return value - } - if value := os.Getenv(key); value != "" { - return value - } - return fallback -} - -func main() { - env := loadEnv() - apiKey := getEnv(env, "CAPTCHAAI_API_KEY", "") - sitekey := getEnv(env, "CAPTCHA_SITEKEY", "") - pageurl := getEnv(env, "CAPTCHA_PAGEURL", "") - pollInterval, _ := strconv.Atoi(getEnv(env, "POLL_INTERVAL", "5")) - maxTimeout, _ := strconv.Atoi(getEnv(env, "MAX_TIMEOUT", "120")) - - if apiKey == "" || apiKey == "YOUR_API_KEY" { - fmt.Println("[!] ERROR: CAPTCHAAI_API_KEY is not set.") - fmt.Println(" Copy .env.example to .env and add your real API key.") - os.Exit(1) - } - if sitekey == "" || sitekey == "YOUR_SITE_KEY" { - fmt.Println("[!] ERROR: CAPTCHA_SITEKEY is not set.") - fmt.Println(" Add the hCaptcha sitekey from your target page to .env") - os.Exit(1) - } - if pageurl == "" || pageurl == "https://example.com/login" { - fmt.Println("[!] WARNING: CAPTCHA_PAGEURL may not be set correctly.") - fmt.Println(" Make sure it points to the actual target page.") - } - - client := &http.Client{Timeout: 30 * time.Second} - - // Submit task - fmt.Println("[*] Submitting hCaptcha task...") - params := url.Values{ - "key": {apiKey}, - "method": {"hcaptcha"}, - "sitekey": {sitekey}, - "pageurl": {pageurl}, - "json": {"1"}, - } - - resp, err := client.Get(submitURL + "?" + params.Encode()) - if err != nil { - fmt.Printf("[!] Network error during submission: %v\n", err) - os.Exit(1) - } - defer resp.Body.Close() - - body, _ := io.ReadAll(resp.Body) - var submitResp apiResponse - json.Unmarshal(body, &submitResp) - - if submitResp.Status != 1 { - handleError(requestValue(submitResp.Request)) - os.Exit(1) - } - - taskID := requestValue(submitResp.Request) - fmt.Printf("[+] Task submitted. ID: %s\n", taskID) - - // Poll for result - fmt.Println("[*] Waiting 15s before first poll...") - time.Sleep(15 * time.Second) - - elapsed := 15 - attempt := 0 - backoff := pollInterval - - for elapsed < maxTimeout { - attempt++ - fmt.Printf("[*] Polling for result (attempt %d)...\n", attempt) - - pollParams := url.Values{ - "key": {apiKey}, - "action": {"get"}, - "id": {taskID}, - "json": {"1"}, - } - - resp, err := client.Get(resultURL + "?" + pollParams.Encode()) - if err != nil { - fmt.Printf("[!] Network error during polling: %v\n", err) - time.Sleep(time.Duration(backoff) * time.Second) - elapsed += backoff - if backoff < 30 { - backoff *= 2 - } - continue - } - - body, _ := io.ReadAll(resp.Body) - resp.Body.Close() - var result apiResponse - json.Unmarshal(body, &result) - reqStr := requestValue(result.Request) - - if result.Status == 1 { - token := reqStr - display := token - if len(display) > 50 { - display = display[:50] - } - fmt.Printf("[+] Solved! Token: %s...\n", display) - fmt.Printf("[+] Full token length: %d characters\n", len(token)) - fmt.Println() - fmt.Println("Next step: inject this token into the target page's") - fmt.Println("h-captcha-response hidden field and submit the form.") - return - } - - if reqStr == "CAPCHA_NOT_READY" { - fmt.Printf("[*] Not ready yet, waiting %ds...\n", pollInterval) - time.Sleep(time.Duration(pollInterval) * time.Second) - elapsed += pollInterval - backoff = pollInterval - continue - } - - if transientErrors[reqStr] { - fmt.Printf("[!] Transient error: %s, retrying in %ds...\n", reqStr, backoff) - time.Sleep(time.Duration(backoff) * time.Second) - elapsed += backoff - if backoff < 30 { - backoff *= 2 - } - continue - } - - if solveErrors[reqStr] { - fmt.Printf("[!] Solve error: %s\n", reqStr) - fmt.Println(" The CAPTCHA could not be solved. Verify parameters and retry.") - os.Exit(1) - } - - fmt.Printf("[!] Unexpected error: %s\n", reqStr) - os.Exit(1) - } - - fmt.Printf("[!] Timeout: no solution received within %d seconds.\n", maxTimeout) - os.Exit(1) -} - -func handleError(errCode string) { - if authErrors[errCode] { - fmt.Printf("[!] Authentication error: %s\n", errCode) - fmt.Println(" Check your API key at https://captchaai.com/dashboard") - } else if balanceErrors[errCode] { - fmt.Printf("[!] Balance error: %s\n", errCode) - fmt.Println(" Top up your account at https://captchaai.com") - } else if inputErrors[errCode] { - fmt.Printf("[!] Input error: %s\n", errCode) - fmt.Println(" Verify your sitekey and page URL are correct.") - } else if proxyErrors[errCode] { - fmt.Printf("[!] Proxy error: %s\n", errCode) - fmt.Println(" Check your proxy configuration or try a different proxy.") - } else { - fmt.Printf("[!] Submission failed: %s\n", errCode) - } -} diff --git a/articles/how-to-solve-hcaptcha-using-api/java/Solve.java b/articles/how-to-solve-hcaptcha-using-api/java/Solve.java deleted file mode 100644 index 3f3eba9..0000000 --- a/articles/how-to-solve-hcaptcha-using-api/java/Solve.java +++ /dev/null @@ -1,221 +0,0 @@ -import java.io.*; -import java.net.*; -import java.nio.file.*; -import java.util.*; - -/** - * Solve hCaptcha using the CaptchaAI API. - * - * Usage: - * javac Solve.java - * java Solve - */ -public class Solve { - static final String SUBMIT_URL = "https://ocr.captchaai.com/in.php"; - static final String RESULT_URL = "https://ocr.captchaai.com/res.php"; - - static final Set AUTH_ERRORS = Set.of("ERROR_WRONG_USER_KEY", "ERROR_KEY_DOES_NOT_EXIST", "IP_BANNED"); - static final Set BALANCE_ERRORS = Set.of("ERROR_ZERO_BALANCE"); - static final Set INPUT_ERRORS = Set.of("ERROR_PAGEURL", "ERROR_WRONG_GOOGLEKEY", "ERROR_BAD_PARAMETERS", "ERROR_BAD_TOKEN_OR_PAGEURL"); - static final Set TRANSIENT_ERRORS = Set.of("ERROR_SERVER_ERROR", "ERROR_INTERNAL_SERVER_ERROR"); - static final Set SOLVE_ERRORS = Set.of("ERROR_CAPTCHA_UNSOLVABLE"); - static final Set PROXY_ERRORS = Set.of("ERROR_BAD_PROXY", "ERROR_PROXY_CONNECTION_FAILED"); - - static Map env = new HashMap<>(); - - public static void main(String[] args) throws Exception { - loadEnv(); - String apiKey = getEnv("CAPTCHAAI_API_KEY", ""); - String sitekey = getEnv("CAPTCHA_SITEKEY", ""); - String pageurl = getEnv("CAPTCHA_PAGEURL", ""); - int pollInterval = Integer.parseInt(getEnv("POLL_INTERVAL", "5")); - int maxTimeout = Integer.parseInt(getEnv("MAX_TIMEOUT", "120")); - - // Validate - if (apiKey.isEmpty() || apiKey.equals("YOUR_API_KEY")) { - System.out.println("[!] ERROR: CAPTCHAAI_API_KEY is not set."); - System.out.println(" Copy .env.example to .env and add your real API key."); - System.exit(1); - } - if (sitekey.isEmpty() || sitekey.equals("YOUR_SITE_KEY")) { - System.out.println("[!] ERROR: CAPTCHA_SITEKEY is not set."); - System.out.println(" Add the hCaptcha sitekey from your target page to .env"); - System.exit(1); - } - if (pageurl.isEmpty() || pageurl.equals("https://example.com/login")) { - System.out.println("[!] WARNING: CAPTCHA_PAGEURL may not be set correctly."); - System.out.println(" Make sure it points to the actual target page."); - } - - // Submit task - System.out.println("[*] Submitting hCaptcha task..."); - String submitParams = String.format( - "key=%s&method=hcaptcha&sitekey=%s&pageurl=%s&json=1", - enc(apiKey), enc(sitekey), enc(pageurl) - ); - - String submitResp = httpGet(SUBMIT_URL + "?" + submitParams); - int submitStatus = jsonInt(submitResp, "status"); - String submitRequest = jsonStr(submitResp, "request"); - - if (submitStatus != 1) { - handleError(submitRequest); - System.exit(1); - } - - String taskId = submitRequest; - System.out.println("[+] Task submitted. ID: " + taskId); - - // Poll for result - System.out.println("[*] Waiting 15s before first poll..."); - Thread.sleep(15000); - - int elapsed = 15; - int attempt = 0; - int backoff = pollInterval; - - while (elapsed < maxTimeout) { - attempt++; - System.out.println("[*] Polling for result (attempt " + attempt + ")..."); - - String pollParams = String.format( - "key=%s&action=get&id=%s&json=1", - enc(apiKey), enc(taskId) - ); - - String resultResp; - try { - resultResp = httpGet(RESULT_URL + "?" + pollParams); - } catch (Exception e) { - System.out.println("[!] Network error during polling: " + e.getMessage()); - Thread.sleep(backoff * 1000L); - elapsed += backoff; - backoff = Math.min(backoff * 2, 30); - continue; - } - - int status = jsonInt(resultResp, "status"); - String request = jsonStr(resultResp, "request"); - - if (status == 1) { - String display = request.length() > 50 ? request.substring(0, 50) : request; - System.out.println("[+] Solved! Token: " + display + "..."); - System.out.println("[+] Full token length: " + request.length() + " characters"); - System.out.println(); - System.out.println("Next step: inject this token into the target page's"); - System.out.println("h-captcha-response hidden field and submit the form."); - return; - } - - if ("CAPCHA_NOT_READY".equals(request)) { - System.out.println("[*] Not ready yet, waiting " + pollInterval + "s..."); - Thread.sleep(pollInterval * 1000L); - elapsed += pollInterval; - backoff = pollInterval; - continue; - } - - if (TRANSIENT_ERRORS.contains(request)) { - System.out.println("[!] Transient error: " + request + ", retrying in " + backoff + "s..."); - Thread.sleep(backoff * 1000L); - elapsed += backoff; - backoff = Math.min(backoff * 2, 30); - continue; - } - - if (SOLVE_ERRORS.contains(request)) { - System.out.println("[!] Solve error: " + request); - System.out.println(" The CAPTCHA could not be solved. Verify parameters and retry."); - System.exit(1); - } - - System.out.println("[!] Unexpected error: " + request); - System.exit(1); - } - - System.out.println("[!] Timeout: no solution received within " + maxTimeout + " seconds."); - System.exit(1); - } - - static void loadEnv() { - try { - Path envPath = Paths.get("..", ".env"); - if (!Files.exists(envPath)) return; - for (String line : Files.readAllLines(envPath)) { - line = line.trim(); - if (line.isEmpty() || line.startsWith("#")) continue; - int eq = line.indexOf('='); - if (eq > 0) { - env.put(line.substring(0, eq).trim(), line.substring(eq + 1).trim()); - } - } - } catch (IOException ignored) {} - } - - static String getEnv(String key, String fallback) { - String v = env.get(key); - if (v != null && !v.isEmpty()) return v; - v = System.getenv(key); - if (v != null && !v.isEmpty()) return v; - return fallback; - } - - static String httpGet(String urlStr) throws Exception { - URL url = new URL(urlStr); - HttpURLConnection conn = (HttpURLConnection) url.openConnection(); - conn.setConnectTimeout(30000); - conn.setReadTimeout(30000); - BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream())); - StringBuilder sb = new StringBuilder(); - String line; - while ((line = reader.readLine()) != null) sb.append(line); - reader.close(); - return sb.toString(); - } - - static String enc(String s) throws Exception { - return URLEncoder.encode(s, "UTF-8"); - } - - static int jsonInt(String json, String key) { - String pattern = "\"" + key + "\":"; - int idx = json.indexOf(pattern); - if (idx < 0) return 0; - int start = idx + pattern.length(); - StringBuilder sb = new StringBuilder(); - for (int i = start; i < json.length(); i++) { - char c = json.charAt(i); - if (c == ',' || c == '}') break; - if (c != ' ') sb.append(c); - } - try { return Integer.parseInt(sb.toString()); } catch (Exception e) { return 0; } - } - - static String jsonStr(String json, String key) { - String pattern = "\"" + key + "\":\""; - int idx = json.indexOf(pattern); - if (idx < 0) return ""; - int start = idx + pattern.length(); - int end = json.indexOf("\"", start); - if (end < 0) return ""; - return json.substring(start, end); - } - - static void handleError(String error) { - if (AUTH_ERRORS.contains(error)) { - System.out.println("[!] Authentication error: " + error); - System.out.println(" Check your API key at https://captchaai.com/dashboard"); - } else if (BALANCE_ERRORS.contains(error)) { - System.out.println("[!] Balance error: " + error); - System.out.println(" Top up your account at https://captchaai.com"); - } else if (INPUT_ERRORS.contains(error)) { - System.out.println("[!] Input error: " + error); - System.out.println(" Verify your sitekey and page URL are correct."); - } else if (PROXY_ERRORS.contains(error)) { - System.out.println("[!] Proxy error: " + error); - System.out.println(" Check your proxy configuration or try a different proxy."); - } else { - System.out.println("[!] Submission failed: " + error); - } - } -} diff --git a/articles/how-to-solve-hcaptcha-using-api/kotlin/solve.kt b/articles/how-to-solve-hcaptcha-using-api/kotlin/solve.kt deleted file mode 100644 index 9c21623..0000000 --- a/articles/how-to-solve-hcaptcha-using-api/kotlin/solve.kt +++ /dev/null @@ -1,213 +0,0 @@ -// Solve hCaptcha using the CaptchaAI API. -// -// Usage: -// kotlinc solve.kt -include-runtime -d solve.jar -// java -jar solve.jar - -import java.io.BufferedReader -import java.io.InputStreamReader -import java.net.HttpURLConnection -import java.net.URL -import java.net.URLEncoder -import java.io.File - -val SUBMIT_URL = "https://ocr.captchaai.com/in.php" -val RESULT_URL = "https://ocr.captchaai.com/res.php" - -val AUTH_ERRORS = setOf("ERROR_WRONG_USER_KEY", "ERROR_KEY_DOES_NOT_EXIST", "IP_BANNED") -val BALANCE_ERRORS = setOf("ERROR_ZERO_BALANCE") -val INPUT_ERRORS = setOf("ERROR_PAGEURL", "ERROR_WRONG_GOOGLEKEY", "ERROR_BAD_PARAMETERS", "ERROR_BAD_TOKEN_OR_PAGEURL") -val TRANSIENT_ERRORS = setOf("ERROR_SERVER_ERROR", "ERROR_INTERNAL_SERVER_ERROR") -val SOLVE_ERRORS = setOf("ERROR_CAPTCHA_UNSOLVABLE") -val PROXY_ERRORS = setOf("ERROR_BAD_PROXY", "ERROR_PROXY_CONNECTION_FAILED") - -fun loadEnv(path: String): Map { - val env = mutableMapOf() - val file = File(path) - if (!file.exists()) return env - file.readLines().forEach { line -> - val trimmed = line.trim() - if (trimmed.isNotEmpty() && !trimmed.startsWith("#")) { - val eq = trimmed.indexOf('=') - if (eq > 0) { - env[trimmed.substring(0, eq).trim()] = trimmed.substring(eq + 1).trim() - } - } - } - return env -} - -fun getEnv(env: Map, key: String, fallback: String = ""): String { - val v = env[key] - if (!v.isNullOrEmpty()) return v - val sv = System.getenv(key) - if (!sv.isNullOrEmpty()) return sv - return fallback -} - -fun httpGet(urlStr: String): String { - val conn = URL(urlStr).openConnection() as HttpURLConnection - conn.connectTimeout = 30000 - conn.readTimeout = 30000 - val reader = BufferedReader(InputStreamReader(conn.inputStream)) - val result = reader.readText() - reader.close() - return result -} - -fun jsonStr(json: String, key: String): String { - val pattern = "\"$key\":\"" - val idx = json.indexOf(pattern) - if (idx < 0) return "" - val start = idx + pattern.length - val end = json.indexOf("\"", start) - if (end < 0) return "" - return json.substring(start, end) -} - -fun jsonInt(json: String, key: String): Int { - val pattern = "\"$key\":" - val idx = json.indexOf(pattern) - if (idx < 0) return 0 - val start = idx + pattern.length - val numStr = json.substring(start).takeWhile { it.isDigit() || it == '-' } - return numStr.toIntOrNull() ?: 0 -} - -fun handleError(error: String) { - when { - error in AUTH_ERRORS -> { - println("[!] Authentication error: $error") - println(" Check your API key at https://captchaai.com/dashboard") - } - error in BALANCE_ERRORS -> { - println("[!] Balance error: $error") - println(" Top up your account at https://captchaai.com") - } - error in INPUT_ERRORS -> { - println("[!] Input error: $error") - println(" Verify your sitekey and page URL are correct.") - } - error in PROXY_ERRORS -> { - println("[!] Proxy error: $error") - println(" Check your proxy configuration or try a different proxy.") - } - else -> println("[!] Submission failed: $error") - } -} - -fun enc(s: String) = URLEncoder.encode(s, "UTF-8") - -fun main() { - val env = loadEnv("../.env") - val apiKey = getEnv(env, "CAPTCHAAI_API_KEY") - val sitekey = getEnv(env, "CAPTCHA_SITEKEY") - val pageurl = getEnv(env, "CAPTCHA_PAGEURL") - val pollInterval = getEnv(env, "POLL_INTERVAL", "5").toInt() - val maxTimeout = getEnv(env, "MAX_TIMEOUT", "120").toInt() - - // Validate - if (apiKey.isEmpty() || apiKey == "YOUR_API_KEY") { - println("[!] ERROR: CAPTCHAAI_API_KEY is not set.") - println(" Copy .env.example to .env and add your real API key.") - System.exit(1) - } - if (sitekey.isEmpty() || sitekey == "YOUR_SITE_KEY") { - println("[!] ERROR: CAPTCHA_SITEKEY is not set.") - println(" Add the hCaptcha sitekey from your target page to .env") - System.exit(1) - } - if (pageurl.isEmpty() || pageurl == "https://example.com/login") { - println("[!] WARNING: CAPTCHA_PAGEURL may not be set correctly.") - println(" Make sure it points to the actual target page.") - } - - // Submit task - println("[*] Submitting hCaptcha task...") - val submitParams = "key=${enc(apiKey)}&method=hcaptcha&sitekey=${enc(sitekey)}&pageurl=${enc(pageurl)}&json=1" - - val submitResp = try { - httpGet("$SUBMIT_URL?$submitParams") - } catch (e: Exception) { - println("[!] Network error during submission: ${e.message}") - System.exit(1) - return - } - - val submitStatus = jsonInt(submitResp, "status") - val submitRequest = jsonStr(submitResp, "request") - - if (submitStatus != 1) { - handleError(submitRequest) - System.exit(1) - } - - val taskId = submitRequest - println("[+] Task submitted. ID: $taskId") - - // Poll for result - println("[*] Waiting 15s before first poll...") - Thread.sleep(15000) - - var elapsed = 15 - var attempt = 0 - var backoff = pollInterval - - while (elapsed < maxTimeout) { - attempt++ - println("[*] Polling for result (attempt $attempt)...") - - val pollParams = "key=${enc(apiKey)}&action=get&id=${enc(taskId)}&json=1" - - val resultResp = try { - httpGet("$RESULT_URL?$pollParams") - } catch (e: Exception) { - println("[!] Network error during polling: ${e.message}") - Thread.sleep(backoff * 1000L) - elapsed += backoff - backoff = minOf(backoff * 2, 30) - continue - } - - val status = jsonInt(resultResp, "status") - val request = jsonStr(resultResp, "request") - - if (status == 1) { - val display = if (request.length > 50) request.substring(0, 50) else request - println("[+] Solved! Token: $display...") - println("[+] Full token length: ${request.length} characters") - println() - println("Next step: inject this token into the target page's") - println("h-captcha-response hidden field and submit the form.") - return - } - - if (request == "CAPCHA_NOT_READY") { - println("[*] Not ready yet, waiting ${pollInterval}s...") - Thread.sleep(pollInterval * 1000L) - elapsed += pollInterval - backoff = pollInterval - continue - } - - if (request in TRANSIENT_ERRORS) { - println("[!] Transient error: $request, retrying in ${backoff}s...") - Thread.sleep(backoff * 1000L) - elapsed += backoff - backoff = minOf(backoff * 2, 30) - continue - } - - if (request in SOLVE_ERRORS) { - println("[!] Solve error: $request") - println(" The CAPTCHA could not be solved. Verify parameters and retry.") - System.exit(1) - } - - println("[!] Unexpected error: $request") - System.exit(1) - } - - println("[!] Timeout: no solution received within $maxTimeout seconds.") - System.exit(1) -} diff --git a/articles/how-to-solve-hcaptcha-using-api/node/package.json b/articles/how-to-solve-hcaptcha-using-api/node/package.json deleted file mode 100644 index afac6b5..0000000 --- a/articles/how-to-solve-hcaptcha-using-api/node/package.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "name": "captchaai-hcaptcha-example", - "version": "1.0.0", - "description": "Solve hCaptcha using CaptchaAI API", - "main": "solve.js", - "scripts": { - "start": "node solve.js" - }, - "dependencies": { - "axios": "^1.6.0", - "dotenv": "^16.3.0" - }, - "license": "MIT" -} diff --git a/articles/how-to-solve-hcaptcha-using-api/node/solve.js b/articles/how-to-solve-hcaptcha-using-api/node/solve.js deleted file mode 100644 index c0ce948..0000000 --- a/articles/how-to-solve-hcaptcha-using-api/node/solve.js +++ /dev/null @@ -1,167 +0,0 @@ -/** - * Solve hCaptcha using the CaptchaAI API. - * - * Usage: - * npm install - * cp ../.env.example ../.env // then edit with your credentials - * node solve.js - */ - -require("dotenv").config({ path: require("path").join(__dirname, "..", ".env") }); -const axios = require("axios"); - -const SUBMIT_URL = "https://ocr.captchaai.com/in.php"; -const RESULT_URL = "https://ocr.captchaai.com/res.php"; - -const API_KEY = process.env.CAPTCHAAI_API_KEY || ""; -const CAPTCHA_SITEKEY = process.env.CAPTCHA_SITEKEY || ""; -const CAPTCHA_PAGEURL = process.env.CAPTCHA_PAGEURL || ""; -const POLL_INTERVAL = parseInt(process.env.POLL_INTERVAL || "5", 10); -const MAX_TIMEOUT = parseInt(process.env.MAX_TIMEOUT || "120", 10); - -const AUTH_ERRORS = new Set(["ERROR_WRONG_USER_KEY", "ERROR_KEY_DOES_NOT_EXIST", "IP_BANNED"]); -const BALANCE_ERRORS = new Set(["ERROR_ZERO_BALANCE"]); -const INPUT_ERRORS = new Set(["ERROR_PAGEURL", "ERROR_WRONG_GOOGLEKEY", "ERROR_BAD_PARAMETERS", "ERROR_BAD_TOKEN_OR_PAGEURL"]); -const TRANSIENT_ERRORS = new Set(["ERROR_SERVER_ERROR", "ERROR_INTERNAL_SERVER_ERROR"]); -const SOLVE_ERRORS = new Set(["ERROR_CAPTCHA_UNSOLVABLE"]); -const PROXY_ERRORS = new Set(["ERROR_BAD_PROXY", "ERROR_PROXY_CONNECTION_FAILED"]); - -function sleep(seconds) { - return new Promise((resolve) => setTimeout(resolve, seconds * 1000)); -} - -function validateConfig() { - if (!API_KEY || API_KEY === "YOUR_API_KEY") { - console.log("[!] ERROR: CAPTCHAAI_API_KEY is not set."); - console.log(" Copy .env.example to .env and add your real API key."); - process.exit(1); - } - if (!CAPTCHA_SITEKEY || CAPTCHA_SITEKEY === "YOUR_SITE_KEY") { - console.log("[!] ERROR: CAPTCHA_SITEKEY is not set."); - console.log(" Add the hCaptcha sitekey from your target page to .env"); - process.exit(1); - } - if (!CAPTCHA_PAGEURL || CAPTCHA_PAGEURL === "https://example.com/login") { - console.log("[!] WARNING: CAPTCHA_PAGEURL may not be set correctly."); - console.log(" Make sure it points to the actual target page."); - } -} - -async function submitTask() { - console.log("[*] Submitting hCaptcha task..."); - - const params = { - key: API_KEY, - method: "hcaptcha", - sitekey: CAPTCHA_SITEKEY, - pageurl: CAPTCHA_PAGEURL, - json: "1", - }; - - let resp; - try { - resp = await axios.get(SUBMIT_URL, { params, timeout: 30000 }); - } catch (err) { - console.log(`[!] Network error during submission: ${err.message}`); - process.exit(1); - } - - const data = resp.data; - if (data.status !== 1) { - const error = data.request || "UNKNOWN_ERROR"; - if (AUTH_ERRORS.has(error)) { - console.log(`[!] Authentication error: ${error}`); - console.log(" Check your API key at https://captchaai.com/dashboard"); - } else if (BALANCE_ERRORS.has(error)) { - console.log(`[!] Balance error: ${error}`); - console.log(" Top up your account at https://captchaai.com"); - } else if (INPUT_ERRORS.has(error)) { - console.log(`[!] Input error: ${error}`); - console.log(" Verify your sitekey and page URL are correct."); - } else if (PROXY_ERRORS.has(error)) { - console.log(`[!] Proxy error: ${error}`); - console.log(" Check your proxy configuration or try a different proxy."); - } else { - console.log(`[!] Submission failed: ${error}`); - } - process.exit(1); - } - - const taskId = data.request; - console.log(`[+] Task submitted. ID: ${taskId}`); - return taskId; -} - -async function pollResult(taskId) { - console.log("[*] Waiting 15s before first poll..."); - await sleep(15); - - const params = { key: API_KEY, action: "get", id: taskId, json: "1" }; - let elapsed = 15; - let attempt = 0; - let backoff = POLL_INTERVAL; - - while (elapsed < MAX_TIMEOUT) { - attempt++; - console.log(`[*] Polling for result (attempt ${attempt})...`); - - let resp; - try { - resp = await axios.get(RESULT_URL, { params, timeout: 30000 }); - } catch (err) { - console.log(`[!] Network error during polling: ${err.message}`); - await sleep(backoff); - elapsed += backoff; - backoff = Math.min(backoff * 2, 30); - continue; - } - - const data = resp.data; - - if (data.status === 1) { - return data.request; - } - - const error = data.request || ""; - if (error === "CAPCHA_NOT_READY") { - console.log(`[*] Not ready yet, waiting ${POLL_INTERVAL}s...`); - await sleep(POLL_INTERVAL); - elapsed += POLL_INTERVAL; - backoff = POLL_INTERVAL; - continue; - } - - if (TRANSIENT_ERRORS.has(error)) { - console.log(`[!] Transient error: ${error}, retrying in ${backoff}s...`); - await sleep(backoff); - elapsed += backoff; - backoff = Math.min(backoff * 2, 30); - continue; - } - - if (SOLVE_ERRORS.has(error)) { - console.log(`[!] Solve error: ${error}`); - console.log(" The CAPTCHA could not be solved. Verify parameters and retry."); - process.exit(1); - } - - console.log(`[!] Unexpected error: ${error}`); - process.exit(1); - } - - console.log(`[!] Timeout: no solution received within ${MAX_TIMEOUT} seconds.`); - process.exit(1); -} - -async function main() { - validateConfig(); - const taskId = await submitTask(); - const token = await pollResult(taskId); - console.log(`[+] Solved! Token: ${token.substring(0, 50)}...`); - console.log(`[+] Full token length: ${token.length} characters`); - console.log(); - console.log("Next step: inject this token into the target page's"); - console.log("h-captcha-response hidden field and submit the form."); -} - -main(); diff --git a/articles/how-to-solve-hcaptcha-using-api/php/composer.json b/articles/how-to-solve-hcaptcha-using-api/php/composer.json deleted file mode 100644 index b5b328f..0000000 --- a/articles/how-to-solve-hcaptcha-using-api/php/composer.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "name": "captchaai/hcaptcha-example", - "description": "Solve hCaptcha using CaptchaAI API", - "require": { - "vlucas/phpdotenv": "^5.5" - } -} diff --git a/articles/how-to-solve-hcaptcha-using-api/php/solve.php b/articles/how-to-solve-hcaptcha-using-api/php/solve.php deleted file mode 100644 index 671c633..0000000 --- a/articles/how-to-solve-hcaptcha-using-api/php/solve.php +++ /dev/null @@ -1,157 +0,0 @@ -load(); - -define('SUBMIT_URL', 'https://ocr.captchaai.com/in.php'); -define('RESULT_URL', 'https://ocr.captchaai.com/res.php'); - -$apiKey = $_ENV['CAPTCHAAI_API_KEY'] ?? ''; -$sitekey = $_ENV['CAPTCHA_SITEKEY'] ?? ''; -$pageurl = $_ENV['CAPTCHA_PAGEURL'] ?? ''; -$pollInterval = (int)($_ENV['POLL_INTERVAL'] ?? 5); -$maxTimeout = (int)($_ENV['MAX_TIMEOUT'] ?? 120); - -$authErrors = ['ERROR_WRONG_USER_KEY', 'ERROR_KEY_DOES_NOT_EXIST', 'IP_BANNED']; -$balanceErrors = ['ERROR_ZERO_BALANCE']; -$inputErrors = ['ERROR_PAGEURL', 'ERROR_WRONG_GOOGLEKEY', 'ERROR_BAD_PARAMETERS', 'ERROR_BAD_TOKEN_OR_PAGEURL']; -$transientErrors = ['ERROR_SERVER_ERROR', 'ERROR_INTERNAL_SERVER_ERROR']; -$solveErrors = ['ERROR_CAPTCHA_UNSOLVABLE']; -$proxyErrors = ['ERROR_BAD_PROXY', 'ERROR_PROXY_CONNECTION_FAILED']; - -// --- Validate configuration --- -if (empty($apiKey) || $apiKey === 'YOUR_API_KEY') { - echo "[!] ERROR: CAPTCHAAI_API_KEY is not set.\n"; - echo " Copy .env.example to .env and add your real API key.\n"; - exit(1); -} -if (empty($sitekey) || $sitekey === 'YOUR_SITE_KEY') { - echo "[!] ERROR: CAPTCHA_SITEKEY is not set.\n"; - echo " Add the hCaptcha sitekey from your target page to .env\n"; - exit(1); -} -if (empty($pageurl) || $pageurl === 'https://example.com/login') { - echo "[!] WARNING: CAPTCHA_PAGEURL may not be set correctly.\n"; - echo " Make sure it points to the actual target page.\n"; -} - -// --- Submit task --- -echo "[*] Submitting hCaptcha task...\n"; -$submitParams = http_build_query([ - 'key' => $apiKey, - 'method' => 'hcaptcha', - 'sitekey' => $sitekey, - 'pageurl' => $pageurl, - 'json' => '1', -]); - -$ctx = stream_context_create(['http' => ['timeout' => 30]]); -$submitResponse = @file_get_contents(SUBMIT_URL . '?' . $submitParams, false, $ctx); -if ($submitResponse === false) { - echo "[!] Network error during submission.\n"; - exit(1); -} - -$submitData = json_decode($submitResponse, true); -if (($submitData['status'] ?? 0) !== 1) { - $error = $submitData['request'] ?? 'UNKNOWN_ERROR'; - if (in_array($error, $authErrors)) { - echo "[!] Authentication error: $error\n"; - echo " Check your API key at https://captchaai.com/dashboard\n"; - } elseif (in_array($error, $balanceErrors)) { - echo "[!] Balance error: $error\n"; - echo " Top up your account at https://captchaai.com\n"; - } elseif (in_array($error, $inputErrors)) { - echo "[!] Input error: $error\n"; - echo " Verify your sitekey and page URL are correct.\n"; - } elseif (in_array($error, $proxyErrors)) { - echo "[!] Proxy error: $error\n"; - echo " Check your proxy configuration or try a different proxy.\n"; - } else { - echo "[!] Submission failed: $error\n"; - } - exit(1); -} - -$taskId = $submitData['request']; -echo "[+] Task submitted. ID: $taskId\n"; - -// --- Poll for result --- -echo "[*] Waiting 15s before first poll...\n"; -sleep(15); - -$elapsed = 15; -$attempt = 0; -$backoff = $pollInterval; - -while ($elapsed < $maxTimeout) { - $attempt++; - echo "[*] Polling for result (attempt $attempt)...\n"; - - $resultParams = http_build_query([ - 'key' => $apiKey, - 'action' => 'get', - 'id' => $taskId, - 'json' => '1', - ]); - - $resultResponse = @file_get_contents(RESULT_URL . '?' . $resultParams, false, $ctx); - if ($resultResponse === false) { - echo "[!] Network error during polling.\n"; - sleep($backoff); - $elapsed += $backoff; - $backoff = min($backoff * 2, 30); - continue; - } - - $resultData = json_decode($resultResponse, true); - - if (($resultData['status'] ?? 0) === 1) { - $token = $resultData['request']; - echo "[+] Solved! Token: " . substr($token, 0, 50) . "...\n"; - echo "[+] Full token length: " . strlen($token) . " characters\n"; - echo "\n"; - echo "Next step: inject this token into the target page's\n"; - echo "h-captcha-response hidden field and submit the form.\n"; - exit(0); - } - - $error = $resultData['request'] ?? ''; - if ($error === 'CAPCHA_NOT_READY') { - echo "[*] Not ready yet, waiting {$pollInterval}s...\n"; - sleep($pollInterval); - $elapsed += $pollInterval; - $backoff = $pollInterval; - continue; - } - - if (in_array($error, $transientErrors)) { - echo "[!] Transient error: $error, retrying in {$backoff}s...\n"; - sleep($backoff); - $elapsed += $backoff; - $backoff = min($backoff * 2, 30); - continue; - } - - if (in_array($error, $solveErrors)) { - echo "[!] Solve error: $error\n"; - echo " The CAPTCHA could not be solved. Verify parameters and retry.\n"; - exit(1); - } - - echo "[!] Unexpected error: $error\n"; - exit(1); -} - -echo "[!] Timeout: no solution received within {$maxTimeout} seconds.\n"; -exit(1); diff --git a/articles/how-to-solve-hcaptcha-using-api/python/requirements.txt b/articles/how-to-solve-hcaptcha-using-api/python/requirements.txt deleted file mode 100644 index f49b6b8..0000000 --- a/articles/how-to-solve-hcaptcha-using-api/python/requirements.txt +++ /dev/null @@ -1,2 +0,0 @@ -requests>=2.28.0 -python-dotenv>=1.0.0 diff --git a/articles/how-to-solve-hcaptcha-using-api/python/solve.py b/articles/how-to-solve-hcaptcha-using-api/python/solve.py deleted file mode 100644 index 62a7f8b..0000000 --- a/articles/how-to-solve-hcaptcha-using-api/python/solve.py +++ /dev/null @@ -1,169 +0,0 @@ -"""Solve hCaptcha using the CaptchaAI API. - -Usage: - pip install -r requirements.txt - cp ../.env.example ../.env # then edit with your credentials - python solve.py -""" - -import os -import sys -import time - -import requests -from dotenv import load_dotenv - -# Load environment variables from the parent .env file -load_dotenv(dotenv_path=os.path.join(os.path.dirname(__file__), "..", ".env")) - -SUBMIT_URL = "https://ocr.captchaai.com/in.php" -RESULT_URL = "https://ocr.captchaai.com/res.php" - -API_KEY = os.getenv("CAPTCHAAI_API_KEY", "") -CAPTCHA_SITEKEY = os.getenv("CAPTCHA_SITEKEY", "") -CAPTCHA_PAGEURL = os.getenv("CAPTCHA_PAGEURL", "") -POLL_INTERVAL = int(os.getenv("POLL_INTERVAL", "5")) -MAX_TIMEOUT = int(os.getenv("MAX_TIMEOUT", "120")) - -# --- Error categories --- -AUTH_ERRORS = {"ERROR_WRONG_USER_KEY", "ERROR_KEY_DOES_NOT_EXIST", "IP_BANNED"} -BALANCE_ERRORS = {"ERROR_ZERO_BALANCE"} -INPUT_ERRORS = {"ERROR_PAGEURL", "ERROR_WRONG_GOOGLEKEY", "ERROR_BAD_PARAMETERS", "ERROR_BAD_TOKEN_OR_PAGEURL"} -TRANSIENT_ERRORS = {"ERROR_SERVER_ERROR", "ERROR_INTERNAL_SERVER_ERROR"} -SOLVE_ERRORS = {"ERROR_CAPTCHA_UNSOLVABLE"} -PROXY_ERRORS = {"ERROR_BAD_PROXY", "ERROR_PROXY_CONNECTION_FAILED"} - - -def validate_config() -> None: - """Check that required environment variables are set.""" - if not API_KEY or API_KEY == "YOUR_API_KEY": - print("[!] ERROR: CAPTCHAAI_API_KEY is not set.") - print(" Copy .env.example to .env and add your real API key.") - sys.exit(1) - if not CAPTCHA_SITEKEY or CAPTCHA_SITEKEY == "YOUR_SITE_KEY": - print("[!] ERROR: CAPTCHA_SITEKEY is not set.") - print(" Add the hCaptcha sitekey from your target page to .env") - sys.exit(1) - if not CAPTCHA_PAGEURL or CAPTCHA_PAGEURL == "https://example.com/login": - print("[!] WARNING: CAPTCHA_PAGEURL may not be set correctly.") - print(" Make sure it points to the actual target page.") - - -def submit_task() -> str: - """Submit the CAPTCHA task and return the task ID.""" - print("[*] Submitting hCaptcha task...") - payload = { - "key": API_KEY, - "method": "hcaptcha", - "sitekey": CAPTCHA_SITEKEY, - "pageurl": CAPTCHA_PAGEURL, - "json": "1", - } - - try: - resp = requests.get(SUBMIT_URL, params=payload, timeout=30) - resp.raise_for_status() - except requests.RequestException as exc: - print(f"[!] Network error during submission: {exc}") - sys.exit(1) - - data = resp.json() - - if data.get("status") != 1: - error = data.get("request", "UNKNOWN_ERROR") - if error in AUTH_ERRORS: - print(f"[!] Authentication error: {error}") - print(" Check your API key at https://captchaai.com/dashboard") - elif error in BALANCE_ERRORS: - print(f"[!] Balance error: {error}") - print(" Top up your account at https://captchaai.com") - elif error in INPUT_ERRORS: - print(f"[!] Input error: {error}") - print(" Verify your sitekey and page URL are correct.") - elif error in PROXY_ERRORS: - print(f"[!] Proxy error: {error}") - print(" Check your proxy configuration or try a different proxy.") - else: - print(f"[!] Submission failed: {error}") - sys.exit(1) - - task_id = data["request"] - print(f"[+] Task submitted. ID: {task_id}") - return task_id - - -def poll_result(task_id: str) -> str: - """Poll for the CAPTCHA solution with timeout and retry logic.""" - print("[*] Waiting 15s before first poll...") - time.sleep(15) - - params = { - "key": API_KEY, - "action": "get", - "id": task_id, - "json": "1", - } - - elapsed = 15 - attempt = 0 - backoff = POLL_INTERVAL - - while elapsed < MAX_TIMEOUT: - attempt += 1 - print(f"[*] Polling for result (attempt {attempt})...") - - try: - resp = requests.get(RESULT_URL, params=params, timeout=30) - resp.raise_for_status() - except requests.RequestException as exc: - print(f"[!] Network error during polling: {exc}") - time.sleep(backoff) - elapsed += backoff - backoff = min(backoff * 2, 30) - continue - - data = resp.json() - - if data.get("status") == 1: - return data["request"] - - error = data.get("request", "") - if error == "CAPCHA_NOT_READY": - print(f"[*] Not ready yet, waiting {POLL_INTERVAL}s...") - time.sleep(POLL_INTERVAL) - elapsed += POLL_INTERVAL - backoff = POLL_INTERVAL - continue - - if error in TRANSIENT_ERRORS: - print(f"[!] Transient error: {error}, retrying in {backoff}s...") - time.sleep(backoff) - elapsed += backoff - backoff = min(backoff * 2, 30) - continue - - if error in SOLVE_ERRORS: - print(f"[!] Solve error: {error}") - print(" The CAPTCHA could not be solved. Verify parameters and retry.") - sys.exit(1) - - print(f"[!] Unexpected error: {error}") - sys.exit(1) - - print(f"[!] Timeout: no solution received within {MAX_TIMEOUT} seconds.") - sys.exit(1) - - -def main() -> None: - validate_config() - task_id = submit_task() - token = poll_result(task_id) - print(f"[+] Solved! Token: {token[:50]}...") - print(f"[+] Full token length: {len(token)} characters") - print() - print("Next step: inject this token into the target page's") - print("h-captcha-response hidden field and submit the form.") - - -if __name__ == "__main__": - main() diff --git a/articles/how-to-solve-hcaptcha-using-api/ruby/Gemfile b/articles/how-to-solve-hcaptcha-using-api/ruby/Gemfile deleted file mode 100644 index 05a677e..0000000 --- a/articles/how-to-solve-hcaptcha-using-api/ruby/Gemfile +++ /dev/null @@ -1,2 +0,0 @@ -source "https://rubygems.org" -# No external gems needed — uses Ruby stdlib (net/http, json, uri) diff --git a/articles/how-to-solve-hcaptcha-using-api/ruby/solve.rb b/articles/how-to-solve-hcaptcha-using-api/ruby/solve.rb deleted file mode 100644 index 577b959..0000000 --- a/articles/how-to-solve-hcaptcha-using-api/ruby/solve.rb +++ /dev/null @@ -1,184 +0,0 @@ -# Solve hCaptcha using the CaptchaAI API. -# -# Usage: -# ruby solve.rb - -require "net/http" -require "json" -require "uri" - -SUBMIT_URL = "https://ocr.captchaai.com/in.php" -RESULT_URL = "https://ocr.captchaai.com/res.php" - -AUTH_ERRORS = %w[ERROR_WRONG_USER_KEY ERROR_KEY_DOES_NOT_EXIST IP_BANNED].freeze -BALANCE_ERRORS = %w[ERROR_ZERO_BALANCE].freeze -INPUT_ERRORS = %w[ERROR_PAGEURL ERROR_WRONG_GOOGLEKEY ERROR_BAD_PARAMETERS ERROR_BAD_TOKEN_OR_PAGEURL].freeze -TRANSIENT_ERRORS = %w[ERROR_SERVER_ERROR ERROR_INTERNAL_SERVER_ERROR].freeze -SOLVE_ERRORS = %w[ERROR_CAPTCHA_UNSOLVABLE].freeze -PROXY_ERRORS = %w[ERROR_BAD_PROXY ERROR_PROXY_CONNECTION_FAILED].freeze - -def load_env(path) - env = {} - return env unless File.exist?(path) - File.readlines(path).each do |line| - line = line.strip - next if line.empty? || line.start_with?("#") - key, value = line.split("=", 2) - env[key.strip] = value&.strip || "" - end - env -end - -def get_env(env, key, fallback = "") - v = env[key] - return v if v && !v.empty? - v = ENV[key] - return v if v && !v.empty? - fallback -end - -env = load_env(File.join(__dir__, "..", ".env")) -api_key = get_env(env, "CAPTCHAAI_API_KEY") -sitekey = get_env(env, "CAPTCHA_SITEKEY") -pageurl = get_env(env, "CAPTCHA_PAGEURL") -poll_interval = get_env(env, "POLL_INTERVAL", "5").to_i -max_timeout = get_env(env, "MAX_TIMEOUT", "120").to_i - -# Validate -if api_key.empty? || api_key == "YOUR_API_KEY" - puts "[!] ERROR: CAPTCHAAI_API_KEY is not set." - puts " Copy .env.example to .env and add your real API key." - exit 1 -end -if sitekey.empty? || sitekey == "YOUR_SITE_KEY" - puts "[!] ERROR: CAPTCHA_SITEKEY is not set." - puts " Add the hCaptcha sitekey from your target page to .env" - exit 1 -end -if pageurl.empty? || pageurl == "https://example.com/login" - puts "[!] WARNING: CAPTCHA_PAGEURL may not be set correctly." - puts " Make sure it points to the actual target page." -end - -def handle_error(error) - if AUTH_ERRORS.include?(error) - puts "[!] Authentication error: #{error}" - puts " Check your API key at https://captchaai.com/dashboard" - elsif BALANCE_ERRORS.include?(error) - puts "[!] Balance error: #{error}" - puts " Top up your account at https://captchaai.com" - elsif INPUT_ERRORS.include?(error) - puts "[!] Input error: #{error}" - puts " Verify your sitekey and page URL are correct." - elsif PROXY_ERRORS.include?(error) - puts "[!] Proxy error: #{error}" - puts " Check your proxy configuration or try a different proxy." - else - puts "[!] Submission failed: #{error}" - end -end - -def http_get(url_str) - uri = URI(url_str) - http = Net::HTTP.new(uri.host, uri.port) - http.use_ssl = true - http.open_timeout = 30 - http.read_timeout = 30 - response = http.get("#{uri.path}?#{uri.query}") - JSON.parse(response.body) -end - -# Submit task -puts "[*] Submitting hCaptcha task..." -params = URI.encode_www_form( - key: api_key, - method: "hcaptcha", - sitekey: sitekey, - pageurl: pageurl, - json: "1" -) - -begin - submit_data = http_get("#{SUBMIT_URL}?#{params}") -rescue StandardError => e - puts "[!] Network error during submission: #{e.message}" - exit 1 -end - -unless submit_data["status"] == 1 - handle_error(submit_data["request"] || "UNKNOWN_ERROR") - exit 1 -end - -task_id = submit_data["request"] -puts "[+] Task submitted. ID: #{task_id}" - -# Poll for result -puts "[*] Waiting 15s before first poll..." -sleep 15 - -elapsed = 15 -attempt = 0 -backoff = poll_interval - -while elapsed < max_timeout - attempt += 1 - puts "[*] Polling for result (attempt #{attempt})..." - - poll_params = URI.encode_www_form( - key: api_key, - action: "get", - id: task_id, - json: "1" - ) - - begin - result_data = http_get("#{RESULT_URL}?#{poll_params}") - rescue StandardError => e - puts "[!] Network error during polling: #{e.message}" - sleep backoff - elapsed += backoff - backoff = [backoff * 2, 30].min - next - end - - if result_data["status"] == 1 - token = result_data["request"] - display = token.length > 50 ? token[0, 50] : token - puts "[+] Solved! Token: #{display}..." - puts "[+] Full token length: #{token.length} characters" - puts - puts "Next step: inject this token into the target page's" - puts "h-captcha-response hidden field and submit the form." - exit 0 - end - - error = result_data["request"] || "" - if error == "CAPCHA_NOT_READY" - puts "[*] Not ready yet, waiting #{poll_interval}s..." - sleep poll_interval - elapsed += poll_interval - backoff = poll_interval - next - end - - if TRANSIENT_ERRORS.include?(error) - puts "[!] Transient error: #{error}, retrying in #{backoff}s..." - sleep backoff - elapsed += backoff - backoff = [backoff * 2, 30].min - next - end - - if SOLVE_ERRORS.include?(error) - puts "[!] Solve error: #{error}" - puts " The CAPTCHA could not be solved. Verify parameters and retry." - exit 1 - end - - puts "[!] Unexpected error: #{error}" - exit 1 -end - -puts "[!] Timeout: no solution received within #{max_timeout} seconds." -exit 1 diff --git a/articles/how-to-solve-hcaptcha-using-api/rust/Cargo.lock b/articles/how-to-solve-hcaptcha-using-api/rust/Cargo.lock deleted file mode 100644 index 8b07fcd..0000000 --- a/articles/how-to-solve-hcaptcha-using-api/rust/Cargo.lock +++ /dev/null @@ -1,675 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 4 - -[[package]] -name = "adler2" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" - -[[package]] -name = "base64" -version = "0.22.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" - -[[package]] -name = "captchaai-hcaptcha-example" -version = "1.0.0" -dependencies = [ - "serde_json", - "ureq", - "urlencoding", -] - -[[package]] -name = "cc" -version = "1.2.60" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43c5703da9466b66a946814e1adf53ea2c90f10063b86290cc9eb67ce3478a20" -dependencies = [ - "find-msvc-tools", - "shlex", -] - -[[package]] -name = "cfg-if" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" - -[[package]] -name = "crc32fast" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "displaydoc" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "find-msvc-tools" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" - -[[package]] -name = "flate2" -version = "1.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c" -dependencies = [ - "crc32fast", - "miniz_oxide", -] - -[[package]] -name = "form_urlencoded" -version = "1.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" -dependencies = [ - "percent-encoding", -] - -[[package]] -name = "getrandom" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" -dependencies = [ - "cfg-if", - "libc", - "wasi", -] - -[[package]] -name = "icu_collections" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2984d1cd16c883d7935b9e07e44071dca8d917fd52ecc02c04d5fa0b5a3f191c" -dependencies = [ - "displaydoc", - "potential_utf", - "utf8_iter", - "yoke", - "zerofrom", - "zerovec", -] - -[[package]] -name = "icu_locale_core" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92219b62b3e2b4d88ac5119f8904c10f8f61bf7e95b640d25ba3075e6cac2c29" -dependencies = [ - "displaydoc", - "litemap", - "tinystr", - "writeable", - "zerovec", -] - -[[package]] -name = "icu_normalizer" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c56e5ee99d6e3d33bd91c5d85458b6005a22140021cc324cea84dd0e72cff3b4" -dependencies = [ - "icu_collections", - "icu_normalizer_data", - "icu_properties", - "icu_provider", - "smallvec", - "zerovec", -] - -[[package]] -name = "icu_normalizer_data" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da3be0ae77ea334f4da67c12f149704f19f81d1adf7c51cf482943e84a2bad38" - -[[package]] -name = "icu_properties" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bee3b67d0ea5c2cca5003417989af8996f8604e34fb9ddf96208a033901e70de" -dependencies = [ - "icu_collections", - "icu_locale_core", - "icu_properties_data", - "icu_provider", - "zerotrie", - "zerovec", -] - -[[package]] -name = "icu_properties_data" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e2bbb201e0c04f7b4b3e14382af113e17ba4f63e2c9d2ee626b720cbce54a14" - -[[package]] -name = "icu_provider" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "139c4cf31c8b5f33d7e199446eff9c1e02decfc2f0eec2c8d71f65befa45b421" -dependencies = [ - "displaydoc", - "icu_locale_core", - "writeable", - "yoke", - "zerofrom", - "zerotrie", - "zerovec", -] - -[[package]] -name = "idna" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" -dependencies = [ - "idna_adapter", - "smallvec", - "utf8_iter", -] - -[[package]] -name = "idna_adapter" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" -dependencies = [ - "icu_normalizer", - "icu_properties", -] - -[[package]] -name = "itoa" -version = "1.0.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" - -[[package]] -name = "libc" -version = "0.2.185" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52ff2c0fe9bc6cb6b14a0592c2ff4fa9ceb83eea9db979b0487cd054946a2b8f" - -[[package]] -name = "litemap" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92daf443525c4cce67b150400bc2316076100ce0b3686209eb8cf3c31612e6f0" - -[[package]] -name = "log" -version = "0.4.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" - -[[package]] -name = "memchr" -version = "2.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" - -[[package]] -name = "miniz_oxide" -version = "0.8.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" -dependencies = [ - "adler2", - "simd-adler32", -] - -[[package]] -name = "once_cell" -version = "1.21.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" - -[[package]] -name = "percent-encoding" -version = "2.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" - -[[package]] -name = "potential_utf" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0103b1cef7ec0cf76490e969665504990193874ea05c85ff9bab8b911d0a0564" -dependencies = [ - "zerovec", -] - -[[package]] -name = "proc-macro2" -version = "1.0.106" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quote" -version = "1.0.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "ring" -version = "0.17.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" -dependencies = [ - "cc", - "cfg-if", - "getrandom", - "libc", - "untrusted", - "windows-sys", -] - -[[package]] -name = "rustls" -version = "0.23.38" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69f9466fb2c14ea04357e91413efb882e2a6d4a406e625449bc0a5d360d53a21" -dependencies = [ - "log", - "once_cell", - "ring", - "rustls-pki-types", - "rustls-webpki", - "subtle", - "zeroize", -] - -[[package]] -name = "rustls-pki-types" -version = "1.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be040f8b0a225e40375822a563fa9524378b9d63112f53e19ffff34df5d33fdd" -dependencies = [ - "zeroize", -] - -[[package]] -name = "rustls-webpki" -version = "0.103.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8279bb85272c9f10811ae6a6c547ff594d6a7f3c6c6b02ee9726d1d0dcfcdd06" -dependencies = [ - "ring", - "rustls-pki-types", - "untrusted", -] - -[[package]] -name = "serde" -version = "1.0.228" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" -dependencies = [ - "serde_core", -] - -[[package]] -name = "serde_core" -version = "1.0.228" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.228" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "serde_json" -version = "1.0.149" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" -dependencies = [ - "itoa", - "memchr", - "serde", - "serde_core", - "zmij", -] - -[[package]] -name = "shlex" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" - -[[package]] -name = "simd-adler32" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "703d5c7ef118737c72f1af64ad2f6f8c5e1921f818cdcb97b8fe6fc69bf66214" - -[[package]] -name = "smallvec" -version = "1.15.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" - -[[package]] -name = "stable_deref_trait" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" - -[[package]] -name = "subtle" -version = "2.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" - -[[package]] -name = "syn" -version = "2.0.117" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "synstructure" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "tinystr" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8323304221c2a851516f22236c5722a72eaa19749016521d6dff0824447d96d" -dependencies = [ - "displaydoc", - "zerovec", -] - -[[package]] -name = "unicode-ident" -version = "1.0.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" - -[[package]] -name = "untrusted" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" - -[[package]] -name = "ureq" -version = "2.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02d1a66277ed75f640d608235660df48c8e3c19f3b4edb6a263315626cc3c01d" -dependencies = [ - "base64", - "flate2", - "log", - "once_cell", - "rustls", - "rustls-pki-types", - "url", - "webpki-roots 0.26.11", -] - -[[package]] -name = "url" -version = "2.5.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed" -dependencies = [ - "form_urlencoded", - "idna", - "percent-encoding", - "serde", -] - -[[package]] -name = "urlencoding" -version = "2.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" - -[[package]] -name = "utf8_iter" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" - -[[package]] -name = "wasi" -version = "0.11.1+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" - -[[package]] -name = "webpki-roots" -version = "0.26.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "521bc38abb08001b01866da9f51eb7c5d647a19260e00054a8c7fd5f9e57f7a9" -dependencies = [ - "webpki-roots 1.0.7", -] - -[[package]] -name = "webpki-roots" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52f5ee44c96cf55f1b349600768e3ece3a8f26010c05265ab73f945bb1a2eb9d" -dependencies = [ - "rustls-pki-types", -] - -[[package]] -name = "windows-sys" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" -dependencies = [ - "windows-targets", -] - -[[package]] -name = "windows-targets" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" -dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_gnullvm", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" - -[[package]] -name = "windows_i686_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" - -[[package]] -name = "windows_i686_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" - -[[package]] -name = "windows_i686_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" - -[[package]] -name = "writeable" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ffae5123b2d3fc086436f8834ae3ab053a283cfac8fe0a0b8eaae044768a4c4" - -[[package]] -name = "yoke" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abe8c5fda708d9ca3df187cae8bfb9ceda00dd96231bed36e445a1a48e66f9ca" -dependencies = [ - "stable_deref_trait", - "yoke-derive", - "zerofrom", -] - -[[package]] -name = "yoke-derive" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de844c262c8848816172cef550288e7dc6c7b7814b4ee56b3e1553f275f1858e" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "synstructure", -] - -[[package]] -name = "zerofrom" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69faa1f2a1ea75661980b013019ed6687ed0e83d069bc1114e2cc74c6c04c4df" -dependencies = [ - "zerofrom-derive", -] - -[[package]] -name = "zerofrom-derive" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11532158c46691caf0f2593ea8358fed6bbf68a0315e80aae9bd41fbade684a1" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "synstructure", -] - -[[package]] -name = "zeroize" -version = "1.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" - -[[package]] -name = "zerotrie" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f9152d31db0792fa83f70fb2f83148effb5c1f5b8c7686c3459e361d9bc20bf" -dependencies = [ - "displaydoc", - "yoke", - "zerofrom", -] - -[[package]] -name = "zerovec" -version = "0.11.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90f911cbc359ab6af17377d242225f4d75119aec87ea711a880987b18cd7b239" -dependencies = [ - "yoke", - "zerofrom", - "zerovec-derive", -] - -[[package]] -name = "zerovec-derive" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "625dc425cab0dca6dc3c3319506e6593dcb08a9f387ea3b284dbd52a92c40555" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "zmij" -version = "1.0.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" diff --git a/articles/how-to-solve-hcaptcha-using-api/rust/Cargo.toml b/articles/how-to-solve-hcaptcha-using-api/rust/Cargo.toml deleted file mode 100644 index 5d52eef..0000000 --- a/articles/how-to-solve-hcaptcha-using-api/rust/Cargo.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -name = "captchaai-hcaptcha-example" -version = "1.0.0" -edition = "2021" - -[dependencies] -ureq = "2" -serde_json = "1" -urlencoding = "2" diff --git a/articles/how-to-solve-hcaptcha-using-api/rust/src/main.rs b/articles/how-to-solve-hcaptcha-using-api/rust/src/main.rs deleted file mode 100644 index e0778e5..0000000 --- a/articles/how-to-solve-hcaptcha-using-api/rust/src/main.rs +++ /dev/null @@ -1,219 +0,0 @@ -// Solve hCaptcha using the CaptchaAI API. -// -// Usage: -// cargo run - -use std::collections::HashMap; -use std::fs; -use std::path::Path; -use std::thread; -use std::time::Duration; - -const SUBMIT_URL: &str = "https://ocr.captchaai.com/in.php"; -const RESULT_URL: &str = "https://ocr.captchaai.com/res.php"; - -fn load_env(path: &str) -> HashMap { - let mut env = HashMap::new(); - if let Ok(content) = fs::read_to_string(path) { - for line in content.lines() { - let trimmed = line.trim(); - if trimmed.is_empty() || trimmed.starts_with('#') { - continue; - } - if let Some((key, value)) = trimmed.split_once('=') { - env.insert(key.trim().to_string(), value.trim().to_string()); - } - } - } - env -} - -fn get_env(env: &HashMap, key: &str, fallback: &str) -> String { - if let Some(v) = env.get(key) { - if !v.is_empty() { - return v.clone(); - } - } - if let Ok(v) = std::env::var(key) { - if !v.is_empty() { - return v; - } - } - fallback.to_string() -} - -fn json_str(json: &str, key: &str) -> String { - let pattern = format!("\"{}\":\"", key); - if let Some(idx) = json.find(&pattern) { - let start = idx + pattern.len(); - if let Some(end) = json[start..].find('"') { - return json[start..start + end].to_string(); - } - } - String::new() -} - -fn json_int(json: &str, key: &str) -> i32 { - let pattern = format!("\"{}\":", key); - if let Some(idx) = json.find(&pattern) { - let start = idx + pattern.len(); - let num_str: String = json[start..] - .chars() - .take_while(|c| c.is_ascii_digit() || *c == '-') - .collect(); - return num_str.parse().unwrap_or(0); - } - 0 -} - -fn handle_error(error: &str) { - let auth = ["ERROR_WRONG_USER_KEY", "ERROR_KEY_DOES_NOT_EXIST", "IP_BANNED"]; - let balance = ["ERROR_ZERO_BALANCE"]; - let input = ["ERROR_PAGEURL", "ERROR_WRONG_GOOGLEKEY", "ERROR_BAD_PARAMETERS", "ERROR_BAD_TOKEN_OR_PAGEURL"]; - let proxy = ["ERROR_BAD_PROXY", "ERROR_PROXY_CONNECTION_FAILED"]; - - if auth.contains(&error) { - println!("[!] Authentication error: {}", error); - println!(" Check your API key at https://captchaai.com/dashboard"); - } else if balance.contains(&error) { - println!("[!] Balance error: {}", error); - println!(" Top up your account at https://captchaai.com"); - } else if input.contains(&error) { - println!("[!] Input error: {}", error); - println!(" Verify your sitekey and page URL are correct."); - } else if proxy.contains(&error) { - println!("[!] Proxy error: {}", error); - println!(" Check your proxy configuration or try a different proxy."); - } else { - println!("[!] Submission failed: {}", error); - } -} - -fn main() { - let env = load_env("../.env"); - let api_key = get_env(&env, "CAPTCHAAI_API_KEY", ""); - let sitekey = get_env(&env, "CAPTCHA_SITEKEY", ""); - let pageurl = get_env(&env, "CAPTCHA_PAGEURL", ""); - let poll_interval: u64 = get_env(&env, "POLL_INTERVAL", "5").parse().unwrap_or(5); - let max_timeout: u64 = get_env(&env, "MAX_TIMEOUT", "120").parse().unwrap_or(120); - - // Validate - if api_key.is_empty() || api_key == "YOUR_API_KEY" { - println!("[!] ERROR: CAPTCHAAI_API_KEY is not set."); - println!(" Copy .env.example to .env and add your real API key."); - std::process::exit(1); - } - if sitekey.is_empty() || sitekey == "YOUR_SITE_KEY" { - println!("[!] ERROR: CAPTCHA_SITEKEY is not set."); - println!(" Add the hCaptcha sitekey from your target page to .env"); - std::process::exit(1); - } - if pageurl.is_empty() || pageurl == "https://example.com/login" { - println!("[!] WARNING: CAPTCHA_PAGEURL may not be set correctly."); - println!(" Make sure it points to the actual target page."); - } - - // Submit task - println!("[*] Submitting hCaptcha task..."); - let submit_url = format!( - "{}?key={}&method=hcaptcha&sitekey={}&pageurl={}&json=1", - SUBMIT_URL, - urlencoding::encode(&api_key), - urlencoding::encode(&sitekey), - urlencoding::encode(&pageurl) - ); - - let submit_resp = match ureq::get(&submit_url).call() { - Ok(r) => r.into_string().unwrap_or_default(), - Err(e) => { - println!("[!] Network error during submission: {}", e); - std::process::exit(1); - } - }; - - let submit_status = json_int(&submit_resp, "status"); - let submit_request = json_str(&submit_resp, "request"); - - if submit_status != 1 { - handle_error(&submit_request); - std::process::exit(1); - } - - let task_id = submit_request; - println!("[+] Task submitted. ID: {}", task_id); - - // Poll for result - println!("[*] Waiting 15s before first poll..."); - thread::sleep(Duration::from_secs(15)); - - let mut elapsed: u64 = 15; - let mut attempt = 0; - let mut backoff = poll_interval; - - let transient = ["ERROR_SERVER_ERROR", "ERROR_INTERNAL_SERVER_ERROR"]; - let solve = ["ERROR_CAPTCHA_UNSOLVABLE"]; - - while elapsed < max_timeout { - attempt += 1; - println!("[*] Polling for result (attempt {})...", attempt); - - let poll_url = format!( - "{}?key={}&action=get&id={}&json=1", - RESULT_URL, - urlencoding::encode(&api_key), - urlencoding::encode(&task_id) - ); - - let result_resp = match ureq::get(&poll_url).call() { - Ok(r) => r.into_string().unwrap_or_default(), - Err(e) => { - println!("[!] Network error during polling: {}", e); - thread::sleep(Duration::from_secs(backoff)); - elapsed += backoff; - backoff = std::cmp::min(backoff * 2, 30); - continue; - } - }; - - let status = json_int(&result_resp, "status"); - let request = json_str(&result_resp, "request"); - - if status == 1 { - let display = if request.len() > 50 { &request[..50] } else { &request }; - println!("[+] Solved! Token: {}...", display); - println!("[+] Full token length: {} characters", request.len()); - println!(); - println!("Next step: inject this token into the target page's"); - println!("h-captcha-response hidden field and submit the form."); - return; - } - - if request == "CAPCHA_NOT_READY" { - println!("[*] Not ready yet, waiting {}s...", poll_interval); - thread::sleep(Duration::from_secs(poll_interval)); - elapsed += poll_interval; - backoff = poll_interval; - continue; - } - - if transient.contains(&request.as_str()) { - println!("[!] Transient error: {}, retrying in {}s...", request, backoff); - thread::sleep(Duration::from_secs(backoff)); - elapsed += backoff; - backoff = std::cmp::min(backoff * 2, 30); - continue; - } - - if solve.contains(&request.as_str()) { - println!("[!] Solve error: {}", request); - println!(" The CAPTCHA could not be solved. Verify parameters and retry."); - std::process::exit(1); - } - - println!("[!] Unexpected error: {}", request); - std::process::exit(1); - } - - println!("[!] Timeout: no solution received within {} seconds.", max_timeout); - std::process::exit(1); -}