Skip to content

Commit 4ceb8e9

Browse files
committed
Refactor code structure for improved readability and maintainability
1 parent ac8e82c commit 4ceb8e9

1,281 files changed

Lines changed: 74022 additions & 26 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

README.md

Lines changed: 282 additions & 26 deletions
Large diffs are not rendered by default.
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# CaptchaAI API credentials
2+
# Get your API key from https://captchaai.com/dashboard
3+
CAPTCHAAI_API_KEY=YOUR_API_KEY
4+
5+
# Target page configuration
6+
CAPTCHA_SITEKEY=YOUR_SITE_KEY
7+
CAPTCHA_PAGEURL=https://example.com/login
8+
9+
# Polling configuration (optional)
10+
POLL_INTERVAL=5
11+
MAX_TIMEOUT=120
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
.env
2+
__pycache__/
3+
*.pyc
4+
node_modules/
5+
vendor/
6+
composer.lock
7+
package-lock.json
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
# App Store Review Monitoring With CAPTCHA Handling
2+
3+
Full working example for solving reCAPTCHA v2 using the CaptchaAI API.
4+
5+
**Languages:** Python
6+
7+
## Related article
8+
9+
This example accompanies the blog article:
10+
**Pending publication**
11+
12+
## Prerequisites
13+
14+
- A CaptchaAI account with API key ([get one here](https://captchaai.com))
15+
- A target page with reCAPTCHA v2 for testing
16+
- Python installed on your system
17+
18+
## Setup
19+
20+
1. Clone the repository:
21+
```bash
22+
git clone https://github.com/CaptchaAI/CaptchaAI-Examples.git
23+
cd CaptchaAI-Examples/articles/app-store-review-monitoring-captcha-handling
24+
```
25+
26+
2. Copy the environment file and add your credentials:
27+
```bash
28+
cp .env.example .env
29+
```
30+
31+
3. Edit `.env` with your API key and target page details.
32+
33+
4. Follow the language-specific setup below.
34+
35+
### Python
36+
37+
```bash
38+
cd python
39+
pip install -r requirements.txt
40+
cp ../.env.example ../.env
41+
# Edit ../.env with your API key and target page details
42+
python solve.py
43+
```
44+
45+
## Configuration
46+
47+
| Variable | Description | Required |
48+
|----------|-------------|----------|
49+
| `CAPTCHAAI_API_KEY` | Your CaptchaAI API key | Yes |
50+
| `CAPTCHA_SITEKEY` | googlekey from the target page | Yes |
51+
| `CAPTCHA_PAGEURL` | pageurl from the target page | Yes |
52+
| `POLL_INTERVAL` | Seconds between poll requests (default: 5) | No |
53+
| `MAX_TIMEOUT` | Maximum seconds to wait for solution (default: 120) | No |
54+
55+
## How it works
56+
57+
1. **Submit** — Sends the CAPTCHA parameters to `https://ocr.captchaai.com/in.php` using method `userrecaptcha`
58+
2. **Wait** — Pauses 15-20 seconds for initial processing
59+
3. **Poll** — Checks `https://ocr.captchaai.com/res.php` every 5 seconds for the result
60+
4. **Result** — Returns the solved token ready for injection
61+
62+
## Expected output
63+
64+
```
65+
[*] Submitting reCAPTCHA v2 task...
66+
[+] Task submitted. ID: 71234567
67+
[*] Waiting 15s before first poll...
68+
[*] Polling for result (attempt 1)...
69+
[*] Not ready yet, waiting 5s...
70+
[*] Polling for result (attempt 2)...
71+
[+] Solved! Token: 03AHJ_Vuve5Asa4koK3KSMyUkCq...
72+
[+] Full token length: 280 characters
73+
```
74+
75+
## Common errors
76+
77+
| Error | Cause | Fix |
78+
|-------|-------|-----|
79+
| `ERROR_WRONG_USER_KEY` | API key is invalid or wrong format | Check your key at https://captchaai.com/dashboard |
80+
| `ERROR_KEY_DOES_NOT_EXIST` | API key not found | Verify the key exists in your dashboard |
81+
| `ERROR_ZERO_BALANCE` | No balance remaining | Top up your account balance |
82+
| `ERROR_CAPTCHA_UNSOLVABLE` | CAPTCHA could not be solved | Verify sitekey and page URL are correct |
83+
| `CAPCHA_NOT_READY` | Solution still processing | This is normal — keep polling |
84+
| `ERROR_BAD_TOKEN_OR_PAGEURL` | Wrong sitekey + URL combination | Extract the correct sitekey from the target page |
85+
86+
## Troubleshooting
87+
88+
**Script exits immediately with auth error**
89+
- Verify your API key is exactly 32 characters
90+
- Make sure `.env` file is in the `articles/app-store-review-monitoring-captcha-handling/` directory (not inside a language folder)
91+
92+
**Polling times out after 120 seconds**
93+
- The CAPTCHA may be unusually complex — try increasing `MAX_TIMEOUT`
94+
- Check that the sitekey and page URL are correct for the target page
95+
- Verify your account has sufficient balance
96+
97+
**Token received but form submission fails**
98+
- The token may have expired (tokens are valid for ~120 seconds)
99+
- Make sure you are injecting the token into the correct form field (see the injection message printed by the script)
100+
- Some sites require additional cookies or headers
101+
102+
## API documentation
103+
104+
- [CaptchaAI API Docs](https://captchaai.com/api-docs)
105+
- [Error Codes Reference](https://captchaai.com/api-docs)
106+
107+
## Related examples
108+
109+
Browse more examples in the [CaptchaAI-Examples repository](https://github.com/CaptchaAI/CaptchaAI-Examples).
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
requests>=2.28.0
2+
python-dotenv>=1.0.0
Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
"""Solve reCAPTCHA v2 using the CaptchaAI API.
2+
3+
Usage:
4+
pip install -r requirements.txt
5+
cp ../.env.example ../.env # then edit with your credentials
6+
python solve.py
7+
"""
8+
9+
import os
10+
import sys
11+
import time
12+
13+
import requests
14+
from dotenv import load_dotenv
15+
16+
# Load environment variables from the parent .env file
17+
load_dotenv(dotenv_path=os.path.join(os.path.dirname(__file__), "..", ".env"))
18+
19+
SUBMIT_URL = "https://ocr.captchaai.com/in.php"
20+
RESULT_URL = "https://ocr.captchaai.com/res.php"
21+
22+
API_KEY = os.getenv("CAPTCHAAI_API_KEY", "")
23+
CAPTCHA_SITEKEY = os.getenv("CAPTCHA_SITEKEY", "")
24+
CAPTCHA_PAGEURL = os.getenv("CAPTCHA_PAGEURL", "")
25+
POLL_INTERVAL = int(os.getenv("POLL_INTERVAL", "5"))
26+
MAX_TIMEOUT = int(os.getenv("MAX_TIMEOUT", "120"))
27+
28+
# --- Error categories ---
29+
AUTH_ERRORS = {"ERROR_WRONG_USER_KEY", "ERROR_KEY_DOES_NOT_EXIST", "IP_BANNED"}
30+
BALANCE_ERRORS = {"ERROR_ZERO_BALANCE"}
31+
INPUT_ERRORS = {"ERROR_PAGEURL", "ERROR_WRONG_GOOGLEKEY", "ERROR_BAD_PARAMETERS", "ERROR_BAD_TOKEN_OR_PAGEURL"}
32+
TRANSIENT_ERRORS = {"ERROR_SERVER_ERROR", "ERROR_INTERNAL_SERVER_ERROR"}
33+
SOLVE_ERRORS = {"ERROR_CAPTCHA_UNSOLVABLE"}
34+
PROXY_ERRORS = {"ERROR_BAD_PROXY", "ERROR_PROXY_CONNECTION_FAILED"}
35+
36+
37+
def validate_config() -> None:
38+
"""Check that required environment variables are set."""
39+
if not API_KEY or API_KEY == "YOUR_API_KEY":
40+
print("[!] ERROR: CAPTCHAAI_API_KEY is not set.")
41+
print(" Copy .env.example to .env and add your real API key.")
42+
sys.exit(1)
43+
44+
45+
def submit_task() -> str:
46+
"""Submit the CAPTCHA task and return the task ID."""
47+
print("[*] Submitting reCAPTCHA v2 task...")
48+
payload = {
49+
"key": API_KEY,
50+
"method": "userrecaptcha",
51+
"googlekey": CAPTCHA_SITEKEY,
52+
"pageurl": CAPTCHA_PAGEURL,
53+
"json": "1",
54+
}
55+
56+
try:
57+
resp = requests.get(SUBMIT_URL, params=payload, timeout=30)
58+
resp.raise_for_status()
59+
except requests.RequestException as exc:
60+
print(f"[!] Network error during submission: {exc}")
61+
sys.exit(1)
62+
63+
data = resp.json()
64+
65+
if data.get("status") != 1:
66+
error = data.get("request", "UNKNOWN_ERROR")
67+
if error in AUTH_ERRORS:
68+
print(f"[!] Authentication error: {error}")
69+
print(" Check your API key at https://captchaai.com/dashboard")
70+
elif error in BALANCE_ERRORS:
71+
print(f"[!] Balance error: {error}")
72+
print(" Top up your account at https://captchaai.com")
73+
elif error in INPUT_ERRORS:
74+
print(f"[!] Input error: {error}")
75+
print(" Verify your sitekey and page URL are correct.")
76+
else:
77+
print(f"[!] Submission failed: {error}")
78+
sys.exit(1)
79+
80+
task_id = data["request"]
81+
print(f"[+] Task submitted. ID: {task_id}")
82+
return task_id
83+
84+
85+
def poll_result(task_id: str) -> str:
86+
"""Poll for the CAPTCHA solution with timeout and retry logic."""
87+
print("[*] Waiting 15s before first poll...")
88+
time.sleep(15)
89+
90+
params = {
91+
"key": API_KEY,
92+
"action": "get",
93+
"id": task_id,
94+
"json": "1",
95+
}
96+
97+
elapsed = 15
98+
attempt = 0
99+
backoff = POLL_INTERVAL
100+
101+
while elapsed < MAX_TIMEOUT:
102+
attempt += 1
103+
print(f"[*] Polling for result (attempt {attempt})...")
104+
105+
try:
106+
resp = requests.get(RESULT_URL, params=params, timeout=30)
107+
resp.raise_for_status()
108+
except requests.RequestException as exc:
109+
print(f"[!] Network error during polling: {exc}")
110+
time.sleep(backoff)
111+
elapsed += backoff
112+
backoff = min(backoff * 2, 30)
113+
continue
114+
115+
data = resp.json()
116+
117+
if data.get("status") == 1:
118+
return data["request"]
119+
120+
error = data.get("request", "")
121+
if error == "CAPCHA_NOT_READY":
122+
print(f"[*] Not ready yet, waiting {POLL_INTERVAL}s...")
123+
time.sleep(POLL_INTERVAL)
124+
elapsed += POLL_INTERVAL
125+
backoff = POLL_INTERVAL # reset backoff on normal response
126+
continue
127+
128+
if error in TRANSIENT_ERRORS:
129+
print(f"[!] Transient error: {error}, retrying in {backoff}s...")
130+
time.sleep(backoff)
131+
elapsed += backoff
132+
backoff = min(backoff * 2, 30)
133+
continue
134+
135+
if error in SOLVE_ERRORS:
136+
print(f"[!] Solve error: {error}")
137+
print(" The CAPTCHA could not be solved. Verify parameters and retry.")
138+
sys.exit(1)
139+
140+
print(f"[!] Unexpected error: {error}")
141+
sys.exit(1)
142+
143+
print(f"[!] Timeout: no solution received within {MAX_TIMEOUT} seconds.")
144+
sys.exit(1)
145+
146+
147+
def main() -> None:
148+
validate_config()
149+
task_id = submit_task()
150+
token = poll_result(task_id)
151+
print(f"[+] Solved! Token: {token[:50]}...")
152+
print(f"[+] Full token length: {len(token)} characters")
153+
print()
154+
print("Next step: inject this token into the target page\'s")
155+
print(f"g-recaptcha-response hidden field and submit the form.")
156+
157+
158+
if __name__ == "__main__":
159+
main()
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# CaptchaAI API credentials
2+
# Get your API key from https://captchaai.com/dashboard
3+
CAPTCHAAI_API_KEY=YOUR_API_KEY
4+
5+
# Target page configuration
6+
CAPTCHA_SITEKEY=YOUR_SITE_KEY
7+
CAPTCHA_PAGEURL=https://example.com/login
8+
9+
# Polling configuration (optional)
10+
POLL_INTERVAL=5
11+
MAX_TIMEOUT=120
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
.env
2+
__pycache__/
3+
*.pyc
4+
node_modules/
5+
vendor/
6+
composer.lock
7+
package-lock.json

0 commit comments

Comments
 (0)