captcha-solver-api 1.0.0__tar.gz → 1.0.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {captcha_solver_api-1.0.0 → captcha_solver_api-1.0.1}/PKG-INFO +34 -21
- {captcha_solver_api-1.0.0 → captcha_solver_api-1.0.1}/README.md +33 -20
- captcha_solver_api-1.0.1/captcha_solver_api/_version.py +1 -0
- {captcha_solver_api-1.0.0 → captcha_solver_api-1.0.1}/captcha_solver_api/async_client.py +12 -7
- {captcha_solver_api-1.0.0 → captcha_solver_api-1.0.1}/captcha_solver_api/client.py +12 -7
- {captcha_solver_api-1.0.0 → captcha_solver_api-1.0.1}/captcha_solver_api.egg-info/PKG-INFO +34 -21
- {captcha_solver_api-1.0.0 → captcha_solver_api-1.0.1}/captcha_solver_api.egg-info/SOURCES.txt +2 -1
- captcha_solver_api-1.0.1/tests/test_polling.py +89 -0
- captcha_solver_api-1.0.0/captcha_solver_api/_version.py +0 -1
- {captcha_solver_api-1.0.0 → captcha_solver_api-1.0.1}/LICENSE.md +0 -0
- {captcha_solver_api-1.0.0 → captcha_solver_api-1.0.1}/captcha_solver_api/__init__.py +0 -0
- {captcha_solver_api-1.0.0 → captcha_solver_api-1.0.1}/captcha_solver_api/exceptions.py +0 -0
- {captcha_solver_api-1.0.0 → captcha_solver_api-1.0.1}/captcha_solver_api/py.typed +0 -0
- {captcha_solver_api-1.0.0 → captcha_solver_api-1.0.1}/captcha_solver_api/tasks.py +0 -0
- {captcha_solver_api-1.0.0 → captcha_solver_api-1.0.1}/captcha_solver_api.egg-info/dependency_links.txt +0 -0
- {captcha_solver_api-1.0.0 → captcha_solver_api-1.0.1}/captcha_solver_api.egg-info/requires.txt +0 -0
- {captcha_solver_api-1.0.0 → captcha_solver_api-1.0.1}/captcha_solver_api.egg-info/top_level.txt +0 -0
- {captcha_solver_api-1.0.0 → captcha_solver_api-1.0.1}/pyproject.toml +0 -0
- {captcha_solver_api-1.0.0 → captcha_solver_api-1.0.1}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: captcha-solver-api
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.1
|
|
4
4
|
Summary: Official Python SDK for solving reCAPTCHA v2/v3, Cloudflare Turnstile, GeeTest v3/v4, Yandex SmartCaptcha, Tencent, and image/click captchas via the Captcha Solver API
|
|
5
5
|
Author: Captcha Solver Team
|
|
6
6
|
License-Expression: MIT
|
|
@@ -110,7 +110,7 @@ client = CaptchaClient("your_api_key")
|
|
|
110
110
|
|
|
111
111
|
## Quick Start
|
|
112
112
|
|
|
113
|
-
Solve a reCAPTCHA v2
|
|
113
|
+
Solve a reCAPTCHA v2 with a task object and one `solve()` call.
|
|
114
114
|
|
|
115
115
|
```python
|
|
116
116
|
from captcha_solver_api import CaptchaClient
|
|
@@ -156,8 +156,8 @@ Constructor.
|
|
|
156
156
|
|---|---|---|---|
|
|
157
157
|
| `client_key` | `str` | required | Your Captcha Solver API key. Raises `ValidationError` if empty. |
|
|
158
158
|
| `base_url` | `str` | `https://api.captcha-solver.com` | API base URL. Override only for self-hosted/staging deployments. |
|
|
159
|
-
| `timeout` | `int` | `120` |
|
|
160
|
-
| `polling_interval` | `int` | `
|
|
159
|
+
| `timeout` | `int` | `120` | Polling window after task creation, in seconds. Overridable per call; each HTTP request has a separate 30-second timeout. |
|
|
160
|
+
| `polling_interval` | `int` | `10` | Seconds before the first `getTaskResult` poll and between subsequent polls, matching the official 2Captcha Python SDK. |
|
|
161
161
|
| `language_pool` | `Optional[str]` | `None` | Default worker pool (`"en"` or `"ru"`) applied to every call that doesn't pass its own `language_pool`. |
|
|
162
162
|
|
|
163
163
|
Both clients hold a reusable connection pool (`requests.Session` / `httpx.AsyncClient`)
|
|
@@ -191,9 +191,9 @@ Raises `ApiError`, `CaptchaTimeoutError`, or `NetworkError`.
|
|
|
191
191
|
### `create_task(task, language_pool=None)`
|
|
192
192
|
|
|
193
193
|
Submits `task` and returns its numeric task ID without waiting for a solution.
|
|
194
|
-
|
|
194
|
+
Accepts `task` and `language_pool`; it does not accept `timeout`. Use this instead of `solve()` if you need to
|
|
195
195
|
manage polling yourself (e.g. checking on many tasks from a different process).
|
|
196
|
-
Raises `ApiError`, `NetworkError`.
|
|
196
|
+
Raises `ApiError`, `CaptchaTimeoutError`, or `NetworkError`.
|
|
197
197
|
|
|
198
198
|
### `get_task_result(task_id)`
|
|
199
199
|
|
|
@@ -201,12 +201,12 @@ Fetches the current status of a task created with `create_task()`. Always
|
|
|
201
201
|
returns a dict with a `status` key (`"processing"` or `"ready"`); when
|
|
202
202
|
`"ready"`, also has a `solution` dict. This is a single poll, not a wait --
|
|
203
203
|
call it repeatedly (as `solve()` does) until `status` is `"ready"`.
|
|
204
|
-
Raises `ApiError`, `NetworkError`.
|
|
204
|
+
Raises `ApiError`, `CaptchaTimeoutError`, or `NetworkError`.
|
|
205
205
|
|
|
206
206
|
### `get_balance()`
|
|
207
207
|
|
|
208
208
|
Returns the account's current balance (`float`) in the account's currency.
|
|
209
|
-
Raises `ApiError`, `NetworkError`.
|
|
209
|
+
Raises `ApiError`, `CaptchaTimeoutError`, or `NetworkError`.
|
|
210
210
|
|
|
211
211
|
## Captcha Types
|
|
212
212
|
|
|
@@ -276,8 +276,10 @@ task = RecaptchaV2Task(
|
|
|
276
276
|
Use this method to solve the Enterprise version of reCAPTCHA v2 and obtain a
|
|
277
277
|
token for a page that uses `grecaptcha.enterprise`.
|
|
278
278
|
|
|
279
|
-
`RecaptchaV2EnterpriseTaskProxyless` / `RecaptchaV2EnterpriseTask
|
|
280
|
-
|
|
279
|
+
`RecaptchaV2EnterpriseTaskProxyless` / `RecaptchaV2EnterpriseTask` accept
|
|
280
|
+
`websiteURL`, `websiteKey`, `isInvisible`, `apiDomain`, `userAgent`, and `cookies`,
|
|
281
|
+
plus `enterprisePayload`. Use `enterprisePayload={"s": "..."}` for the
|
|
282
|
+
Enterprise `s` value; these classes do not accept `recaptchaDataSValue`.
|
|
281
283
|
|
|
282
284
|
| Parameter | Required | Description |
|
|
283
285
|
|---|---|---|
|
|
@@ -307,8 +309,8 @@ With proxy, use `RecaptchaV2EnterpriseTask` (same proxy fields as reCAPTCHA v2).
|
|
|
307
309
|
Use this method to obtain a score-based reCAPTCHA v3 token for a specific site,
|
|
308
310
|
action, and minimum score. This variant does not use a proxy.
|
|
309
311
|
|
|
310
|
-
`RecaptchaV3TaskProxyless`.
|
|
311
|
-
|
|
312
|
+
`RecaptchaV3TaskProxyless`. This API supports v3 through the service's IPs;
|
|
313
|
+
there is no corresponding task type for your own proxy.
|
|
312
314
|
|
|
313
315
|
| Parameter | Required | Description |
|
|
314
316
|
|---|---|---|
|
|
@@ -353,7 +355,10 @@ that the target page expects in `cf-turnstile-response`.
|
|
|
353
355
|
| `pagedata` | no | Value of the `chlPageData` parameter, needed for some Cloudflare challenge pages beyond the basic widget. |
|
|
354
356
|
| `userAgent` | no | User-Agent to solve with -- the returned token is tied to it, submit with the same one. |
|
|
355
357
|
|
|
356
|
-
**Response:** `token` -- submit as `cf-turnstile-response`.
|
|
358
|
+
**Response:** `token` -- submit as `cf-turnstile-response`. For Cloudflare
|
|
359
|
+
Challenge pages, the solution also includes `userAgent`; use that User-Agent
|
|
360
|
+
when submitting the token. Pass `action`, `data`, and `pagedata` when the page
|
|
361
|
+
provides them. The API field is spelled `pagedata`, all lowercase.
|
|
357
362
|
|
|
358
363
|
```python
|
|
359
364
|
from captcha_solver_api import CaptchaClient
|
|
@@ -425,7 +430,7 @@ pass the values collected from the target page before creating the task.
|
|
|
425
430
|
| `version` | no | `3` (default) or `4`. |
|
|
426
431
|
| `gt` | v3 only | Public key of the GeeTest widget. |
|
|
427
432
|
| `challenge` | v3 only | Session-specific challenge value from the page -- must be freshly fetched for every request, it cannot be reused. |
|
|
428
|
-
| `initParameters` |
|
|
433
|
+
| `initParameters` | required for v4; optional for v3 | Extra initialization parameters; for v4 must contain `captcha_id`. |
|
|
429
434
|
| `geetestApiServerSubdomain` | no | Custom GeeTest API subdomain, if the site uses one. |
|
|
430
435
|
| `userAgent` | no | User-Agent to solve with. |
|
|
431
436
|
| `risk_type` | no | Value of the `risk_type` parameter from the captcha-loading request, if present. Dynamic, single-use, and time-limited. |
|
|
@@ -598,6 +603,14 @@ it for every other call:
|
|
|
598
603
|
result = client.solve(task, timeout=300)
|
|
599
604
|
```
|
|
600
605
|
|
|
606
|
+
The [API requires at least 5 seconds between polls](https://captcha-solver.com/en/docs/how-it-works).
|
|
607
|
+
The SDK defaults to 10 seconds, like the official 2Captcha Python SDK. `solve()`
|
|
608
|
+
waits for `polling_interval` before its first poll and between polls.
|
|
609
|
+
Its default 120-second polling window is independent of the API's five-minute
|
|
610
|
+
task lifetime. A local timeout does not cancel a task or mean that the API
|
|
611
|
+
failed to solve it. Use `create_task()` and keep its `task_id` if you need to
|
|
612
|
+
check the same task later; calling `solve()` again creates a new task.
|
|
613
|
+
|
|
601
614
|
### Worker language pool
|
|
602
615
|
|
|
603
616
|
Set a default `language_pool` once at construction instead of passing it to every call:
|
|
@@ -683,9 +696,10 @@ See the dedicated [examples documentation](https://github.com/captcha-solver-api
|
|
|
683
696
|
sync/async example list, setup steps, expected results, and placeholder guidance.
|
|
684
697
|
|
|
685
698
|
- **Image/click captchas** (`image_to_text.py`, `coordinates.py`,
|
|
686
|
-
`yandex_smartcaptcha_image.py`) run
|
|
699
|
+
`yandex_smartcaptcha_image.py`) run after installing the dependencies and setting a valid
|
|
687
700
|
`CAPTCHA_API_KEY` -- they read sample images bundled in
|
|
688
701
|
[examples/assets](https://github.com/captcha-solver-api/python-sdk/tree/main/examples/assets), no target page needed.
|
|
702
|
+
`python-dotenv` is optional: install it only if you want the scripts to load a `.env` file.
|
|
689
703
|
- **Token captchas** (`recaptcha_v2.py`, `recaptcha_v2_enterprise.py`, `recaptcha_v3.py`,
|
|
690
704
|
`turnstile.py`, `yandex_smartcaptcha.py`, `geetest_v4.py`, `tencent.py`) use
|
|
691
705
|
placeholder values (`https://example.com/...`, `YOUR_WEBSITE_KEY`, `YOUR_APP_ID`,
|
|
@@ -709,12 +723,11 @@ python examples/sync/image_to_text.py
|
|
|
709
723
|
python examples/sync/coordinates.py
|
|
710
724
|
```
|
|
711
725
|
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
solution
|
|
716
|
-
|
|
717
|
-
pair.
|
|
726
|
+
Live checks with real parameters have exercised all supported task types.
|
|
727
|
+
Individual tasks may return `ERROR_CAPTCHA_UNSOLVABLE` or exceed the client's
|
|
728
|
+
polling timeout. A `ready` response confirms that the service returned a
|
|
729
|
+
solution; the target website must still accept the token with the matching
|
|
730
|
+
page and session parameters.
|
|
718
731
|
|
|
719
732
|
## Requirements
|
|
720
733
|
|
|
@@ -74,7 +74,7 @@ client = CaptchaClient("your_api_key")
|
|
|
74
74
|
|
|
75
75
|
## Quick Start
|
|
76
76
|
|
|
77
|
-
Solve a reCAPTCHA v2
|
|
77
|
+
Solve a reCAPTCHA v2 with a task object and one `solve()` call.
|
|
78
78
|
|
|
79
79
|
```python
|
|
80
80
|
from captcha_solver_api import CaptchaClient
|
|
@@ -120,8 +120,8 @@ Constructor.
|
|
|
120
120
|
|---|---|---|---|
|
|
121
121
|
| `client_key` | `str` | required | Your Captcha Solver API key. Raises `ValidationError` if empty. |
|
|
122
122
|
| `base_url` | `str` | `https://api.captcha-solver.com` | API base URL. Override only for self-hosted/staging deployments. |
|
|
123
|
-
| `timeout` | `int` | `120` |
|
|
124
|
-
| `polling_interval` | `int` | `
|
|
123
|
+
| `timeout` | `int` | `120` | Polling window after task creation, in seconds. Overridable per call; each HTTP request has a separate 30-second timeout. |
|
|
124
|
+
| `polling_interval` | `int` | `10` | Seconds before the first `getTaskResult` poll and between subsequent polls, matching the official 2Captcha Python SDK. |
|
|
125
125
|
| `language_pool` | `Optional[str]` | `None` | Default worker pool (`"en"` or `"ru"`) applied to every call that doesn't pass its own `language_pool`. |
|
|
126
126
|
|
|
127
127
|
Both clients hold a reusable connection pool (`requests.Session` / `httpx.AsyncClient`)
|
|
@@ -155,9 +155,9 @@ Raises `ApiError`, `CaptchaTimeoutError`, or `NetworkError`.
|
|
|
155
155
|
### `create_task(task, language_pool=None)`
|
|
156
156
|
|
|
157
157
|
Submits `task` and returns its numeric task ID without waiting for a solution.
|
|
158
|
-
|
|
158
|
+
Accepts `task` and `language_pool`; it does not accept `timeout`. Use this instead of `solve()` if you need to
|
|
159
159
|
manage polling yourself (e.g. checking on many tasks from a different process).
|
|
160
|
-
Raises `ApiError`, `NetworkError`.
|
|
160
|
+
Raises `ApiError`, `CaptchaTimeoutError`, or `NetworkError`.
|
|
161
161
|
|
|
162
162
|
### `get_task_result(task_id)`
|
|
163
163
|
|
|
@@ -165,12 +165,12 @@ Fetches the current status of a task created with `create_task()`. Always
|
|
|
165
165
|
returns a dict with a `status` key (`"processing"` or `"ready"`); when
|
|
166
166
|
`"ready"`, also has a `solution` dict. This is a single poll, not a wait --
|
|
167
167
|
call it repeatedly (as `solve()` does) until `status` is `"ready"`.
|
|
168
|
-
Raises `ApiError`, `NetworkError`.
|
|
168
|
+
Raises `ApiError`, `CaptchaTimeoutError`, or `NetworkError`.
|
|
169
169
|
|
|
170
170
|
### `get_balance()`
|
|
171
171
|
|
|
172
172
|
Returns the account's current balance (`float`) in the account's currency.
|
|
173
|
-
Raises `ApiError`, `NetworkError`.
|
|
173
|
+
Raises `ApiError`, `CaptchaTimeoutError`, or `NetworkError`.
|
|
174
174
|
|
|
175
175
|
## Captcha Types
|
|
176
176
|
|
|
@@ -240,8 +240,10 @@ task = RecaptchaV2Task(
|
|
|
240
240
|
Use this method to solve the Enterprise version of reCAPTCHA v2 and obtain a
|
|
241
241
|
token for a page that uses `grecaptcha.enterprise`.
|
|
242
242
|
|
|
243
|
-
`RecaptchaV2EnterpriseTaskProxyless` / `RecaptchaV2EnterpriseTask
|
|
244
|
-
|
|
243
|
+
`RecaptchaV2EnterpriseTaskProxyless` / `RecaptchaV2EnterpriseTask` accept
|
|
244
|
+
`websiteURL`, `websiteKey`, `isInvisible`, `apiDomain`, `userAgent`, and `cookies`,
|
|
245
|
+
plus `enterprisePayload`. Use `enterprisePayload={"s": "..."}` for the
|
|
246
|
+
Enterprise `s` value; these classes do not accept `recaptchaDataSValue`.
|
|
245
247
|
|
|
246
248
|
| Parameter | Required | Description |
|
|
247
249
|
|---|---|---|
|
|
@@ -271,8 +273,8 @@ With proxy, use `RecaptchaV2EnterpriseTask` (same proxy fields as reCAPTCHA v2).
|
|
|
271
273
|
Use this method to obtain a score-based reCAPTCHA v3 token for a specific site,
|
|
272
274
|
action, and minimum score. This variant does not use a proxy.
|
|
273
275
|
|
|
274
|
-
`RecaptchaV3TaskProxyless`.
|
|
275
|
-
|
|
276
|
+
`RecaptchaV3TaskProxyless`. This API supports v3 through the service's IPs;
|
|
277
|
+
there is no corresponding task type for your own proxy.
|
|
276
278
|
|
|
277
279
|
| Parameter | Required | Description |
|
|
278
280
|
|---|---|---|
|
|
@@ -317,7 +319,10 @@ that the target page expects in `cf-turnstile-response`.
|
|
|
317
319
|
| `pagedata` | no | Value of the `chlPageData` parameter, needed for some Cloudflare challenge pages beyond the basic widget. |
|
|
318
320
|
| `userAgent` | no | User-Agent to solve with -- the returned token is tied to it, submit with the same one. |
|
|
319
321
|
|
|
320
|
-
**Response:** `token` -- submit as `cf-turnstile-response`.
|
|
322
|
+
**Response:** `token` -- submit as `cf-turnstile-response`. For Cloudflare
|
|
323
|
+
Challenge pages, the solution also includes `userAgent`; use that User-Agent
|
|
324
|
+
when submitting the token. Pass `action`, `data`, and `pagedata` when the page
|
|
325
|
+
provides them. The API field is spelled `pagedata`, all lowercase.
|
|
321
326
|
|
|
322
327
|
```python
|
|
323
328
|
from captcha_solver_api import CaptchaClient
|
|
@@ -389,7 +394,7 @@ pass the values collected from the target page before creating the task.
|
|
|
389
394
|
| `version` | no | `3` (default) or `4`. |
|
|
390
395
|
| `gt` | v3 only | Public key of the GeeTest widget. |
|
|
391
396
|
| `challenge` | v3 only | Session-specific challenge value from the page -- must be freshly fetched for every request, it cannot be reused. |
|
|
392
|
-
| `initParameters` |
|
|
397
|
+
| `initParameters` | required for v4; optional for v3 | Extra initialization parameters; for v4 must contain `captcha_id`. |
|
|
393
398
|
| `geetestApiServerSubdomain` | no | Custom GeeTest API subdomain, if the site uses one. |
|
|
394
399
|
| `userAgent` | no | User-Agent to solve with. |
|
|
395
400
|
| `risk_type` | no | Value of the `risk_type` parameter from the captcha-loading request, if present. Dynamic, single-use, and time-limited. |
|
|
@@ -562,6 +567,14 @@ it for every other call:
|
|
|
562
567
|
result = client.solve(task, timeout=300)
|
|
563
568
|
```
|
|
564
569
|
|
|
570
|
+
The [API requires at least 5 seconds between polls](https://captcha-solver.com/en/docs/how-it-works).
|
|
571
|
+
The SDK defaults to 10 seconds, like the official 2Captcha Python SDK. `solve()`
|
|
572
|
+
waits for `polling_interval` before its first poll and between polls.
|
|
573
|
+
Its default 120-second polling window is independent of the API's five-minute
|
|
574
|
+
task lifetime. A local timeout does not cancel a task or mean that the API
|
|
575
|
+
failed to solve it. Use `create_task()` and keep its `task_id` if you need to
|
|
576
|
+
check the same task later; calling `solve()` again creates a new task.
|
|
577
|
+
|
|
565
578
|
### Worker language pool
|
|
566
579
|
|
|
567
580
|
Set a default `language_pool` once at construction instead of passing it to every call:
|
|
@@ -647,9 +660,10 @@ See the dedicated [examples documentation](https://github.com/captcha-solver-api
|
|
|
647
660
|
sync/async example list, setup steps, expected results, and placeholder guidance.
|
|
648
661
|
|
|
649
662
|
- **Image/click captchas** (`image_to_text.py`, `coordinates.py`,
|
|
650
|
-
`yandex_smartcaptcha_image.py`) run
|
|
663
|
+
`yandex_smartcaptcha_image.py`) run after installing the dependencies and setting a valid
|
|
651
664
|
`CAPTCHA_API_KEY` -- they read sample images bundled in
|
|
652
665
|
[examples/assets](https://github.com/captcha-solver-api/python-sdk/tree/main/examples/assets), no target page needed.
|
|
666
|
+
`python-dotenv` is optional: install it only if you want the scripts to load a `.env` file.
|
|
653
667
|
- **Token captchas** (`recaptcha_v2.py`, `recaptcha_v2_enterprise.py`, `recaptcha_v3.py`,
|
|
654
668
|
`turnstile.py`, `yandex_smartcaptcha.py`, `geetest_v4.py`, `tencent.py`) use
|
|
655
669
|
placeholder values (`https://example.com/...`, `YOUR_WEBSITE_KEY`, `YOUR_APP_ID`,
|
|
@@ -673,12 +687,11 @@ python examples/sync/image_to_text.py
|
|
|
673
687
|
python examples/sync/coordinates.py
|
|
674
688
|
```
|
|
675
689
|
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
solution
|
|
680
|
-
|
|
681
|
-
pair.
|
|
690
|
+
Live checks with real parameters have exercised all supported task types.
|
|
691
|
+
Individual tasks may return `ERROR_CAPTCHA_UNSOLVABLE` or exceed the client's
|
|
692
|
+
polling timeout. A `ready` response confirms that the service returned a
|
|
693
|
+
solution; the target website must still accept the token with the matching
|
|
694
|
+
page and session parameters.
|
|
682
695
|
|
|
683
696
|
## Requirements
|
|
684
697
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "1.0.1"
|
|
@@ -42,7 +42,7 @@ class AsyncCaptchaClient:
|
|
|
42
42
|
client_key: str,
|
|
43
43
|
base_url: str = "https://api.captcha-solver.com",
|
|
44
44
|
timeout: int = 120,
|
|
45
|
-
polling_interval: int =
|
|
45
|
+
polling_interval: int = 10,
|
|
46
46
|
language_pool: Optional[str] = None,
|
|
47
47
|
) -> None:
|
|
48
48
|
"""
|
|
@@ -52,8 +52,9 @@ class AsyncCaptchaClient:
|
|
|
52
52
|
deployments.
|
|
53
53
|
timeout: Default max seconds `solve()` waits for a solution before
|
|
54
54
|
raising `CaptchaTimeoutError`. Can be overridden per call.
|
|
55
|
-
polling_interval: Seconds to wait
|
|
56
|
-
inside `solve()`.
|
|
55
|
+
polling_interval: Seconds to wait before the first `getTaskResult`
|
|
56
|
+
poll and between subsequent polls inside `solve()`. Defaults
|
|
57
|
+
to 10 seconds, matching the official 2Captcha Python SDK.
|
|
57
58
|
language_pool: Default worker pool selector (e.g. `"en"` or `"ru"`)
|
|
58
59
|
applied to every `create_task()`/`solve()` call that doesn't pass
|
|
59
60
|
its own `language_pool`. Leave unset to use the account's default
|
|
@@ -174,6 +175,7 @@ class AsyncCaptchaClient:
|
|
|
174
175
|
Raises:
|
|
175
176
|
ApiError: The API reports an error for the task.
|
|
176
177
|
NetworkError: The request failed at the transport level.
|
|
178
|
+
CaptchaTimeoutError: The HTTP request timed out.
|
|
177
179
|
"""
|
|
178
180
|
payload = {
|
|
179
181
|
"clientKey": self.client_key,
|
|
@@ -196,6 +198,7 @@ class AsyncCaptchaClient:
|
|
|
196
198
|
Raises:
|
|
197
199
|
ApiError: The API key is invalid or the account cannot be resolved.
|
|
198
200
|
NetworkError: The request failed at the transport level.
|
|
201
|
+
CaptchaTimeoutError: The HTTP request timed out.
|
|
199
202
|
"""
|
|
200
203
|
payload = {"clientKey": self.client_key}
|
|
201
204
|
data = await self._request("getBalance", payload)
|
|
@@ -235,14 +238,16 @@ class AsyncCaptchaClient:
|
|
|
235
238
|
|
|
236
239
|
task_id = await self.create_task(task, language_pool=language_pool)
|
|
237
240
|
|
|
238
|
-
deadline = time.
|
|
241
|
+
deadline = time.monotonic() + (timeout if timeout is not None else self.timeout)
|
|
239
242
|
|
|
240
|
-
while time.
|
|
243
|
+
while time.monotonic() < deadline:
|
|
244
|
+
remaining = deadline - time.monotonic()
|
|
245
|
+
await asyncio.sleep(min(self.polling_interval, max(0, remaining)))
|
|
246
|
+
if time.monotonic() >= deadline:
|
|
247
|
+
break
|
|
241
248
|
result = await self.get_task_result(task_id)
|
|
242
249
|
|
|
243
250
|
if result.get("status") == "ready":
|
|
244
251
|
return result["solution"]
|
|
245
252
|
|
|
246
|
-
await asyncio.sleep(self.polling_interval)
|
|
247
|
-
|
|
248
253
|
raise CaptchaTimeoutError("Task solving timed out.")
|
|
@@ -31,7 +31,7 @@ class CaptchaClient:
|
|
|
31
31
|
client_key: str,
|
|
32
32
|
base_url: str = "https://api.captcha-solver.com",
|
|
33
33
|
timeout: int = 120,
|
|
34
|
-
polling_interval: int =
|
|
34
|
+
polling_interval: int = 10,
|
|
35
35
|
language_pool: Optional[str] = None,
|
|
36
36
|
) -> None:
|
|
37
37
|
"""
|
|
@@ -41,8 +41,9 @@ class CaptchaClient:
|
|
|
41
41
|
deployments.
|
|
42
42
|
timeout: Default max seconds `solve()` waits for a solution before
|
|
43
43
|
raising `CaptchaTimeoutError`. Can be overridden per call.
|
|
44
|
-
polling_interval: Seconds to wait
|
|
45
|
-
inside `solve()`.
|
|
44
|
+
polling_interval: Seconds to wait before the first `getTaskResult`
|
|
45
|
+
poll and between subsequent polls inside `solve()`. Defaults
|
|
46
|
+
to 10 seconds, matching the official 2Captcha Python SDK.
|
|
46
47
|
language_pool: Default worker pool selector (e.g. `"en"` or `"ru"`)
|
|
47
48
|
applied to every `create_task()`/`solve()` call that doesn't pass
|
|
48
49
|
its own `language_pool`. Leave unset to use the account's default
|
|
@@ -160,6 +161,7 @@ class CaptchaClient:
|
|
|
160
161
|
Raises:
|
|
161
162
|
ApiError: The API reports an error for this task (e.g. it expired).
|
|
162
163
|
NetworkError: The request failed at the transport level.
|
|
164
|
+
CaptchaTimeoutError: The HTTP request timed out.
|
|
163
165
|
"""
|
|
164
166
|
payload = {
|
|
165
167
|
"clientKey": self.client_key,
|
|
@@ -180,6 +182,7 @@ class CaptchaClient:
|
|
|
180
182
|
Raises:
|
|
181
183
|
ApiError: The API key is invalid or the account can't be resolved.
|
|
182
184
|
NetworkError: The request failed at the transport level.
|
|
185
|
+
CaptchaTimeoutError: The HTTP request timed out.
|
|
183
186
|
"""
|
|
184
187
|
payload = {"clientKey": self.client_key}
|
|
185
188
|
data = self._request("getBalance", payload)
|
|
@@ -217,14 +220,16 @@ class CaptchaClient:
|
|
|
217
220
|
|
|
218
221
|
task_id = self.create_task(task, language_pool=language_pool)
|
|
219
222
|
|
|
220
|
-
deadline = time.
|
|
223
|
+
deadline = time.monotonic() + (timeout if timeout is not None else self.timeout)
|
|
221
224
|
|
|
222
|
-
while time.
|
|
225
|
+
while time.monotonic() < deadline:
|
|
226
|
+
remaining = deadline - time.monotonic()
|
|
227
|
+
time.sleep(min(self.polling_interval, max(0, remaining)))
|
|
228
|
+
if time.monotonic() >= deadline:
|
|
229
|
+
break
|
|
223
230
|
result = self.get_task_result(task_id)
|
|
224
231
|
|
|
225
232
|
if result.get("status") == "ready":
|
|
226
233
|
return result["solution"]
|
|
227
234
|
|
|
228
|
-
time.sleep(self.polling_interval)
|
|
229
|
-
|
|
230
235
|
raise CaptchaTimeoutError("Task solving timed out.")
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: captcha-solver-api
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.1
|
|
4
4
|
Summary: Official Python SDK for solving reCAPTCHA v2/v3, Cloudflare Turnstile, GeeTest v3/v4, Yandex SmartCaptcha, Tencent, and image/click captchas via the Captcha Solver API
|
|
5
5
|
Author: Captcha Solver Team
|
|
6
6
|
License-Expression: MIT
|
|
@@ -110,7 +110,7 @@ client = CaptchaClient("your_api_key")
|
|
|
110
110
|
|
|
111
111
|
## Quick Start
|
|
112
112
|
|
|
113
|
-
Solve a reCAPTCHA v2
|
|
113
|
+
Solve a reCAPTCHA v2 with a task object and one `solve()` call.
|
|
114
114
|
|
|
115
115
|
```python
|
|
116
116
|
from captcha_solver_api import CaptchaClient
|
|
@@ -156,8 +156,8 @@ Constructor.
|
|
|
156
156
|
|---|---|---|---|
|
|
157
157
|
| `client_key` | `str` | required | Your Captcha Solver API key. Raises `ValidationError` if empty. |
|
|
158
158
|
| `base_url` | `str` | `https://api.captcha-solver.com` | API base URL. Override only for self-hosted/staging deployments. |
|
|
159
|
-
| `timeout` | `int` | `120` |
|
|
160
|
-
| `polling_interval` | `int` | `
|
|
159
|
+
| `timeout` | `int` | `120` | Polling window after task creation, in seconds. Overridable per call; each HTTP request has a separate 30-second timeout. |
|
|
160
|
+
| `polling_interval` | `int` | `10` | Seconds before the first `getTaskResult` poll and between subsequent polls, matching the official 2Captcha Python SDK. |
|
|
161
161
|
| `language_pool` | `Optional[str]` | `None` | Default worker pool (`"en"` or `"ru"`) applied to every call that doesn't pass its own `language_pool`. |
|
|
162
162
|
|
|
163
163
|
Both clients hold a reusable connection pool (`requests.Session` / `httpx.AsyncClient`)
|
|
@@ -191,9 +191,9 @@ Raises `ApiError`, `CaptchaTimeoutError`, or `NetworkError`.
|
|
|
191
191
|
### `create_task(task, language_pool=None)`
|
|
192
192
|
|
|
193
193
|
Submits `task` and returns its numeric task ID without waiting for a solution.
|
|
194
|
-
|
|
194
|
+
Accepts `task` and `language_pool`; it does not accept `timeout`. Use this instead of `solve()` if you need to
|
|
195
195
|
manage polling yourself (e.g. checking on many tasks from a different process).
|
|
196
|
-
Raises `ApiError`, `NetworkError`.
|
|
196
|
+
Raises `ApiError`, `CaptchaTimeoutError`, or `NetworkError`.
|
|
197
197
|
|
|
198
198
|
### `get_task_result(task_id)`
|
|
199
199
|
|
|
@@ -201,12 +201,12 @@ Fetches the current status of a task created with `create_task()`. Always
|
|
|
201
201
|
returns a dict with a `status` key (`"processing"` or `"ready"`); when
|
|
202
202
|
`"ready"`, also has a `solution` dict. This is a single poll, not a wait --
|
|
203
203
|
call it repeatedly (as `solve()` does) until `status` is `"ready"`.
|
|
204
|
-
Raises `ApiError`, `NetworkError`.
|
|
204
|
+
Raises `ApiError`, `CaptchaTimeoutError`, or `NetworkError`.
|
|
205
205
|
|
|
206
206
|
### `get_balance()`
|
|
207
207
|
|
|
208
208
|
Returns the account's current balance (`float`) in the account's currency.
|
|
209
|
-
Raises `ApiError`, `NetworkError`.
|
|
209
|
+
Raises `ApiError`, `CaptchaTimeoutError`, or `NetworkError`.
|
|
210
210
|
|
|
211
211
|
## Captcha Types
|
|
212
212
|
|
|
@@ -276,8 +276,10 @@ task = RecaptchaV2Task(
|
|
|
276
276
|
Use this method to solve the Enterprise version of reCAPTCHA v2 and obtain a
|
|
277
277
|
token for a page that uses `grecaptcha.enterprise`.
|
|
278
278
|
|
|
279
|
-
`RecaptchaV2EnterpriseTaskProxyless` / `RecaptchaV2EnterpriseTask
|
|
280
|
-
|
|
279
|
+
`RecaptchaV2EnterpriseTaskProxyless` / `RecaptchaV2EnterpriseTask` accept
|
|
280
|
+
`websiteURL`, `websiteKey`, `isInvisible`, `apiDomain`, `userAgent`, and `cookies`,
|
|
281
|
+
plus `enterprisePayload`. Use `enterprisePayload={"s": "..."}` for the
|
|
282
|
+
Enterprise `s` value; these classes do not accept `recaptchaDataSValue`.
|
|
281
283
|
|
|
282
284
|
| Parameter | Required | Description |
|
|
283
285
|
|---|---|---|
|
|
@@ -307,8 +309,8 @@ With proxy, use `RecaptchaV2EnterpriseTask` (same proxy fields as reCAPTCHA v2).
|
|
|
307
309
|
Use this method to obtain a score-based reCAPTCHA v3 token for a specific site,
|
|
308
310
|
action, and minimum score. This variant does not use a proxy.
|
|
309
311
|
|
|
310
|
-
`RecaptchaV3TaskProxyless`.
|
|
311
|
-
|
|
312
|
+
`RecaptchaV3TaskProxyless`. This API supports v3 through the service's IPs;
|
|
313
|
+
there is no corresponding task type for your own proxy.
|
|
312
314
|
|
|
313
315
|
| Parameter | Required | Description |
|
|
314
316
|
|---|---|---|
|
|
@@ -353,7 +355,10 @@ that the target page expects in `cf-turnstile-response`.
|
|
|
353
355
|
| `pagedata` | no | Value of the `chlPageData` parameter, needed for some Cloudflare challenge pages beyond the basic widget. |
|
|
354
356
|
| `userAgent` | no | User-Agent to solve with -- the returned token is tied to it, submit with the same one. |
|
|
355
357
|
|
|
356
|
-
**Response:** `token` -- submit as `cf-turnstile-response`.
|
|
358
|
+
**Response:** `token` -- submit as `cf-turnstile-response`. For Cloudflare
|
|
359
|
+
Challenge pages, the solution also includes `userAgent`; use that User-Agent
|
|
360
|
+
when submitting the token. Pass `action`, `data`, and `pagedata` when the page
|
|
361
|
+
provides them. The API field is spelled `pagedata`, all lowercase.
|
|
357
362
|
|
|
358
363
|
```python
|
|
359
364
|
from captcha_solver_api import CaptchaClient
|
|
@@ -425,7 +430,7 @@ pass the values collected from the target page before creating the task.
|
|
|
425
430
|
| `version` | no | `3` (default) or `4`. |
|
|
426
431
|
| `gt` | v3 only | Public key of the GeeTest widget. |
|
|
427
432
|
| `challenge` | v3 only | Session-specific challenge value from the page -- must be freshly fetched for every request, it cannot be reused. |
|
|
428
|
-
| `initParameters` |
|
|
433
|
+
| `initParameters` | required for v4; optional for v3 | Extra initialization parameters; for v4 must contain `captcha_id`. |
|
|
429
434
|
| `geetestApiServerSubdomain` | no | Custom GeeTest API subdomain, if the site uses one. |
|
|
430
435
|
| `userAgent` | no | User-Agent to solve with. |
|
|
431
436
|
| `risk_type` | no | Value of the `risk_type` parameter from the captcha-loading request, if present. Dynamic, single-use, and time-limited. |
|
|
@@ -598,6 +603,14 @@ it for every other call:
|
|
|
598
603
|
result = client.solve(task, timeout=300)
|
|
599
604
|
```
|
|
600
605
|
|
|
606
|
+
The [API requires at least 5 seconds between polls](https://captcha-solver.com/en/docs/how-it-works).
|
|
607
|
+
The SDK defaults to 10 seconds, like the official 2Captcha Python SDK. `solve()`
|
|
608
|
+
waits for `polling_interval` before its first poll and between polls.
|
|
609
|
+
Its default 120-second polling window is independent of the API's five-minute
|
|
610
|
+
task lifetime. A local timeout does not cancel a task or mean that the API
|
|
611
|
+
failed to solve it. Use `create_task()` and keep its `task_id` if you need to
|
|
612
|
+
check the same task later; calling `solve()` again creates a new task.
|
|
613
|
+
|
|
601
614
|
### Worker language pool
|
|
602
615
|
|
|
603
616
|
Set a default `language_pool` once at construction instead of passing it to every call:
|
|
@@ -683,9 +696,10 @@ See the dedicated [examples documentation](https://github.com/captcha-solver-api
|
|
|
683
696
|
sync/async example list, setup steps, expected results, and placeholder guidance.
|
|
684
697
|
|
|
685
698
|
- **Image/click captchas** (`image_to_text.py`, `coordinates.py`,
|
|
686
|
-
`yandex_smartcaptcha_image.py`) run
|
|
699
|
+
`yandex_smartcaptcha_image.py`) run after installing the dependencies and setting a valid
|
|
687
700
|
`CAPTCHA_API_KEY` -- they read sample images bundled in
|
|
688
701
|
[examples/assets](https://github.com/captcha-solver-api/python-sdk/tree/main/examples/assets), no target page needed.
|
|
702
|
+
`python-dotenv` is optional: install it only if you want the scripts to load a `.env` file.
|
|
689
703
|
- **Token captchas** (`recaptcha_v2.py`, `recaptcha_v2_enterprise.py`, `recaptcha_v3.py`,
|
|
690
704
|
`turnstile.py`, `yandex_smartcaptcha.py`, `geetest_v4.py`, `tencent.py`) use
|
|
691
705
|
placeholder values (`https://example.com/...`, `YOUR_WEBSITE_KEY`, `YOUR_APP_ID`,
|
|
@@ -709,12 +723,11 @@ python examples/sync/image_to_text.py
|
|
|
709
723
|
python examples/sync/coordinates.py
|
|
710
724
|
```
|
|
711
725
|
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
solution
|
|
716
|
-
|
|
717
|
-
pair.
|
|
726
|
+
Live checks with real parameters have exercised all supported task types.
|
|
727
|
+
Individual tasks may return `ERROR_CAPTCHA_UNSOLVABLE` or exceed the client's
|
|
728
|
+
polling timeout. A `ready` response confirms that the service returned a
|
|
729
|
+
solution; the target website must still accept the token with the matching
|
|
730
|
+
page and session parameters.
|
|
718
731
|
|
|
719
732
|
## Requirements
|
|
720
733
|
|
{captcha_solver_api-1.0.0 → captcha_solver_api-1.0.1}/captcha_solver_api.egg-info/SOURCES.txt
RENAMED
|
@@ -12,4 +12,5 @@ captcha_solver_api.egg-info/PKG-INFO
|
|
|
12
12
|
captcha_solver_api.egg-info/SOURCES.txt
|
|
13
13
|
captcha_solver_api.egg-info/dependency_links.txt
|
|
14
14
|
captcha_solver_api.egg-info/requires.txt
|
|
15
|
-
captcha_solver_api.egg-info/top_level.txt
|
|
15
|
+
captcha_solver_api.egg-info/top_level.txt
|
|
16
|
+
tests/test_polling.py
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
"""The documented polling schedule applies to both clients, including the first poll."""
|
|
2
|
+
|
|
3
|
+
from types import SimpleNamespace
|
|
4
|
+
from unittest.mock import AsyncMock
|
|
5
|
+
|
|
6
|
+
import pytest
|
|
7
|
+
|
|
8
|
+
import captcha_solver_api.client as sync_module
|
|
9
|
+
import captcha_solver_api.async_client as async_module
|
|
10
|
+
from captcha_solver_api import CaptchaClient, AsyncCaptchaClient, CaptchaTimeoutError
|
|
11
|
+
from captcha_solver_api.tasks import RecaptchaV2TaskProxyless
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class Clock:
|
|
15
|
+
def __init__(self):
|
|
16
|
+
self.now = 0
|
|
17
|
+
|
|
18
|
+
def monotonic(self):
|
|
19
|
+
return self.now
|
|
20
|
+
|
|
21
|
+
def sleep(self, seconds):
|
|
22
|
+
self.now += seconds
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
CASES = [
|
|
26
|
+
(None, 25, [10, 20], False),
|
|
27
|
+
(2, 20, [2, 4], False),
|
|
28
|
+
(None, 3, [], True),
|
|
29
|
+
(5, 7, [5], True),
|
|
30
|
+
]
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
@pytest.mark.parametrize('interval,timeout,expected_polls,times_out', CASES)
|
|
34
|
+
def test_sync_polling_schedule(monkeypatch, interval, timeout, expected_polls, times_out):
|
|
35
|
+
clock = Clock()
|
|
36
|
+
polls = []
|
|
37
|
+
monkeypatch.setattr(sync_module, 'time', clock)
|
|
38
|
+
|
|
39
|
+
def request(endpoint, payload):
|
|
40
|
+
if endpoint == 'createTask':
|
|
41
|
+
assert clock.now == 0
|
|
42
|
+
return {'errorId': 0, 'taskId': 100}
|
|
43
|
+
assert payload['taskId'] == 100
|
|
44
|
+
polls.append(clock.now)
|
|
45
|
+
if len(polls) == 2:
|
|
46
|
+
return {'errorId': 0, 'status': 'ready', 'solution': {'token': 'done'}}
|
|
47
|
+
return {'errorId': 0, 'status': 'processing'}
|
|
48
|
+
|
|
49
|
+
options = {} if interval is None else {'polling_interval': interval}
|
|
50
|
+
with CaptchaClient('test-key', **options) as client:
|
|
51
|
+
monkeypatch.setattr(client, '_request', request)
|
|
52
|
+
task = RecaptchaV2TaskProxyless('https://example.com', 'site-key')
|
|
53
|
+
if times_out:
|
|
54
|
+
with pytest.raises(CaptchaTimeoutError):
|
|
55
|
+
client.solve(task, timeout=timeout)
|
|
56
|
+
assert clock.now == timeout
|
|
57
|
+
else:
|
|
58
|
+
assert client.solve(task, timeout=timeout) == {'token': 'done'}
|
|
59
|
+
assert polls == expected_polls
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
@pytest.mark.parametrize('interval,timeout,expected_polls,times_out', CASES)
|
|
63
|
+
async def test_async_polling_schedule(monkeypatch, interval, timeout, expected_polls, times_out):
|
|
64
|
+
clock = Clock()
|
|
65
|
+
polls = []
|
|
66
|
+
monkeypatch.setattr(async_module, 'time', clock)
|
|
67
|
+
monkeypatch.setattr(async_module, 'asyncio', SimpleNamespace(sleep=AsyncMock(side_effect=clock.sleep)))
|
|
68
|
+
|
|
69
|
+
async def request(endpoint, payload):
|
|
70
|
+
if endpoint == 'createTask':
|
|
71
|
+
assert clock.now == 0
|
|
72
|
+
return {'errorId': 0, 'taskId': 100}
|
|
73
|
+
assert payload['taskId'] == 100
|
|
74
|
+
polls.append(clock.now)
|
|
75
|
+
if len(polls) == 2:
|
|
76
|
+
return {'errorId': 0, 'status': 'ready', 'solution': {'token': 'done'}}
|
|
77
|
+
return {'errorId': 0, 'status': 'processing'}
|
|
78
|
+
|
|
79
|
+
options = {} if interval is None else {'polling_interval': interval}
|
|
80
|
+
async with AsyncCaptchaClient('test-key', **options) as client:
|
|
81
|
+
monkeypatch.setattr(client, '_request', request)
|
|
82
|
+
task = RecaptchaV2TaskProxyless('https://example.com', 'site-key')
|
|
83
|
+
if times_out:
|
|
84
|
+
with pytest.raises(CaptchaTimeoutError):
|
|
85
|
+
await client.solve(task, timeout=timeout)
|
|
86
|
+
assert clock.now == timeout
|
|
87
|
+
else:
|
|
88
|
+
assert await client.solve(task, timeout=timeout) == {'token': 'done'}
|
|
89
|
+
assert polls == expected_polls
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "1.0.0"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{captcha_solver_api-1.0.0 → captcha_solver_api-1.0.1}/captcha_solver_api.egg-info/requires.txt
RENAMED
|
File without changes
|
{captcha_solver_api-1.0.0 → captcha_solver_api-1.0.1}/captcha_solver_api.egg-info/top_level.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|