captcha-solver-api 1.0.0__tar.gz → 1.0.2__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.2}/PKG-INFO +36 -28
- {captcha_solver_api-1.0.0 → captcha_solver_api-1.0.2}/README.md +35 -27
- captcha_solver_api-1.0.2/captcha_solver_api/_version.py +1 -0
- {captcha_solver_api-1.0.0 → captcha_solver_api-1.0.2}/captcha_solver_api/async_client.py +12 -7
- {captcha_solver_api-1.0.0 → captcha_solver_api-1.0.2}/captcha_solver_api/client.py +12 -7
- {captcha_solver_api-1.0.0 → captcha_solver_api-1.0.2}/captcha_solver_api/tasks.py +13 -11
- {captcha_solver_api-1.0.0 → captcha_solver_api-1.0.2}/captcha_solver_api.egg-info/PKG-INFO +36 -28
- {captcha_solver_api-1.0.0 → captcha_solver_api-1.0.2}/captcha_solver_api.egg-info/SOURCES.txt +2 -1
- captcha_solver_api-1.0.2/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.2}/LICENSE.md +0 -0
- {captcha_solver_api-1.0.0 → captcha_solver_api-1.0.2}/captcha_solver_api/__init__.py +0 -0
- {captcha_solver_api-1.0.0 → captcha_solver_api-1.0.2}/captcha_solver_api/exceptions.py +0 -0
- {captcha_solver_api-1.0.0 → captcha_solver_api-1.0.2}/captcha_solver_api/py.typed +0 -0
- {captcha_solver_api-1.0.0 → captcha_solver_api-1.0.2}/captcha_solver_api.egg-info/dependency_links.txt +0 -0
- {captcha_solver_api-1.0.0 → captcha_solver_api-1.0.2}/captcha_solver_api.egg-info/requires.txt +0 -0
- {captcha_solver_api-1.0.0 → captcha_solver_api-1.0.2}/captcha_solver_api.egg-info/top_level.txt +0 -0
- {captcha_solver_api-1.0.0 → captcha_solver_api-1.0.2}/pyproject.toml +0 -0
- {captcha_solver_api-1.0.0 → captcha_solver_api-1.0.2}/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.2
|
|
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. |
|
|
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. |
|
|
@@ -471,7 +476,7 @@ for the widget on the target page. Use the coordinates method for image challeng
|
|
|
471
476
|
|
|
472
477
|
`YandexSmartCaptchaTaskProxyless` / `YandexSmartCaptchaTask` -- token-based
|
|
473
478
|
challenge. For the image challenge instead, use `CoordinatesTask` with
|
|
474
|
-
|
|
479
|
+
[Coordinates](#coordinates-click-captcha) is available for generic click captchas.
|
|
475
480
|
|
|
476
481
|
| Parameter | Required | Description |
|
|
477
482
|
|---|---|---|
|
|
@@ -514,10 +519,9 @@ SmartCaptcha's image challenge. No proxy variant -- the image is submitted direc
|
|
|
514
519
|
|---|---|---|
|
|
515
520
|
| `body` | yes | The captcha image, base64-encoded. |
|
|
516
521
|
| `comment` | no (recommended) | Hint for the worker, e.g. `"click on the green apple"`. |
|
|
517
|
-
| `imgInstructions` |
|
|
522
|
+
| `imgInstructions` | no | Optional instruction image, base64-encoded. |
|
|
518
523
|
| `minClicks` | no | Minimum number of clicks expected (default `1`). |
|
|
519
524
|
| `maxClicks` | no | Maximum number of clicks allowed. |
|
|
520
|
-
| `imgType` | no | `"smart_captcha"` to solve a Yandex SmartCaptcha image challenge instead of a generic click captcha. |
|
|
521
525
|
|
|
522
526
|
**Response:** `coordinates` -- a list of `{"x": int, "y": int}` pixel positions to click, in order.
|
|
523
527
|
|
|
@@ -535,9 +539,6 @@ task = CoordinatesTask(
|
|
|
535
539
|
result = client.solve(task)
|
|
536
540
|
print(result["coordinates"]) # [{"x": 140, "y": 110}]
|
|
537
541
|
```
|
|
538
|
-
For the Yandex SmartCaptcha image challenge, see
|
|
539
|
-
[examples/sync/yandex_smartcaptcha_image.py](https://github.com/captcha-solver-api/python-sdk/blob/main/examples/sync/yandex_smartcaptcha_image.py)
|
|
540
|
-
(or [examples/async](https://github.com/captcha-solver-api/python-sdk/blob/main/examples/async/yandex_smartcaptcha_image.py)).
|
|
541
542
|
|
|
542
543
|
### Tencent
|
|
543
544
|
|
|
@@ -598,6 +599,14 @@ it for every other call:
|
|
|
598
599
|
result = client.solve(task, timeout=300)
|
|
599
600
|
```
|
|
600
601
|
|
|
602
|
+
The [API requires at least 5 seconds between polls](https://captcha-solver.com/en/docs/how-it-works).
|
|
603
|
+
The SDK defaults to 10 seconds. `solve()` waits for `polling_interval` before
|
|
604
|
+
its first poll and between polls.
|
|
605
|
+
Its default 120-second polling window is independent of the API's five-minute
|
|
606
|
+
task lifetime. A local timeout does not cancel a task or mean that the API
|
|
607
|
+
failed to solve it. Use `create_task()` and keep its `task_id` if you need to
|
|
608
|
+
check the same task later; calling `solve()` again creates a new task.
|
|
609
|
+
|
|
601
610
|
### Worker language pool
|
|
602
611
|
|
|
603
612
|
Set a default `language_pool` once at construction instead of passing it to every call:
|
|
@@ -682,10 +691,10 @@ Avoid importing it by name: it shadows Python's built-in `TimeoutError`.
|
|
|
682
691
|
See the dedicated [examples documentation](https://github.com/captcha-solver-api/python-sdk/blob/main/examples/README.md) for the full
|
|
683
692
|
sync/async example list, setup steps, expected results, and placeholder guidance.
|
|
684
693
|
|
|
685
|
-
- **Image/click captchas** (`image_to_text.py`, `coordinates.py
|
|
686
|
-
`yandex_smartcaptcha_image.py`) run end-to-end with nothing but a valid
|
|
694
|
+
- **Image/click captchas** (`image_to_text.py`, `coordinates.py`) run after installing the dependencies and setting a valid
|
|
687
695
|
`CAPTCHA_API_KEY` -- they read sample images bundled in
|
|
688
696
|
[examples/assets](https://github.com/captcha-solver-api/python-sdk/tree/main/examples/assets), no target page needed.
|
|
697
|
+
`python-dotenv` is optional: install it only if you want the scripts to load a `.env` file.
|
|
689
698
|
- **Token captchas** (`recaptcha_v2.py`, `recaptcha_v2_enterprise.py`, `recaptcha_v3.py`,
|
|
690
699
|
`turnstile.py`, `yandex_smartcaptcha.py`, `geetest_v4.py`, `tencent.py`) use
|
|
691
700
|
placeholder values (`https://example.com/...`, `YOUR_WEBSITE_KEY`, `YOUR_APP_ID`,
|
|
@@ -709,12 +718,11 @@ python examples/sync/image_to_text.py
|
|
|
709
718
|
python examples/sync/coordinates.py
|
|
710
719
|
```
|
|
711
720
|
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
solution
|
|
716
|
-
|
|
717
|
-
pair.
|
|
721
|
+
Live checks with real parameters have exercised all supported task types.
|
|
722
|
+
Individual tasks may return `ERROR_CAPTCHA_UNSOLVABLE` or exceed the client's
|
|
723
|
+
polling timeout. A `ready` response confirms that the service returned a
|
|
724
|
+
solution; the target website must still accept the token with the matching
|
|
725
|
+
page and session parameters.
|
|
718
726
|
|
|
719
727
|
## Requirements
|
|
720
728
|
|
|
@@ -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. |
|
|
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. |
|
|
@@ -435,7 +440,7 @@ for the widget on the target page. Use the coordinates method for image challeng
|
|
|
435
440
|
|
|
436
441
|
`YandexSmartCaptchaTaskProxyless` / `YandexSmartCaptchaTask` -- token-based
|
|
437
442
|
challenge. For the image challenge instead, use `CoordinatesTask` with
|
|
438
|
-
|
|
443
|
+
[Coordinates](#coordinates-click-captcha) is available for generic click captchas.
|
|
439
444
|
|
|
440
445
|
| Parameter | Required | Description |
|
|
441
446
|
|---|---|---|
|
|
@@ -478,10 +483,9 @@ SmartCaptcha's image challenge. No proxy variant -- the image is submitted direc
|
|
|
478
483
|
|---|---|---|
|
|
479
484
|
| `body` | yes | The captcha image, base64-encoded. |
|
|
480
485
|
| `comment` | no (recommended) | Hint for the worker, e.g. `"click on the green apple"`. |
|
|
481
|
-
| `imgInstructions` |
|
|
486
|
+
| `imgInstructions` | no | Optional instruction image, base64-encoded. |
|
|
482
487
|
| `minClicks` | no | Minimum number of clicks expected (default `1`). |
|
|
483
488
|
| `maxClicks` | no | Maximum number of clicks allowed. |
|
|
484
|
-
| `imgType` | no | `"smart_captcha"` to solve a Yandex SmartCaptcha image challenge instead of a generic click captcha. |
|
|
485
489
|
|
|
486
490
|
**Response:** `coordinates` -- a list of `{"x": int, "y": int}` pixel positions to click, in order.
|
|
487
491
|
|
|
@@ -499,9 +503,6 @@ task = CoordinatesTask(
|
|
|
499
503
|
result = client.solve(task)
|
|
500
504
|
print(result["coordinates"]) # [{"x": 140, "y": 110}]
|
|
501
505
|
```
|
|
502
|
-
For the Yandex SmartCaptcha image challenge, see
|
|
503
|
-
[examples/sync/yandex_smartcaptcha_image.py](https://github.com/captcha-solver-api/python-sdk/blob/main/examples/sync/yandex_smartcaptcha_image.py)
|
|
504
|
-
(or [examples/async](https://github.com/captcha-solver-api/python-sdk/blob/main/examples/async/yandex_smartcaptcha_image.py)).
|
|
505
506
|
|
|
506
507
|
### Tencent
|
|
507
508
|
|
|
@@ -562,6 +563,14 @@ it for every other call:
|
|
|
562
563
|
result = client.solve(task, timeout=300)
|
|
563
564
|
```
|
|
564
565
|
|
|
566
|
+
The [API requires at least 5 seconds between polls](https://captcha-solver.com/en/docs/how-it-works).
|
|
567
|
+
The SDK defaults to 10 seconds. `solve()` waits for `polling_interval` before
|
|
568
|
+
its first poll and between polls.
|
|
569
|
+
Its default 120-second polling window is independent of the API's five-minute
|
|
570
|
+
task lifetime. A local timeout does not cancel a task or mean that the API
|
|
571
|
+
failed to solve it. Use `create_task()` and keep its `task_id` if you need to
|
|
572
|
+
check the same task later; calling `solve()` again creates a new task.
|
|
573
|
+
|
|
565
574
|
### Worker language pool
|
|
566
575
|
|
|
567
576
|
Set a default `language_pool` once at construction instead of passing it to every call:
|
|
@@ -646,10 +655,10 @@ Avoid importing it by name: it shadows Python's built-in `TimeoutError`.
|
|
|
646
655
|
See the dedicated [examples documentation](https://github.com/captcha-solver-api/python-sdk/blob/main/examples/README.md) for the full
|
|
647
656
|
sync/async example list, setup steps, expected results, and placeholder guidance.
|
|
648
657
|
|
|
649
|
-
- **Image/click captchas** (`image_to_text.py`, `coordinates.py
|
|
650
|
-
`yandex_smartcaptcha_image.py`) run end-to-end with nothing but a valid
|
|
658
|
+
- **Image/click captchas** (`image_to_text.py`, `coordinates.py`) run after installing the dependencies and setting a valid
|
|
651
659
|
`CAPTCHA_API_KEY` -- they read sample images bundled in
|
|
652
660
|
[examples/assets](https://github.com/captcha-solver-api/python-sdk/tree/main/examples/assets), no target page needed.
|
|
661
|
+
`python-dotenv` is optional: install it only if you want the scripts to load a `.env` file.
|
|
653
662
|
- **Token captchas** (`recaptcha_v2.py`, `recaptcha_v2_enterprise.py`, `recaptcha_v3.py`,
|
|
654
663
|
`turnstile.py`, `yandex_smartcaptcha.py`, `geetest_v4.py`, `tencent.py`) use
|
|
655
664
|
placeholder values (`https://example.com/...`, `YOUR_WEBSITE_KEY`, `YOUR_APP_ID`,
|
|
@@ -673,12 +682,11 @@ python examples/sync/image_to_text.py
|
|
|
673
682
|
python examples/sync/coordinates.py
|
|
674
683
|
```
|
|
675
684
|
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
solution
|
|
680
|
-
|
|
681
|
-
pair.
|
|
685
|
+
Live checks with real parameters have exercised all supported task types.
|
|
686
|
+
Individual tasks may return `ERROR_CAPTCHA_UNSOLVABLE` or exceed the client's
|
|
687
|
+
polling timeout. A `ready` response confirms that the service returned a
|
|
688
|
+
solution; the target website must still accept the token with the matching
|
|
689
|
+
page and session parameters.
|
|
682
690
|
|
|
683
691
|
## Requirements
|
|
684
692
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "1.0.2"
|
|
@@ -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.
|
|
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.
|
|
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.")
|
|
@@ -55,6 +55,15 @@ class ProxyMixin:
|
|
|
55
55
|
proxy_login: Optional[str] = None,
|
|
56
56
|
proxy_password: Optional[str] = None,
|
|
57
57
|
) -> None:
|
|
58
|
+
"""Sets the proxy fields on this task.
|
|
59
|
+
|
|
60
|
+
Args:
|
|
61
|
+
proxy_type: `"http"`, `"socks4"`, or `"socks5"`.
|
|
62
|
+
proxy_address: Proxy IP address or hostname.
|
|
63
|
+
proxy_port: Proxy port.
|
|
64
|
+
proxy_login: Proxy auth username, if required.
|
|
65
|
+
proxy_password: Proxy auth password, if required.
|
|
66
|
+
"""
|
|
58
67
|
self.proxyType = proxy_type
|
|
59
68
|
self.proxyAddress = proxy_address
|
|
60
69
|
self.proxyPort = proxy_port
|
|
@@ -525,8 +534,7 @@ class GeeTestTask(BaseTask, ProxyMixin):
|
|
|
525
534
|
|
|
526
535
|
|
|
527
536
|
class YandexSmartCaptchaTaskProxyless(BaseTask):
|
|
528
|
-
"""Yandex SmartCaptcha (token challenge) without proxy.
|
|
529
|
-
challenge instead, use `CoordinatesTask` with `imgType="smart_captcha"`.
|
|
537
|
+
"""Yandex SmartCaptcha (token challenge) without proxy.
|
|
530
538
|
|
|
531
539
|
Args:
|
|
532
540
|
websiteURL: Full URL of the page where the widget is located.
|
|
@@ -597,20 +605,16 @@ class YandexSmartCaptchaTask(BaseTask, ProxyMixin):
|
|
|
597
605
|
|
|
598
606
|
|
|
599
607
|
class CoordinatesTask(BaseTask):
|
|
600
|
-
"""Coordinate-based (click) image captcha.
|
|
601
|
-
|
|
602
|
-
`imgType` accordingly). No proxy variant -- the image is submitted directly.
|
|
608
|
+
"""Coordinate-based (click) image captcha. No proxy variant -- the image
|
|
609
|
+
is submitted directly.
|
|
603
610
|
|
|
604
611
|
Args:
|
|
605
612
|
body: The captcha image, base64-encoded (no `data:image/...;base64,` prefix).
|
|
606
613
|
comment: Hint for the worker, e.g. `"click on the green apple"`. Recommended
|
|
607
614
|
for generic click captchas.
|
|
608
|
-
imgInstructions: Optional instruction image, base64-encoded
|
|
609
|
-
to click and in what order. Required when `imgType="smart_captcha"`.
|
|
615
|
+
imgInstructions: Optional instruction image, base64-encoded.
|
|
610
616
|
minClicks: Minimum number of clicks expected (default `1`).
|
|
611
617
|
maxClicks: Maximum number of clicks allowed.
|
|
612
|
-
imgType: Set to `"smart_captcha"` to solve a Yandex SmartCaptcha image
|
|
613
|
-
challenge instead of a generic click captcha.
|
|
614
618
|
|
|
615
619
|
Returns (`solution` from `solve()`):
|
|
616
620
|
`coordinates` -- a list of `{"x": int, "y": int}` pixel positions to click,
|
|
@@ -626,14 +630,12 @@ class CoordinatesTask(BaseTask):
|
|
|
626
630
|
imgInstructions: Optional[str] = None,
|
|
627
631
|
minClicks: Optional[int] = None,
|
|
628
632
|
maxClicks: Optional[int] = None,
|
|
629
|
-
imgType: Optional[str] = None,
|
|
630
633
|
) -> None:
|
|
631
634
|
self.body = body
|
|
632
635
|
self.comment = comment
|
|
633
636
|
self.imgInstructions = imgInstructions
|
|
634
637
|
self.minClicks = minClicks
|
|
635
638
|
self.maxClicks = maxClicks
|
|
636
|
-
self.imgType = imgType
|
|
637
639
|
|
|
638
640
|
|
|
639
641
|
class TencentTaskProxyless(BaseTask):
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: captcha-solver-api
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.2
|
|
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. |
|
|
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. |
|
|
@@ -471,7 +476,7 @@ for the widget on the target page. Use the coordinates method for image challeng
|
|
|
471
476
|
|
|
472
477
|
`YandexSmartCaptchaTaskProxyless` / `YandexSmartCaptchaTask` -- token-based
|
|
473
478
|
challenge. For the image challenge instead, use `CoordinatesTask` with
|
|
474
|
-
|
|
479
|
+
[Coordinates](#coordinates-click-captcha) is available for generic click captchas.
|
|
475
480
|
|
|
476
481
|
| Parameter | Required | Description |
|
|
477
482
|
|---|---|---|
|
|
@@ -514,10 +519,9 @@ SmartCaptcha's image challenge. No proxy variant -- the image is submitted direc
|
|
|
514
519
|
|---|---|---|
|
|
515
520
|
| `body` | yes | The captcha image, base64-encoded. |
|
|
516
521
|
| `comment` | no (recommended) | Hint for the worker, e.g. `"click on the green apple"`. |
|
|
517
|
-
| `imgInstructions` |
|
|
522
|
+
| `imgInstructions` | no | Optional instruction image, base64-encoded. |
|
|
518
523
|
| `minClicks` | no | Minimum number of clicks expected (default `1`). |
|
|
519
524
|
| `maxClicks` | no | Maximum number of clicks allowed. |
|
|
520
|
-
| `imgType` | no | `"smart_captcha"` to solve a Yandex SmartCaptcha image challenge instead of a generic click captcha. |
|
|
521
525
|
|
|
522
526
|
**Response:** `coordinates` -- a list of `{"x": int, "y": int}` pixel positions to click, in order.
|
|
523
527
|
|
|
@@ -535,9 +539,6 @@ task = CoordinatesTask(
|
|
|
535
539
|
result = client.solve(task)
|
|
536
540
|
print(result["coordinates"]) # [{"x": 140, "y": 110}]
|
|
537
541
|
```
|
|
538
|
-
For the Yandex SmartCaptcha image challenge, see
|
|
539
|
-
[examples/sync/yandex_smartcaptcha_image.py](https://github.com/captcha-solver-api/python-sdk/blob/main/examples/sync/yandex_smartcaptcha_image.py)
|
|
540
|
-
(or [examples/async](https://github.com/captcha-solver-api/python-sdk/blob/main/examples/async/yandex_smartcaptcha_image.py)).
|
|
541
542
|
|
|
542
543
|
### Tencent
|
|
543
544
|
|
|
@@ -598,6 +599,14 @@ it for every other call:
|
|
|
598
599
|
result = client.solve(task, timeout=300)
|
|
599
600
|
```
|
|
600
601
|
|
|
602
|
+
The [API requires at least 5 seconds between polls](https://captcha-solver.com/en/docs/how-it-works).
|
|
603
|
+
The SDK defaults to 10 seconds. `solve()` waits for `polling_interval` before
|
|
604
|
+
its first poll and between polls.
|
|
605
|
+
Its default 120-second polling window is independent of the API's five-minute
|
|
606
|
+
task lifetime. A local timeout does not cancel a task or mean that the API
|
|
607
|
+
failed to solve it. Use `create_task()` and keep its `task_id` if you need to
|
|
608
|
+
check the same task later; calling `solve()` again creates a new task.
|
|
609
|
+
|
|
601
610
|
### Worker language pool
|
|
602
611
|
|
|
603
612
|
Set a default `language_pool` once at construction instead of passing it to every call:
|
|
@@ -682,10 +691,10 @@ Avoid importing it by name: it shadows Python's built-in `TimeoutError`.
|
|
|
682
691
|
See the dedicated [examples documentation](https://github.com/captcha-solver-api/python-sdk/blob/main/examples/README.md) for the full
|
|
683
692
|
sync/async example list, setup steps, expected results, and placeholder guidance.
|
|
684
693
|
|
|
685
|
-
- **Image/click captchas** (`image_to_text.py`, `coordinates.py
|
|
686
|
-
`yandex_smartcaptcha_image.py`) run end-to-end with nothing but a valid
|
|
694
|
+
- **Image/click captchas** (`image_to_text.py`, `coordinates.py`) run after installing the dependencies and setting a valid
|
|
687
695
|
`CAPTCHA_API_KEY` -- they read sample images bundled in
|
|
688
696
|
[examples/assets](https://github.com/captcha-solver-api/python-sdk/tree/main/examples/assets), no target page needed.
|
|
697
|
+
`python-dotenv` is optional: install it only if you want the scripts to load a `.env` file.
|
|
689
698
|
- **Token captchas** (`recaptcha_v2.py`, `recaptcha_v2_enterprise.py`, `recaptcha_v3.py`,
|
|
690
699
|
`turnstile.py`, `yandex_smartcaptcha.py`, `geetest_v4.py`, `tencent.py`) use
|
|
691
700
|
placeholder values (`https://example.com/...`, `YOUR_WEBSITE_KEY`, `YOUR_APP_ID`,
|
|
@@ -709,12 +718,11 @@ python examples/sync/image_to_text.py
|
|
|
709
718
|
python examples/sync/coordinates.py
|
|
710
719
|
```
|
|
711
720
|
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
solution
|
|
716
|
-
|
|
717
|
-
pair.
|
|
721
|
+
Live checks with real parameters have exercised all supported task types.
|
|
722
|
+
Individual tasks may return `ERROR_CAPTCHA_UNSOLVABLE` or exceed the client's
|
|
723
|
+
polling timeout. A `ready` response confirms that the service returned a
|
|
724
|
+
solution; the target website must still accept the token with the matching
|
|
725
|
+
page and session parameters.
|
|
718
726
|
|
|
719
727
|
## Requirements
|
|
720
728
|
|
{captcha_solver_api-1.0.0 → captcha_solver_api-1.0.2}/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
|
{captcha_solver_api-1.0.0 → captcha_solver_api-1.0.2}/captcha_solver_api.egg-info/requires.txt
RENAMED
|
File without changes
|
{captcha_solver_api-1.0.0 → captcha_solver_api-1.0.2}/captcha_solver_api.egg-info/top_level.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|