captcha-solver-api 1.0.4__tar.gz → 1.1.0__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.4 → captcha_solver_api-1.1.0}/PKG-INFO +91 -27
- {captcha_solver_api-1.0.4 → captcha_solver_api-1.1.0}/README.md +87 -23
- captcha_solver_api-1.1.0/captcha_solver_api/_version.py +1 -0
- {captcha_solver_api-1.0.4 → captcha_solver_api-1.1.0}/captcha_solver_api/async_client.py +47 -8
- {captcha_solver_api-1.0.4 → captcha_solver_api-1.1.0}/captcha_solver_api/client.py +47 -8
- {captcha_solver_api-1.0.4 → captcha_solver_api-1.1.0}/captcha_solver_api/exceptions.py +26 -2
- {captcha_solver_api-1.0.4 → captcha_solver_api-1.1.0}/captcha_solver_api/tasks.py +230 -135
- {captcha_solver_api-1.0.4 → captcha_solver_api-1.1.0}/captcha_solver_api.egg-info/PKG-INFO +91 -27
- {captcha_solver_api-1.0.4 → captcha_solver_api-1.1.0}/captcha_solver_api.egg-info/requires.txt +2 -2
- {captcha_solver_api-1.0.4 → captcha_solver_api-1.1.0}/pyproject.toml +3 -3
- captcha_solver_api-1.0.4/captcha_solver_api/_version.py +0 -1
- {captcha_solver_api-1.0.4 → captcha_solver_api-1.1.0}/LICENSE.md +0 -0
- {captcha_solver_api-1.0.4 → captcha_solver_api-1.1.0}/captcha_solver_api/__init__.py +0 -0
- {captcha_solver_api-1.0.4 → captcha_solver_api-1.1.0}/captcha_solver_api/py.typed +0 -0
- {captcha_solver_api-1.0.4 → captcha_solver_api-1.1.0}/captcha_solver_api.egg-info/SOURCES.txt +0 -0
- {captcha_solver_api-1.0.4 → captcha_solver_api-1.1.0}/captcha_solver_api.egg-info/dependency_links.txt +0 -0
- {captcha_solver_api-1.0.4 → captcha_solver_api-1.1.0}/captcha_solver_api.egg-info/top_level.txt +0 -0
- {captcha_solver_api-1.0.4 → captcha_solver_api-1.1.0}/setup.cfg +0 -0
- {captcha_solver_api-1.0.4 → captcha_solver_api-1.1.0}/tests/test_polling.py +0 -0
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: captcha-solver-api
|
|
3
|
-
Version: 1.0
|
|
3
|
+
Version: 1.1.0
|
|
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
|
|
7
7
|
Project-URL: Homepage, https://captcha-solver.com
|
|
8
|
-
Project-URL: Documentation, https://
|
|
8
|
+
Project-URL: Documentation, https://github.com/captcha-solver-api/python-sdk#readme
|
|
9
9
|
Project-URL: Repository, https://github.com/captcha-solver-api/python-sdk
|
|
10
10
|
Keywords: captcha,captcha solver,recaptcha,recaptcha v2,recaptcha v3,cloudflare turnstile,geetest,geetest v4,yandex smartcaptcha,tencent captcha,image captcha,coordinates,click captcha,api
|
|
11
11
|
Classifier: Development Status :: 5 - Production/Stable
|
|
@@ -25,8 +25,8 @@ Classifier: Typing :: Typed
|
|
|
25
25
|
Requires-Python: >=3.9
|
|
26
26
|
Description-Content-Type: text/markdown
|
|
27
27
|
License-File: LICENSE.md
|
|
28
|
-
Requires-Dist: requests>=2.
|
|
29
|
-
Requires-Dist: httpx>=0.
|
|
28
|
+
Requires-Dist: requests>=2.32.4
|
|
29
|
+
Requires-Dist: httpx>=0.27
|
|
30
30
|
Provides-Extra: dev
|
|
31
31
|
Requires-Dist: pytest>=7; extra == "dev"
|
|
32
32
|
Requires-Dist: pytest-asyncio>=0.21; extra == "dev"
|
|
@@ -115,6 +115,10 @@ enabled in your editor, hover over `CaptchaClient`, `AsyncCaptchaClient`, their
|
|
|
115
115
|
methods, or a task class such as `RecaptchaV2TaskProxyless` to read the documentation.
|
|
116
116
|
Signature help shows argument names, types, and defaults while you type a call.
|
|
117
117
|
|
|
118
|
+
The `captcha_solver_api/py.typed` file is intentionally empty. It is the standard
|
|
119
|
+
[PEP 561](https://peps.python.org/pep-0561/) marker that tells type checkers to use
|
|
120
|
+
the inline type annotations shipped with this package.
|
|
121
|
+
|
|
118
122
|
Docstrings describe parameters, solution fields, exceptions, and usage examples.
|
|
119
123
|
Task examples assume an existing synchronous `client`; with `AsyncCaptchaClient`,
|
|
120
124
|
use `solution = await client.solve(task)` instead. Async snippets run inside an
|
|
@@ -191,15 +195,19 @@ on the target page.
|
|
|
191
195
|
|---|---|---|
|
|
192
196
|
| reCAPTCHA v2 | ✅ | ✅ |
|
|
193
197
|
| reCAPTCHA v2 Enterprise | ✅ | ✅ |
|
|
194
|
-
| reCAPTCHA v3 | ✅ |
|
|
198
|
+
| reCAPTCHA v3 | ✅ | - |
|
|
195
199
|
| Cloudflare Turnstile | ✅ | ✅ |
|
|
196
200
|
| GeeTest v3 | ✅ | ✅ |
|
|
197
201
|
| GeeTest v4 | ✅ | ✅ |
|
|
198
|
-
| Image to Text | ✅ |
|
|
202
|
+
| Image to Text | ✅ | - |
|
|
199
203
|
| Yandex SmartCaptcha | ✅ | ✅ |
|
|
200
|
-
|
|
|
204
|
+
| Yandex SmartCaptcha Image | ✅ | - |
|
|
205
|
+
| Coordinates (click captcha) | ✅ | - |
|
|
201
206
|
| Tencent | ✅ | ✅ |
|
|
202
207
|
|
|
208
|
+
A dash (`-`) means that this CAPTCHA type has no separate task class that accepts
|
|
209
|
+
your own proxy; it does not indicate that solving the CAPTCHA is unsupported.
|
|
210
|
+
|
|
203
211
|
## Client Reference
|
|
204
212
|
|
|
205
213
|
Every method below is available on both `CaptchaClient` (sync, `requests`-based) and
|
|
@@ -247,14 +255,17 @@ solution -- wraps `create_task()` + `get_task_result()` so you don't poll by han
|
|
|
247
255
|
|
|
248
256
|
Returns the `solution` dict once `status` is `"ready"` -- its shape depends on
|
|
249
257
|
the task type (see [Captcha Types](#captcha-types)).
|
|
250
|
-
Raises `
|
|
258
|
+
Raises `ValidationError` before any request if `task` is not a task object or a
|
|
259
|
+
required task parameter is missing or empty. Otherwise raises `ApiError`,
|
|
260
|
+
`CaptchaTimeoutError`, or `NetworkError`.
|
|
251
261
|
|
|
252
262
|
### `create_task(task, language_pool=None)`
|
|
253
263
|
|
|
254
264
|
Submits `task` and returns its numeric task ID without waiting for a solution.
|
|
255
265
|
Accepts `task` and `language_pool`; it does not accept `timeout`. Use this instead of `solve()` if you need to
|
|
256
266
|
manage polling yourself (e.g. checking on many tasks from a different process).
|
|
257
|
-
Raises `
|
|
267
|
+
Raises `ValidationError` before any request if `task` is invalid (same rules as
|
|
268
|
+
`solve()`). Otherwise raises `ApiError`, `CaptchaTimeoutError`, or `NetworkError`.
|
|
258
269
|
|
|
259
270
|
### `get_task_result(task_id)`
|
|
260
271
|
|
|
@@ -519,7 +530,7 @@ print(result["validate"])
|
|
|
519
530
|
print(result["seccode"])
|
|
520
531
|
```
|
|
521
532
|
`challenge` is session-specific and expires quickly, so it can't be hardcoded
|
|
522
|
-
into a static example -- see [examples/sync/
|
|
533
|
+
into a static example -- see [examples/sync/geetest_v3_proxyless.py](https://github.com/captcha-solver-api/python-sdk/blob/main/examples/sync/geetest_v3_proxyless.py)
|
|
523
534
|
for where the fetch belongs in the flow.
|
|
524
535
|
|
|
525
536
|
```python
|
|
@@ -539,11 +550,9 @@ With proxy, use `GeeTestTask` (same proxy fields as reCAPTCHA v2).
|
|
|
539
550
|
<sup>[API method description.](https://captcha-solver.com/en/docs/captcha-types#yandex-smartcaptcha)</sup>
|
|
540
551
|
|
|
541
552
|
Use this method to solve the token-based Yandex SmartCaptcha and obtain a token
|
|
542
|
-
for the widget on the target page. Use the
|
|
553
|
+
for the widget on the target page. Use the dedicated image method for image challenges.
|
|
543
554
|
|
|
544
|
-
`YandexSmartCaptchaTaskProxyless` / `YandexSmartCaptchaTask` -- token-based
|
|
545
|
-
challenge. For the image challenge instead, use `CoordinatesTask` with
|
|
546
|
-
[Coordinates](#coordinates-click-captcha) is available for generic click captchas.
|
|
555
|
+
`YandexSmartCaptchaTaskProxyless` / `YandexSmartCaptchaTask` -- token-based challenge.
|
|
547
556
|
|
|
548
557
|
| Parameter | Required | Description |
|
|
549
558
|
|---|---|---|
|
|
@@ -572,15 +581,45 @@ print(result["token"])
|
|
|
572
581
|
With proxy, use `YandexSmartCaptchaTask` (same proxy fields as reCAPTCHA v2,
|
|
573
582
|
plus the `https` option above).
|
|
574
583
|
|
|
584
|
+
#### Image challenge
|
|
585
|
+
|
|
586
|
+
Use `YandexSmartCaptchaImageTask` when SmartCaptcha shows a main image and a
|
|
587
|
+
separate strip indicating the symbols to click. The SDK sends API v2 type
|
|
588
|
+
`SmartCaptchaTask`; both images must be base64-encoded.
|
|
589
|
+
|
|
590
|
+
| Parameter | Required | Description |
|
|
591
|
+
|---|---|---|
|
|
592
|
+
| `image` | yes | Main captcha image, base64-encoded. |
|
|
593
|
+
| `imgInstructions` | yes | Click-order instruction image, base64-encoded. |
|
|
594
|
+
| `comment` | no | Optional text hint for the worker. |
|
|
595
|
+
|
|
596
|
+
**Response:** `coordinates` -- ordered `{"x": int, "y": int}` click positions.
|
|
597
|
+
|
|
598
|
+
```python
|
|
599
|
+
import base64
|
|
600
|
+
from captcha_solver_api import CaptchaClient
|
|
601
|
+
from captcha_solver_api.tasks import YandexSmartCaptchaImageTask
|
|
602
|
+
|
|
603
|
+
with open("captcha.png", "rb") as f:
|
|
604
|
+
image = base64.b64encode(f.read()).decode("utf-8")
|
|
605
|
+
with open("instructions.png", "rb") as f:
|
|
606
|
+
instructions = base64.b64encode(f.read()).decode("utf-8")
|
|
607
|
+
|
|
608
|
+
task = YandexSmartCaptchaImageTask(
|
|
609
|
+
image=image,
|
|
610
|
+
imgInstructions=instructions,
|
|
611
|
+
)
|
|
612
|
+
result = CaptchaClient("your_api_key").solve(task)
|
|
613
|
+
print(result["coordinates"])
|
|
614
|
+
```
|
|
615
|
+
|
|
575
616
|
### Coordinates (click captcha)
|
|
576
617
|
|
|
577
618
|
<sup>[API method description.](https://captcha-solver.com/en/docs/captcha-types#coordinates)</sup>
|
|
578
619
|
|
|
579
|
-
Use this method to identify points that a worker should click in
|
|
580
|
-
supports generic click captchas and the image version of Yandex SmartCaptcha.
|
|
620
|
+
Use this method to identify points that a worker should click in a generic image.
|
|
581
621
|
|
|
582
|
-
`CoordinatesTask`.
|
|
583
|
-
SmartCaptcha's image challenge. No proxy variant -- the image is submitted directly.
|
|
622
|
+
`CoordinatesTask`. No proxy variant -- the image is submitted directly.
|
|
584
623
|
|
|
585
624
|
| Parameter | Required | Description |
|
|
586
625
|
|---|---|---|
|
|
@@ -674,6 +713,16 @@ task lifetime. A local timeout does not cancel a task or mean that the API
|
|
|
674
713
|
failed to solve it. Use `create_task()` and keep its `task_id` if you need to
|
|
675
714
|
check the same task later; calling `solve()` again creates a new task.
|
|
676
715
|
|
|
716
|
+
While polling, `solve()` retries short network failures and HTTP timeouts of
|
|
717
|
+
`getTaskResult` on the next poll, so a brief outage does not lose an already
|
|
718
|
+
created task. After `poll_retries` (default 3) consecutive failures the error is
|
|
719
|
+
raised. API errors are not retried, and `createTask` is never retried because
|
|
720
|
+
that could create and pay for a second task. To change the limit:
|
|
721
|
+
|
|
722
|
+
```python
|
|
723
|
+
client.poll_retries = 5
|
|
724
|
+
```
|
|
725
|
+
|
|
677
726
|
### Worker language pool
|
|
678
727
|
|
|
679
728
|
Set a default `language_pool` once at construction instead of passing it to every call:
|
|
@@ -743,13 +792,26 @@ try:
|
|
|
743
792
|
except ValidationError as e:
|
|
744
793
|
print(f"Invalid argument: {e}")
|
|
745
794
|
except ApiError as e:
|
|
746
|
-
print(f"API error: {e.error_code} {e.error_description}")
|
|
747
|
-
except CaptchaTimeoutError:
|
|
748
|
-
print("Task timed out")
|
|
795
|
+
print(f"API error: {e.error_code} {e.error_description} (task {e.task_id})")
|
|
796
|
+
except CaptchaTimeoutError as e:
|
|
797
|
+
print(f"Task {e.task_id} timed out")
|
|
749
798
|
except NetworkError as e:
|
|
750
799
|
print(f"Network error: {e}")
|
|
751
800
|
```
|
|
752
801
|
|
|
802
|
+
Every SDK error has a `task_id` attribute. It is set when the error happens
|
|
803
|
+
after the task was created (while polling in `solve()` or in `get_task_result()`)
|
|
804
|
+
and is `None` otherwise. A polling timeout does not cancel the task, so you can
|
|
805
|
+
keep checking it:
|
|
806
|
+
|
|
807
|
+
```python
|
|
808
|
+
try:
|
|
809
|
+
result = client.solve(task)
|
|
810
|
+
except CaptchaTimeoutError as e:
|
|
811
|
+
if e.task_id is not None:
|
|
812
|
+
status = client.get_task_result(e.task_id)
|
|
813
|
+
```
|
|
814
|
+
|
|
753
815
|
`TimeoutError` is still exported as a deprecated alias of `CaptchaTimeoutError`.
|
|
754
816
|
Avoid importing it by name: it shadows Python's built-in `TimeoutError`.
|
|
755
817
|
|
|
@@ -758,16 +820,17 @@ Avoid importing it by name: it shadows Python's built-in `TimeoutError`.
|
|
|
758
820
|
See the dedicated [examples documentation](https://github.com/captcha-solver-api/python-sdk/blob/main/examples/README.md) for the full
|
|
759
821
|
sync/async example list, setup steps, expected results, and placeholder guidance.
|
|
760
822
|
|
|
761
|
-
- **Image/click captchas** (`image_to_text.py`, `coordinates.py
|
|
823
|
+
- **Image/click captchas** (`image_to_text.py`, `coordinates.py`,
|
|
824
|
+
`yandex_smartcaptcha_image.py`) run after installing the dependencies and setting a valid
|
|
762
825
|
`CAPTCHA_API_KEY` -- they read sample images bundled in
|
|
763
826
|
[examples/assets](https://github.com/captcha-solver-api/python-sdk/tree/main/examples/assets), no target page needed.
|
|
764
827
|
`python-dotenv` is optional: install it only if you want the scripts to load a `.env` file.
|
|
765
|
-
- **Token captchas** (`
|
|
766
|
-
`
|
|
828
|
+
- **Token captchas** (`recaptcha_v2_*.py`, `recaptcha_v2_enterprise_*.py`, `recaptcha_v3.py`,
|
|
829
|
+
`turnstile_*.py`, `yandex_smartcaptcha_*.py`, `geetest_v4_*.py`, `tencent_*.py`) use
|
|
767
830
|
placeholder values (`https://example.com/...`, `YOUR_WEBSITE_KEY`, `YOUR_APP_ID`,
|
|
768
831
|
`YOUR_CAPTCHA_ID`) -- replace these with the real values from your own target
|
|
769
832
|
page before running.
|
|
770
|
-
- **`
|
|
833
|
+
- **`geetest_v3_*.py`** additionally needs `challenge` fetched fresh for every
|
|
771
834
|
request -- it's single-use and expires within seconds, so it can't be
|
|
772
835
|
hardcoded into a static example. `"https://target-site.com/path/to/geetest/init"`
|
|
773
836
|
is a placeholder; replace it with a request to your own target's equivalent
|
|
@@ -783,6 +846,7 @@ export CAPTCHA_API_KEY=your_api_key
|
|
|
783
846
|
python examples/sync/balance.py
|
|
784
847
|
python examples/sync/image_to_text.py
|
|
785
848
|
python examples/sync/coordinates.py
|
|
849
|
+
python examples/sync/yandex_smartcaptcha_image.py
|
|
786
850
|
```
|
|
787
851
|
|
|
788
852
|
Live checks with real parameters have exercised all supported task types.
|
|
@@ -807,8 +871,8 @@ Full API reference: https://captcha-solver.com/en/docs/captcha-types
|
|
|
807
871
|
- [Selenium Python examples](https://github.com/captcha-solver-api/captcha-solver-selenium-python-examples)
|
|
808
872
|
- [JavaScript examples](https://github.com/captcha-solver-api/javascript-examples)
|
|
809
873
|
- [Tencent CAPTCHA automation examples](https://github.com/captcha-solver-api/How-to-Automate-Tencent-CAPTCHA)
|
|
810
|
-
- [Cloudflare Turnstile Puppeteer Demo](https://github.com/captcha-solver-api/cloudflare-turnstile-puppeteer-demo)
|
|
811
|
-
- [How to Automate Tencent CAPTCHA](https://captcha-solver.com/en/blog/how-to-automate-tencent-captcha)
|
|
874
|
+
- [Cloudflare Turnstile Puppeteer Demo](https://github.com/captcha-solver-api/cloudflare-turnstile-puppeteer-demo) - a working browser automation example for Cloudflare Turnstile.
|
|
875
|
+
- [How to Automate Tencent CAPTCHA](https://captcha-solver.com/en/blog/how-to-automate-tencent-captcha) - a step-by-step guide with Python and JavaScript SDK examples.
|
|
812
876
|
|
|
813
877
|
## License
|
|
814
878
|
|
|
@@ -75,6 +75,10 @@ enabled in your editor, hover over `CaptchaClient`, `AsyncCaptchaClient`, their
|
|
|
75
75
|
methods, or a task class such as `RecaptchaV2TaskProxyless` to read the documentation.
|
|
76
76
|
Signature help shows argument names, types, and defaults while you type a call.
|
|
77
77
|
|
|
78
|
+
The `captcha_solver_api/py.typed` file is intentionally empty. It is the standard
|
|
79
|
+
[PEP 561](https://peps.python.org/pep-0561/) marker that tells type checkers to use
|
|
80
|
+
the inline type annotations shipped with this package.
|
|
81
|
+
|
|
78
82
|
Docstrings describe parameters, solution fields, exceptions, and usage examples.
|
|
79
83
|
Task examples assume an existing synchronous `client`; with `AsyncCaptchaClient`,
|
|
80
84
|
use `solution = await client.solve(task)` instead. Async snippets run inside an
|
|
@@ -151,15 +155,19 @@ on the target page.
|
|
|
151
155
|
|---|---|---|
|
|
152
156
|
| reCAPTCHA v2 | ✅ | ✅ |
|
|
153
157
|
| reCAPTCHA v2 Enterprise | ✅ | ✅ |
|
|
154
|
-
| reCAPTCHA v3 | ✅ |
|
|
158
|
+
| reCAPTCHA v3 | ✅ | - |
|
|
155
159
|
| Cloudflare Turnstile | ✅ | ✅ |
|
|
156
160
|
| GeeTest v3 | ✅ | ✅ |
|
|
157
161
|
| GeeTest v4 | ✅ | ✅ |
|
|
158
|
-
| Image to Text | ✅ |
|
|
162
|
+
| Image to Text | ✅ | - |
|
|
159
163
|
| Yandex SmartCaptcha | ✅ | ✅ |
|
|
160
|
-
|
|
|
164
|
+
| Yandex SmartCaptcha Image | ✅ | - |
|
|
165
|
+
| Coordinates (click captcha) | ✅ | - |
|
|
161
166
|
| Tencent | ✅ | ✅ |
|
|
162
167
|
|
|
168
|
+
A dash (`-`) means that this CAPTCHA type has no separate task class that accepts
|
|
169
|
+
your own proxy; it does not indicate that solving the CAPTCHA is unsupported.
|
|
170
|
+
|
|
163
171
|
## Client Reference
|
|
164
172
|
|
|
165
173
|
Every method below is available on both `CaptchaClient` (sync, `requests`-based) and
|
|
@@ -207,14 +215,17 @@ solution -- wraps `create_task()` + `get_task_result()` so you don't poll by han
|
|
|
207
215
|
|
|
208
216
|
Returns the `solution` dict once `status` is `"ready"` -- its shape depends on
|
|
209
217
|
the task type (see [Captcha Types](#captcha-types)).
|
|
210
|
-
Raises `
|
|
218
|
+
Raises `ValidationError` before any request if `task` is not a task object or a
|
|
219
|
+
required task parameter is missing or empty. Otherwise raises `ApiError`,
|
|
220
|
+
`CaptchaTimeoutError`, or `NetworkError`.
|
|
211
221
|
|
|
212
222
|
### `create_task(task, language_pool=None)`
|
|
213
223
|
|
|
214
224
|
Submits `task` and returns its numeric task ID without waiting for a solution.
|
|
215
225
|
Accepts `task` and `language_pool`; it does not accept `timeout`. Use this instead of `solve()` if you need to
|
|
216
226
|
manage polling yourself (e.g. checking on many tasks from a different process).
|
|
217
|
-
Raises `
|
|
227
|
+
Raises `ValidationError` before any request if `task` is invalid (same rules as
|
|
228
|
+
`solve()`). Otherwise raises `ApiError`, `CaptchaTimeoutError`, or `NetworkError`.
|
|
218
229
|
|
|
219
230
|
### `get_task_result(task_id)`
|
|
220
231
|
|
|
@@ -479,7 +490,7 @@ print(result["validate"])
|
|
|
479
490
|
print(result["seccode"])
|
|
480
491
|
```
|
|
481
492
|
`challenge` is session-specific and expires quickly, so it can't be hardcoded
|
|
482
|
-
into a static example -- see [examples/sync/
|
|
493
|
+
into a static example -- see [examples/sync/geetest_v3_proxyless.py](https://github.com/captcha-solver-api/python-sdk/blob/main/examples/sync/geetest_v3_proxyless.py)
|
|
483
494
|
for where the fetch belongs in the flow.
|
|
484
495
|
|
|
485
496
|
```python
|
|
@@ -499,11 +510,9 @@ With proxy, use `GeeTestTask` (same proxy fields as reCAPTCHA v2).
|
|
|
499
510
|
<sup>[API method description.](https://captcha-solver.com/en/docs/captcha-types#yandex-smartcaptcha)</sup>
|
|
500
511
|
|
|
501
512
|
Use this method to solve the token-based Yandex SmartCaptcha and obtain a token
|
|
502
|
-
for the widget on the target page. Use the
|
|
513
|
+
for the widget on the target page. Use the dedicated image method for image challenges.
|
|
503
514
|
|
|
504
|
-
`YandexSmartCaptchaTaskProxyless` / `YandexSmartCaptchaTask` -- token-based
|
|
505
|
-
challenge. For the image challenge instead, use `CoordinatesTask` with
|
|
506
|
-
[Coordinates](#coordinates-click-captcha) is available for generic click captchas.
|
|
515
|
+
`YandexSmartCaptchaTaskProxyless` / `YandexSmartCaptchaTask` -- token-based challenge.
|
|
507
516
|
|
|
508
517
|
| Parameter | Required | Description |
|
|
509
518
|
|---|---|---|
|
|
@@ -532,15 +541,45 @@ print(result["token"])
|
|
|
532
541
|
With proxy, use `YandexSmartCaptchaTask` (same proxy fields as reCAPTCHA v2,
|
|
533
542
|
plus the `https` option above).
|
|
534
543
|
|
|
544
|
+
#### Image challenge
|
|
545
|
+
|
|
546
|
+
Use `YandexSmartCaptchaImageTask` when SmartCaptcha shows a main image and a
|
|
547
|
+
separate strip indicating the symbols to click. The SDK sends API v2 type
|
|
548
|
+
`SmartCaptchaTask`; both images must be base64-encoded.
|
|
549
|
+
|
|
550
|
+
| Parameter | Required | Description |
|
|
551
|
+
|---|---|---|
|
|
552
|
+
| `image` | yes | Main captcha image, base64-encoded. |
|
|
553
|
+
| `imgInstructions` | yes | Click-order instruction image, base64-encoded. |
|
|
554
|
+
| `comment` | no | Optional text hint for the worker. |
|
|
555
|
+
|
|
556
|
+
**Response:** `coordinates` -- ordered `{"x": int, "y": int}` click positions.
|
|
557
|
+
|
|
558
|
+
```python
|
|
559
|
+
import base64
|
|
560
|
+
from captcha_solver_api import CaptchaClient
|
|
561
|
+
from captcha_solver_api.tasks import YandexSmartCaptchaImageTask
|
|
562
|
+
|
|
563
|
+
with open("captcha.png", "rb") as f:
|
|
564
|
+
image = base64.b64encode(f.read()).decode("utf-8")
|
|
565
|
+
with open("instructions.png", "rb") as f:
|
|
566
|
+
instructions = base64.b64encode(f.read()).decode("utf-8")
|
|
567
|
+
|
|
568
|
+
task = YandexSmartCaptchaImageTask(
|
|
569
|
+
image=image,
|
|
570
|
+
imgInstructions=instructions,
|
|
571
|
+
)
|
|
572
|
+
result = CaptchaClient("your_api_key").solve(task)
|
|
573
|
+
print(result["coordinates"])
|
|
574
|
+
```
|
|
575
|
+
|
|
535
576
|
### Coordinates (click captcha)
|
|
536
577
|
|
|
537
578
|
<sup>[API method description.](https://captcha-solver.com/en/docs/captcha-types#coordinates)</sup>
|
|
538
579
|
|
|
539
|
-
Use this method to identify points that a worker should click in
|
|
540
|
-
supports generic click captchas and the image version of Yandex SmartCaptcha.
|
|
580
|
+
Use this method to identify points that a worker should click in a generic image.
|
|
541
581
|
|
|
542
|
-
`CoordinatesTask`.
|
|
543
|
-
SmartCaptcha's image challenge. No proxy variant -- the image is submitted directly.
|
|
582
|
+
`CoordinatesTask`. No proxy variant -- the image is submitted directly.
|
|
544
583
|
|
|
545
584
|
| Parameter | Required | Description |
|
|
546
585
|
|---|---|---|
|
|
@@ -634,6 +673,16 @@ task lifetime. A local timeout does not cancel a task or mean that the API
|
|
|
634
673
|
failed to solve it. Use `create_task()` and keep its `task_id` if you need to
|
|
635
674
|
check the same task later; calling `solve()` again creates a new task.
|
|
636
675
|
|
|
676
|
+
While polling, `solve()` retries short network failures and HTTP timeouts of
|
|
677
|
+
`getTaskResult` on the next poll, so a brief outage does not lose an already
|
|
678
|
+
created task. After `poll_retries` (default 3) consecutive failures the error is
|
|
679
|
+
raised. API errors are not retried, and `createTask` is never retried because
|
|
680
|
+
that could create and pay for a second task. To change the limit:
|
|
681
|
+
|
|
682
|
+
```python
|
|
683
|
+
client.poll_retries = 5
|
|
684
|
+
```
|
|
685
|
+
|
|
637
686
|
### Worker language pool
|
|
638
687
|
|
|
639
688
|
Set a default `language_pool` once at construction instead of passing it to every call:
|
|
@@ -703,13 +752,26 @@ try:
|
|
|
703
752
|
except ValidationError as e:
|
|
704
753
|
print(f"Invalid argument: {e}")
|
|
705
754
|
except ApiError as e:
|
|
706
|
-
print(f"API error: {e.error_code} {e.error_description}")
|
|
707
|
-
except CaptchaTimeoutError:
|
|
708
|
-
print("Task timed out")
|
|
755
|
+
print(f"API error: {e.error_code} {e.error_description} (task {e.task_id})")
|
|
756
|
+
except CaptchaTimeoutError as e:
|
|
757
|
+
print(f"Task {e.task_id} timed out")
|
|
709
758
|
except NetworkError as e:
|
|
710
759
|
print(f"Network error: {e}")
|
|
711
760
|
```
|
|
712
761
|
|
|
762
|
+
Every SDK error has a `task_id` attribute. It is set when the error happens
|
|
763
|
+
after the task was created (while polling in `solve()` or in `get_task_result()`)
|
|
764
|
+
and is `None` otherwise. A polling timeout does not cancel the task, so you can
|
|
765
|
+
keep checking it:
|
|
766
|
+
|
|
767
|
+
```python
|
|
768
|
+
try:
|
|
769
|
+
result = client.solve(task)
|
|
770
|
+
except CaptchaTimeoutError as e:
|
|
771
|
+
if e.task_id is not None:
|
|
772
|
+
status = client.get_task_result(e.task_id)
|
|
773
|
+
```
|
|
774
|
+
|
|
713
775
|
`TimeoutError` is still exported as a deprecated alias of `CaptchaTimeoutError`.
|
|
714
776
|
Avoid importing it by name: it shadows Python's built-in `TimeoutError`.
|
|
715
777
|
|
|
@@ -718,16 +780,17 @@ Avoid importing it by name: it shadows Python's built-in `TimeoutError`.
|
|
|
718
780
|
See the dedicated [examples documentation](https://github.com/captcha-solver-api/python-sdk/blob/main/examples/README.md) for the full
|
|
719
781
|
sync/async example list, setup steps, expected results, and placeholder guidance.
|
|
720
782
|
|
|
721
|
-
- **Image/click captchas** (`image_to_text.py`, `coordinates.py
|
|
783
|
+
- **Image/click captchas** (`image_to_text.py`, `coordinates.py`,
|
|
784
|
+
`yandex_smartcaptcha_image.py`) run after installing the dependencies and setting a valid
|
|
722
785
|
`CAPTCHA_API_KEY` -- they read sample images bundled in
|
|
723
786
|
[examples/assets](https://github.com/captcha-solver-api/python-sdk/tree/main/examples/assets), no target page needed.
|
|
724
787
|
`python-dotenv` is optional: install it only if you want the scripts to load a `.env` file.
|
|
725
|
-
- **Token captchas** (`
|
|
726
|
-
`
|
|
788
|
+
- **Token captchas** (`recaptcha_v2_*.py`, `recaptcha_v2_enterprise_*.py`, `recaptcha_v3.py`,
|
|
789
|
+
`turnstile_*.py`, `yandex_smartcaptcha_*.py`, `geetest_v4_*.py`, `tencent_*.py`) use
|
|
727
790
|
placeholder values (`https://example.com/...`, `YOUR_WEBSITE_KEY`, `YOUR_APP_ID`,
|
|
728
791
|
`YOUR_CAPTCHA_ID`) -- replace these with the real values from your own target
|
|
729
792
|
page before running.
|
|
730
|
-
- **`
|
|
793
|
+
- **`geetest_v3_*.py`** additionally needs `challenge` fetched fresh for every
|
|
731
794
|
request -- it's single-use and expires within seconds, so it can't be
|
|
732
795
|
hardcoded into a static example. `"https://target-site.com/path/to/geetest/init"`
|
|
733
796
|
is a placeholder; replace it with a request to your own target's equivalent
|
|
@@ -743,6 +806,7 @@ export CAPTCHA_API_KEY=your_api_key
|
|
|
743
806
|
python examples/sync/balance.py
|
|
744
807
|
python examples/sync/image_to_text.py
|
|
745
808
|
python examples/sync/coordinates.py
|
|
809
|
+
python examples/sync/yandex_smartcaptcha_image.py
|
|
746
810
|
```
|
|
747
811
|
|
|
748
812
|
Live checks with real parameters have exercised all supported task types.
|
|
@@ -767,8 +831,8 @@ Full API reference: https://captcha-solver.com/en/docs/captcha-types
|
|
|
767
831
|
- [Selenium Python examples](https://github.com/captcha-solver-api/captcha-solver-selenium-python-examples)
|
|
768
832
|
- [JavaScript examples](https://github.com/captcha-solver-api/javascript-examples)
|
|
769
833
|
- [Tencent CAPTCHA automation examples](https://github.com/captcha-solver-api/How-to-Automate-Tencent-CAPTCHA)
|
|
770
|
-
- [Cloudflare Turnstile Puppeteer Demo](https://github.com/captcha-solver-api/cloudflare-turnstile-puppeteer-demo)
|
|
771
|
-
- [How to Automate Tencent CAPTCHA](https://captcha-solver.com/en/blog/how-to-automate-tencent-captcha)
|
|
834
|
+
- [Cloudflare Turnstile Puppeteer Demo](https://github.com/captcha-solver-api/cloudflare-turnstile-puppeteer-demo) - a working browser automation example for Cloudflare Turnstile.
|
|
835
|
+
- [How to Automate Tencent CAPTCHA](https://captcha-solver.com/en/blog/how-to-automate-tencent-captcha) - a step-by-step guide with Python and JavaScript SDK examples.
|
|
772
836
|
|
|
773
837
|
## License
|
|
774
838
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "1.1.0"
|
|
@@ -15,10 +15,12 @@ import httpx
|
|
|
15
15
|
from ._version import __version__
|
|
16
16
|
from .exceptions import (
|
|
17
17
|
ApiError,
|
|
18
|
+
CaptchaError,
|
|
18
19
|
CaptchaTimeoutError,
|
|
19
20
|
NetworkError,
|
|
20
21
|
ValidationError,
|
|
21
22
|
)
|
|
23
|
+
from .tasks import BaseTask
|
|
22
24
|
|
|
23
25
|
|
|
24
26
|
class AsyncCaptchaClient:
|
|
@@ -42,7 +44,7 @@ class AsyncCaptchaClient:
|
|
|
42
44
|
the account default. Can be overridden in `solve()` or `create_task()`.
|
|
43
45
|
|
|
44
46
|
Raises:
|
|
45
|
-
ValidationError: `client_key` is empty.
|
|
47
|
+
ValidationError: `client_key` is missing, empty, or whitespace.
|
|
46
48
|
|
|
47
49
|
Example:
|
|
48
50
|
from captcha_solver_api import AsyncCaptchaClient
|
|
@@ -57,6 +59,10 @@ class AsyncCaptchaClient:
|
|
|
57
59
|
token = solution["gRecaptchaResponse"]
|
|
58
60
|
"""
|
|
59
61
|
|
|
62
|
+
#: Consecutive `getTaskResult` network failures or HTTP timeouts that
|
|
63
|
+
#: `solve()` tolerates before raising. Each retry happens on the next poll.
|
|
64
|
+
poll_retries: int = 3
|
|
65
|
+
|
|
60
66
|
def __init__(
|
|
61
67
|
self,
|
|
62
68
|
client_key: str,
|
|
@@ -84,9 +90,9 @@ class AsyncCaptchaClient:
|
|
|
84
90
|
pool.
|
|
85
91
|
|
|
86
92
|
Raises:
|
|
87
|
-
ValidationError: `client_key` is empty.
|
|
93
|
+
ValidationError: `client_key` is missing, empty, or whitespace.
|
|
88
94
|
"""
|
|
89
|
-
if not client_key:
|
|
95
|
+
if not isinstance(client_key, str) or not client_key.strip():
|
|
90
96
|
raise ValidationError("client_key is required")
|
|
91
97
|
|
|
92
98
|
self.client_key = client_key
|
|
@@ -165,6 +171,8 @@ class AsyncCaptchaClient:
|
|
|
165
171
|
The numeric task ID to pass to `get_task_result()`.
|
|
166
172
|
|
|
167
173
|
Raises:
|
|
174
|
+
ValidationError: `task` is not a task object, or a required task
|
|
175
|
+
parameter is missing or empty. Raised before any request is sent.
|
|
168
176
|
ApiError: The API rejected the task or its parameters.
|
|
169
177
|
NetworkError: The request failed at the transport level.
|
|
170
178
|
CaptchaTimeoutError: The HTTP request timed out.
|
|
@@ -172,6 +180,9 @@ class AsyncCaptchaClient:
|
|
|
172
180
|
Example:
|
|
173
181
|
task_id = await client.create_task(task, language_pool="en")
|
|
174
182
|
"""
|
|
183
|
+
if not isinstance(task, BaseTask):
|
|
184
|
+
raise ValidationError("task must be an instance of BaseTask")
|
|
185
|
+
|
|
175
186
|
payload: Dict[str, Any] = {
|
|
176
187
|
"clientKey": self.client_key,
|
|
177
188
|
"task": task.to_dict(),
|
|
@@ -216,8 +227,12 @@ class AsyncCaptchaClient:
|
|
|
216
227
|
"clientKey": self.client_key,
|
|
217
228
|
"taskId": task_id,
|
|
218
229
|
}
|
|
219
|
-
|
|
220
|
-
|
|
230
|
+
try:
|
|
231
|
+
data = await self._request("getTaskResult", payload)
|
|
232
|
+
self._ensure_success(data)
|
|
233
|
+
except CaptchaError as exc:
|
|
234
|
+
exc.task_id = task_id
|
|
235
|
+
raise
|
|
221
236
|
return data
|
|
222
237
|
|
|
223
238
|
async def get_balance(self) -> float:
|
|
@@ -273,10 +288,17 @@ class AsyncCaptchaClient:
|
|
|
273
288
|
or the README's method reference.
|
|
274
289
|
|
|
275
290
|
Raises:
|
|
291
|
+
ValidationError: `task` is not a task object, or a required task
|
|
292
|
+
parameter is missing or empty. Raised before any request is sent.
|
|
276
293
|
ApiError: The API rejected the task or reported a solving error.
|
|
277
294
|
CaptchaTimeoutError: Polling exceeded its deadline or an HTTP request
|
|
278
295
|
timed out.
|
|
279
296
|
NetworkError: A request failed or the API returned an invalid response.
|
|
297
|
+
While polling, up to `poll_retries` consecutive network failures or
|
|
298
|
+
HTTP timeouts are retried on the next poll before this is raised.
|
|
299
|
+
|
|
300
|
+
Errors raised after the task is created have `task_id` set, so the
|
|
301
|
+
task can still be checked with `get_task_result(exc.task_id)`.
|
|
280
302
|
|
|
281
303
|
Example:
|
|
282
304
|
from captcha_solver_api.tasks import RecaptchaV2TaskProxyless
|
|
@@ -292,18 +314,35 @@ class AsyncCaptchaClient:
|
|
|
292
314
|
task_id = await self.create_task(task, language_pool=language_pool)
|
|
293
315
|
|
|
294
316
|
deadline = time.monotonic() + (timeout if timeout is not None else self.timeout)
|
|
317
|
+
poll_failures = 0
|
|
295
318
|
|
|
296
319
|
while time.monotonic() < deadline:
|
|
297
320
|
remaining = deadline - time.monotonic()
|
|
298
321
|
await asyncio.sleep(min(self.polling_interval, max(0, remaining)))
|
|
299
322
|
if time.monotonic() >= deadline:
|
|
300
323
|
break
|
|
301
|
-
|
|
324
|
+
try:
|
|
325
|
+
result = await self.get_task_result(task_id)
|
|
326
|
+
except (NetworkError, CaptchaTimeoutError):
|
|
327
|
+
# getTaskResult is safe to repeat: retry a short transport
|
|
328
|
+
# failure on the next poll instead of losing a paid task.
|
|
329
|
+
poll_failures += 1
|
|
330
|
+
if poll_failures > self.poll_retries:
|
|
331
|
+
raise
|
|
332
|
+
continue
|
|
333
|
+
poll_failures = 0
|
|
302
334
|
|
|
303
335
|
if result.get("status") == "ready":
|
|
304
336
|
solution = result["solution"]
|
|
305
337
|
if not isinstance(solution, dict):
|
|
306
|
-
raise NetworkError(
|
|
338
|
+
raise NetworkError(
|
|
339
|
+
"API returned a ready task without a solution object",
|
|
340
|
+
task_id=task_id,
|
|
341
|
+
)
|
|
307
342
|
return solution
|
|
308
343
|
|
|
309
|
-
raise CaptchaTimeoutError(
|
|
344
|
+
raise CaptchaTimeoutError(
|
|
345
|
+
f"Task {task_id} was not solved within the polling timeout. It may still "
|
|
346
|
+
f"be solved later: check it with get_task_result({task_id}).",
|
|
347
|
+
task_id=task_id,
|
|
348
|
+
)
|