captcha-solver-api 1.0.2__tar.gz → 1.0.4__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.
Files changed (20) hide show
  1. {captcha_solver_api-1.0.2 → captcha_solver_api-1.0.4}/PKG-INFO +84 -7
  2. {captcha_solver_api-1.0.2 → captcha_solver_api-1.0.4}/README.md +79 -6
  3. {captcha_solver_api-1.0.2 → captcha_solver_api-1.0.4}/captcha_solver_api/__init__.py +8 -8
  4. captcha_solver_api-1.0.4/captcha_solver_api/_version.py +1 -0
  5. {captcha_solver_api-1.0.2 → captcha_solver_api-1.0.4}/captcha_solver_api/async_client.py +75 -19
  6. {captcha_solver_api-1.0.2 → captcha_solver_api-1.0.4}/captcha_solver_api/client.py +68 -16
  7. captcha_solver_api-1.0.4/captcha_solver_api/exceptions.py +61 -0
  8. {captcha_solver_api-1.0.2 → captcha_solver_api-1.0.4}/captcha_solver_api/tasks.py +227 -4
  9. {captcha_solver_api-1.0.2 → captcha_solver_api-1.0.4}/captcha_solver_api.egg-info/PKG-INFO +84 -7
  10. {captcha_solver_api-1.0.2 → captcha_solver_api-1.0.4}/captcha_solver_api.egg-info/requires.txt +4 -0
  11. {captcha_solver_api-1.0.2 → captcha_solver_api-1.0.4}/pyproject.toml +35 -0
  12. {captcha_solver_api-1.0.2 → captcha_solver_api-1.0.4}/tests/test_polling.py +29 -27
  13. captcha_solver_api-1.0.2/captcha_solver_api/_version.py +0 -1
  14. captcha_solver_api-1.0.2/captcha_solver_api/exceptions.py +0 -41
  15. {captcha_solver_api-1.0.2 → captcha_solver_api-1.0.4}/LICENSE.md +0 -0
  16. {captcha_solver_api-1.0.2 → captcha_solver_api-1.0.4}/captcha_solver_api/py.typed +0 -0
  17. {captcha_solver_api-1.0.2 → captcha_solver_api-1.0.4}/captcha_solver_api.egg-info/SOURCES.txt +0 -0
  18. {captcha_solver_api-1.0.2 → captcha_solver_api-1.0.4}/captcha_solver_api.egg-info/dependency_links.txt +0 -0
  19. {captcha_solver_api-1.0.2 → captcha_solver_api-1.0.4}/captcha_solver_api.egg-info/top_level.txt +0 -0
  20. {captcha_solver_api-1.0.2 → captcha_solver_api-1.0.4}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: captcha-solver-api
3
- Version: 1.0.2
3
+ Version: 1.0.4
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
@@ -32,11 +32,27 @@ Requires-Dist: pytest>=7; extra == "dev"
32
32
  Requires-Dist: pytest-asyncio>=0.21; extra == "dev"
33
33
  Requires-Dist: pytest-mock>=3; extra == "dev"
34
34
  Requires-Dist: python-dotenv>=1.0; extra == "dev"
35
+ Requires-Dist: ruff>=0.6; extra == "dev"
36
+ Requires-Dist: mypy>=1.10; extra == "dev"
37
+ Requires-Dist: types-requests>=2.28; extra == "dev"
38
+ Requires-Dist: pytest-cov>=4; extra == "dev"
35
39
  Dynamic: license-file
36
40
 
37
41
  # Captcha Solver Python SDK
38
42
 
39
- ![python-sdk-banner](https://raw.githubusercontent.com/captcha-solver-api/python-sdk/main/assets/repo-banner-python.png)
43
+ ![python-sdk-banner](https://raw.githubusercontent.com/captcha-solver-api/python-sdk/main/assets/repo-banner-python.png?v=09a4ebb)
44
+
45
+ [![PyPI](https://img.shields.io/pypi/v/captcha-solver-api?logo=pypi&logoColor=white)](https://pypi.org/project/captcha-solver-api/)
46
+ [![Python](https://img.shields.io/pypi/pyversions/captcha-solver-api?logo=python&logoColor=white)](https://pypi.org/project/captcha-solver-api/)
47
+ [![Downloads](https://img.shields.io/pepy/dt/captcha-solver-api)](https://pepy.tech/project/captcha-solver-api)
48
+ [![Tests](https://github.com/captcha-solver-api/python-sdk/actions/workflows/tests.yml/badge.svg)](https://github.com/captcha-solver-api/python-sdk/actions/workflows/tests.yml)
49
+ [![Coverage](https://img.shields.io/endpoint?url=https://gist.githubusercontent.com/dzmitry-duboyski/77b084ed0d46c740183f89ec66af8a95/raw/python-sdk-coverage.json)](https://github.com/captcha-solver-api/python-sdk/actions/workflows/tests.yml)
50
+ [![Typed](https://img.shields.io/badge/typing-typed-blue)](https://github.com/captcha-solver-api/python-sdk/blob/main/captcha_solver_api/py.typed)
51
+ [![License: MIT](https://img.shields.io/badge/license-MIT-green)](https://github.com/captcha-solver-api/python-sdk/blob/main/LICENSE.md)
52
+ [![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff)
53
+ [![Checked with mypy](https://www.mypy-lang.org/static/mypy_badge.svg)](https://mypy-lang.org/)
54
+ [![GitHub Release](https://img.shields.io/github/v/release/captcha-solver-api/python-sdk)](https://github.com/captcha-solver-api/python-sdk/releases)
55
+ [![JavaScript SDK](https://img.shields.io/badge/also_available-JavaScript_SDK-f7df1e?logo=javascript&logoColor=black)](https://github.com/captcha-solver-api/javascript-sdk)
40
56
 
41
57
  Official Python SDK for the Captcha Solver API. Solve reCAPTCHA v2/v3, Cloudflare Turnstile, GeeTest, Yandex SmartCaptcha, Tencent, and image/click captchas with a single method call -- sync or async.
42
58
 
@@ -45,8 +61,10 @@ Full API reference (all endpoints, error codes, captcha-type details): **https:/
45
61
  ## Table of Contents
46
62
 
47
63
  - [Installation](#installation)
64
+ - [Editor documentation](#editor-documentation)
48
65
  - [Configuration](#configuration)
49
66
  - [Quick Start](#quick-start)
67
+ - [Build Faster with AI](#build-faster-with-ai)
50
68
  - [Supported CAPTCHA Types](#supported-captcha-types)
51
69
  - [Client Reference](#client-reference)
52
70
  - [CaptchaClient(...)](#captchaclient)
@@ -74,6 +92,7 @@ Full API reference (all endpoints, error codes, captcha-type details): **https:/
74
92
  - [Running the examples](#running-the-examples)
75
93
  - [Requirements](#requirements)
76
94
  - [API Documentation](#api-documentation)
95
+ - [Useful Links](#useful-links)
77
96
  - [License](#license)
78
97
 
79
98
  ## Installation
@@ -88,6 +107,31 @@ Or install the latest version from GitHub:
88
107
  pip install git+https://github.com/captcha-solver-api/python-sdk.git
89
108
  ```
90
109
 
110
+ ## Editor documentation
111
+
112
+ The SDK includes Python docstrings (the equivalent of JSDoc), type annotations,
113
+ and a `py.typed` marker in the installed package. With Python language support
114
+ enabled in your editor, hover over `CaptchaClient`, `AsyncCaptchaClient`, their
115
+ methods, or a task class such as `RecaptchaV2TaskProxyless` to read the documentation.
116
+ Signature help shows argument names, types, and defaults while you type a call.
117
+
118
+ Docstrings describe parameters, solution fields, exceptions, and usage examples.
119
+ Task examples assume an existing synchronous `client`; with `AsyncCaptchaClient`,
120
+ use `solution = await client.solve(task)` instead. Async snippets run inside an
121
+ `async def` function. In VS Code, select the Python interpreter where the SDK is
122
+ installed and enable the Python and Pylance extensions. In PyCharm, use Quick
123
+ Documentation. The exact presentation depends on the editor.
124
+
125
+ You can also read the same documentation without an editor:
126
+
127
+ ```python
128
+ from captcha_solver_api import CaptchaClient
129
+ from captcha_solver_api.tasks import RecaptchaV2TaskProxyless
130
+
131
+ help(CaptchaClient.solve)
132
+ help(RecaptchaV2TaskProxyless)
133
+ ```
134
+
91
135
  ## Configuration
92
136
 
93
137
  The client always takes the API key as an explicit argument -- it does not read
@@ -124,6 +168,23 @@ result = client.solve(task)
124
168
  print(result["gRecaptchaResponse"])
125
169
  ```
126
170
 
171
+ ## Build Faster with AI
172
+
173
+ Use our [`llms.txt`](https://captcha-solver.com/llms.txt) as context when asking an
174
+ AI assistant to build or update your integration. It contains the current API
175
+ format, supported task parameters, SDK installation instructions, solution
176
+ fields, and error codes in one file.
177
+
178
+ Copy this prompt and add a description of the page and CAPTCHA you need to
179
+ handle:
180
+
181
+ ```text
182
+ Read https://captcha-solver.com/llms.txt and use the Captcha Solver Python SDK.
183
+ Write a complete integration for this task: [describe your task here].
184
+ Use the documented task parameters and show how to apply the returned solution
185
+ on the target page.
186
+ ```
187
+
127
188
  ## Supported CAPTCHA Types
128
189
 
129
190
  | Type | Proxyless | With Proxy |
@@ -353,12 +414,13 @@ that the target page expects in `cf-turnstile-response`.
353
414
  | `action` | no | Value of the widget's `data-action` attribute, if set. |
354
415
  | `data` | no | Custom payload from the widget's `data-cdata` attribute, if set. |
355
416
  | `pagedata` | no | Value of the `chlPageData` parameter, needed for some Cloudflare challenge pages beyond the basic widget. |
356
- | `userAgent` | no | User-Agent to solve with -- the returned token is tied to it, submit with the same one. |
417
+ | `userAgent` | no | Current browser User-Agent. Pass it for Cloudflare Challenge pages; it is not needed for a standalone widget. |
357
418
 
358
419
  **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.
420
+ Challenge pages, pass `action`, `data`, `pagedata`, and the current browser
421
+ `userAgent` in the task. The solution also contains `userAgent`; switch the
422
+ browser or HTTP client to this returned value before invoking the callback with
423
+ the token. The API field is spelled `pagedata`, all lowercase.
362
424
 
363
425
  ```python
364
426
  from captcha_solver_api import CaptchaClient
@@ -366,10 +428,15 @@ from captcha_solver_api.tasks import TurnstileTaskProxyless
366
428
  client = CaptchaClient("your_api_key")
367
429
  task = TurnstileTaskProxyless(
368
430
  websiteURL="https://example.com/login",
369
- websiteKey="YOUR_WEBSITE_KEY"
431
+ websiteKey="YOUR_WEBSITE_KEY",
432
+ action="managed",
433
+ data="INTERCEPTED_CDATA",
434
+ pagedata="INTERCEPTED_CHL_PAGE_DATA",
435
+ userAgent="CURRENT_BROWSER_USER_AGENT",
370
436
  )
371
437
  result = client.solve(task)
372
438
  print(result["token"])
439
+ print(result.get("userAgent"))
373
440
  ```
374
441
 
375
442
  With proxy, use `TurnstileTask` (same proxy fields as reCAPTCHA v2).
@@ -733,6 +800,16 @@ page and session parameters.
733
800
 
734
801
  Full API reference: https://captcha-solver.com/en/docs/captcha-types
735
802
 
803
+ ## Useful Links
804
+
805
+ - [JavaScript SDK](https://github.com/captcha-solver-api/javascript-sdk)
806
+ - [Python examples](https://github.com/captcha-solver-api/python-examples)
807
+ - [Selenium Python examples](https://github.com/captcha-solver-api/captcha-solver-selenium-python-examples)
808
+ - [JavaScript examples](https://github.com/captcha-solver-api/javascript-examples)
809
+ - [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) — a working browser automation example for Cloudflare Turnstile.
811
+ - [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
+
736
813
  ## License
737
814
 
738
815
  This project is licensed under the MIT License. See [LICENSE.md](https://github.com/captcha-solver-api/python-sdk/blob/main/LICENSE.md) for details.
@@ -1,6 +1,18 @@
1
1
  # Captcha Solver Python SDK
2
2
 
3
- ![python-sdk-banner](https://raw.githubusercontent.com/captcha-solver-api/python-sdk/main/assets/repo-banner-python.png)
3
+ ![python-sdk-banner](https://raw.githubusercontent.com/captcha-solver-api/python-sdk/main/assets/repo-banner-python.png?v=09a4ebb)
4
+
5
+ [![PyPI](https://img.shields.io/pypi/v/captcha-solver-api?logo=pypi&logoColor=white)](https://pypi.org/project/captcha-solver-api/)
6
+ [![Python](https://img.shields.io/pypi/pyversions/captcha-solver-api?logo=python&logoColor=white)](https://pypi.org/project/captcha-solver-api/)
7
+ [![Downloads](https://img.shields.io/pepy/dt/captcha-solver-api)](https://pepy.tech/project/captcha-solver-api)
8
+ [![Tests](https://github.com/captcha-solver-api/python-sdk/actions/workflows/tests.yml/badge.svg)](https://github.com/captcha-solver-api/python-sdk/actions/workflows/tests.yml)
9
+ [![Coverage](https://img.shields.io/endpoint?url=https://gist.githubusercontent.com/dzmitry-duboyski/77b084ed0d46c740183f89ec66af8a95/raw/python-sdk-coverage.json)](https://github.com/captcha-solver-api/python-sdk/actions/workflows/tests.yml)
10
+ [![Typed](https://img.shields.io/badge/typing-typed-blue)](https://github.com/captcha-solver-api/python-sdk/blob/main/captcha_solver_api/py.typed)
11
+ [![License: MIT](https://img.shields.io/badge/license-MIT-green)](https://github.com/captcha-solver-api/python-sdk/blob/main/LICENSE.md)
12
+ [![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff)
13
+ [![Checked with mypy](https://www.mypy-lang.org/static/mypy_badge.svg)](https://mypy-lang.org/)
14
+ [![GitHub Release](https://img.shields.io/github/v/release/captcha-solver-api/python-sdk)](https://github.com/captcha-solver-api/python-sdk/releases)
15
+ [![JavaScript SDK](https://img.shields.io/badge/also_available-JavaScript_SDK-f7df1e?logo=javascript&logoColor=black)](https://github.com/captcha-solver-api/javascript-sdk)
4
16
 
5
17
  Official Python SDK for the Captcha Solver API. Solve reCAPTCHA v2/v3, Cloudflare Turnstile, GeeTest, Yandex SmartCaptcha, Tencent, and image/click captchas with a single method call -- sync or async.
6
18
 
@@ -9,8 +21,10 @@ Full API reference (all endpoints, error codes, captcha-type details): **https:/
9
21
  ## Table of Contents
10
22
 
11
23
  - [Installation](#installation)
24
+ - [Editor documentation](#editor-documentation)
12
25
  - [Configuration](#configuration)
13
26
  - [Quick Start](#quick-start)
27
+ - [Build Faster with AI](#build-faster-with-ai)
14
28
  - [Supported CAPTCHA Types](#supported-captcha-types)
15
29
  - [Client Reference](#client-reference)
16
30
  - [CaptchaClient(...)](#captchaclient)
@@ -38,6 +52,7 @@ Full API reference (all endpoints, error codes, captcha-type details): **https:/
38
52
  - [Running the examples](#running-the-examples)
39
53
  - [Requirements](#requirements)
40
54
  - [API Documentation](#api-documentation)
55
+ - [Useful Links](#useful-links)
41
56
  - [License](#license)
42
57
 
43
58
  ## Installation
@@ -52,6 +67,31 @@ Or install the latest version from GitHub:
52
67
  pip install git+https://github.com/captcha-solver-api/python-sdk.git
53
68
  ```
54
69
 
70
+ ## Editor documentation
71
+
72
+ The SDK includes Python docstrings (the equivalent of JSDoc), type annotations,
73
+ and a `py.typed` marker in the installed package. With Python language support
74
+ enabled in your editor, hover over `CaptchaClient`, `AsyncCaptchaClient`, their
75
+ methods, or a task class such as `RecaptchaV2TaskProxyless` to read the documentation.
76
+ Signature help shows argument names, types, and defaults while you type a call.
77
+
78
+ Docstrings describe parameters, solution fields, exceptions, and usage examples.
79
+ Task examples assume an existing synchronous `client`; with `AsyncCaptchaClient`,
80
+ use `solution = await client.solve(task)` instead. Async snippets run inside an
81
+ `async def` function. In VS Code, select the Python interpreter where the SDK is
82
+ installed and enable the Python and Pylance extensions. In PyCharm, use Quick
83
+ Documentation. The exact presentation depends on the editor.
84
+
85
+ You can also read the same documentation without an editor:
86
+
87
+ ```python
88
+ from captcha_solver_api import CaptchaClient
89
+ from captcha_solver_api.tasks import RecaptchaV2TaskProxyless
90
+
91
+ help(CaptchaClient.solve)
92
+ help(RecaptchaV2TaskProxyless)
93
+ ```
94
+
55
95
  ## Configuration
56
96
 
57
97
  The client always takes the API key as an explicit argument -- it does not read
@@ -88,6 +128,23 @@ result = client.solve(task)
88
128
  print(result["gRecaptchaResponse"])
89
129
  ```
90
130
 
131
+ ## Build Faster with AI
132
+
133
+ Use our [`llms.txt`](https://captcha-solver.com/llms.txt) as context when asking an
134
+ AI assistant to build or update your integration. It contains the current API
135
+ format, supported task parameters, SDK installation instructions, solution
136
+ fields, and error codes in one file.
137
+
138
+ Copy this prompt and add a description of the page and CAPTCHA you need to
139
+ handle:
140
+
141
+ ```text
142
+ Read https://captcha-solver.com/llms.txt and use the Captcha Solver Python SDK.
143
+ Write a complete integration for this task: [describe your task here].
144
+ Use the documented task parameters and show how to apply the returned solution
145
+ on the target page.
146
+ ```
147
+
91
148
  ## Supported CAPTCHA Types
92
149
 
93
150
  | Type | Proxyless | With Proxy |
@@ -317,12 +374,13 @@ that the target page expects in `cf-turnstile-response`.
317
374
  | `action` | no | Value of the widget's `data-action` attribute, if set. |
318
375
  | `data` | no | Custom payload from the widget's `data-cdata` attribute, if set. |
319
376
  | `pagedata` | no | Value of the `chlPageData` parameter, needed for some Cloudflare challenge pages beyond the basic widget. |
320
- | `userAgent` | no | User-Agent to solve with -- the returned token is tied to it, submit with the same one. |
377
+ | `userAgent` | no | Current browser User-Agent. Pass it for Cloudflare Challenge pages; it is not needed for a standalone widget. |
321
378
 
322
379
  **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.
380
+ Challenge pages, pass `action`, `data`, `pagedata`, and the current browser
381
+ `userAgent` in the task. The solution also contains `userAgent`; switch the
382
+ browser or HTTP client to this returned value before invoking the callback with
383
+ the token. The API field is spelled `pagedata`, all lowercase.
326
384
 
327
385
  ```python
328
386
  from captcha_solver_api import CaptchaClient
@@ -330,10 +388,15 @@ from captcha_solver_api.tasks import TurnstileTaskProxyless
330
388
  client = CaptchaClient("your_api_key")
331
389
  task = TurnstileTaskProxyless(
332
390
  websiteURL="https://example.com/login",
333
- websiteKey="YOUR_WEBSITE_KEY"
391
+ websiteKey="YOUR_WEBSITE_KEY",
392
+ action="managed",
393
+ data="INTERCEPTED_CDATA",
394
+ pagedata="INTERCEPTED_CHL_PAGE_DATA",
395
+ userAgent="CURRENT_BROWSER_USER_AGENT",
334
396
  )
335
397
  result = client.solve(task)
336
398
  print(result["token"])
399
+ print(result.get("userAgent"))
337
400
  ```
338
401
 
339
402
  With proxy, use `TurnstileTask` (same proxy fields as reCAPTCHA v2).
@@ -697,6 +760,16 @@ page and session parameters.
697
760
 
698
761
  Full API reference: https://captcha-solver.com/en/docs/captcha-types
699
762
 
763
+ ## Useful Links
764
+
765
+ - [JavaScript SDK](https://github.com/captcha-solver-api/javascript-sdk)
766
+ - [Python examples](https://github.com/captcha-solver-api/python-examples)
767
+ - [Selenium Python examples](https://github.com/captcha-solver-api/captcha-solver-selenium-python-examples)
768
+ - [JavaScript examples](https://github.com/captcha-solver-api/javascript-examples)
769
+ - [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) — a working browser automation example for Cloudflare Turnstile.
771
+ - [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
+
700
773
  ## License
701
774
 
702
775
  This project is licensed under the MIT License. See [LICENSE.md](https://github.com/captcha-solver-api/python-sdk/blob/main/LICENSE.md) for details.
@@ -13,26 +13,26 @@ Example:
13
13
  result = client.solve(task)
14
14
  """
15
15
 
16
- from .client import CaptchaClient
16
+ from ._version import __version__
17
17
  from .async_client import AsyncCaptchaClient
18
+ from .client import CaptchaClient
18
19
  from .exceptions import (
19
- CaptchaError,
20
20
  ApiError,
21
- NetworkError,
21
+ CaptchaError,
22
22
  CaptchaTimeoutError,
23
+ NetworkError,
23
24
  TimeoutError,
24
25
  ValidationError,
25
26
  )
26
27
 
27
- from ._version import __version__
28
-
29
28
  __all__ = [
30
- "CaptchaClient",
29
+ "ApiError",
31
30
  "AsyncCaptchaClient",
31
+ "CaptchaClient",
32
32
  "CaptchaError",
33
- "ApiError",
34
- "NetworkError",
35
33
  "CaptchaTimeoutError",
34
+ "NetworkError",
36
35
  "TimeoutError",
37
36
  "ValidationError",
37
+ "__version__",
38
38
  ]
@@ -0,0 +1 @@
1
+ __version__ = "1.0.4"
@@ -15,26 +15,46 @@ import httpx
15
15
  from ._version import __version__
16
16
  from .exceptions import (
17
17
  ApiError,
18
- NetworkError,
19
18
  CaptchaTimeoutError,
19
+ NetworkError,
20
20
  ValidationError,
21
21
  )
22
22
 
23
23
 
24
24
  class AsyncCaptchaClient:
25
- """
26
- Async client for interacting with the Captcha Solver API.
25
+ """Asynchronous client for submitting tasks and awaiting CAPTCHA solutions.
27
26
 
28
27
  Holds a single, reused `httpx.AsyncClient` connection pool for the
29
28
  lifetime of the instance (created once, not per request), so repeated
30
29
  calls -- especially the `getTaskResult` polling inside `solve()` --
31
30
  reuse the same keep-alive connection instead of paying a fresh TCP/TLS
32
31
  handshake every time. Close it with `aclose()` when you're done, or use
33
- it as an async context manager:
32
+ it as an async context manager.
33
+
34
+ Args:
35
+ client_key: Your Captcha Solver API key. Must not be empty.
36
+ base_url: API base URL. Defaults to `https://api.captcha-solver.com`.
37
+ timeout: Default polling timeout in seconds, starting after task creation.
38
+ Defaults to 120. Each HTTP request has a separate 30-second timeout.
39
+ polling_interval: Seconds before the first poll and between polls.
40
+ Defaults to 10. Waiting does not block the event loop.
41
+ language_pool: Default worker pool, e.g. `"en"` or `"ru"`. `None` uses
42
+ the account default. Can be overridden in `solve()` or `create_task()`.
43
+
44
+ Raises:
45
+ ValidationError: `client_key` is empty.
34
46
 
35
47
  Example:
48
+ from captcha_solver_api import AsyncCaptchaClient
49
+ from captcha_solver_api.tasks import RecaptchaV2TaskProxyless
50
+
51
+ task = RecaptchaV2TaskProxyless(
52
+ websiteURL="https://example.com",
53
+ websiteKey="SITE_KEY",
54
+ )
36
55
  async with AsyncCaptchaClient("YOUR_API_KEY") as client:
37
- result = await client.solve(task)
56
+ solution = await client.solve(task)
57
+ token = solution["gRecaptchaResponse"]
38
58
  """
39
59
 
40
60
  def __init__(
@@ -45,13 +65,16 @@ class AsyncCaptchaClient:
45
65
  polling_interval: int = 10,
46
66
  language_pool: Optional[str] = None,
47
67
  ) -> None:
48
- """
68
+ """Create an async client with a reusable HTTP connection pool.
69
+
49
70
  Args:
50
71
  client_key: Your Captcha Solver API key.
51
72
  base_url: API base URL. Override only for self-hosted or staging
52
73
  deployments.
53
- timeout: Default max seconds `solve()` waits for a solution before
54
- raising `CaptchaTimeoutError`. Can be overridden per call.
74
+ timeout: Default polling timeout in seconds, starting after task
75
+ creation. Defaults to 120 and can be overridden per `solve()` call.
76
+ Each HTTP request has a separate 30-second timeout, so this is
77
+ not a strict deadline for the entire call.
55
78
  polling_interval: Seconds to wait before the first `getTaskResult`
56
79
  poll and between subsequent polls inside `solve()`. Defaults
57
80
  to 10 seconds.
@@ -87,7 +110,7 @@ class AsyncCaptchaClient:
87
110
  (`async with AsyncCaptchaClient(...) as c:`) to have it closed automatically."""
88
111
  await self._client.aclose()
89
112
 
90
- async def __aenter__(self) -> "AsyncCaptchaClient":
113
+ async def __aenter__(self) -> AsyncCaptchaClient:
91
114
  return self
92
115
 
93
116
  async def __aexit__(self, *exc_info: Any) -> None:
@@ -113,6 +136,8 @@ class AsyncCaptchaClient:
113
136
  except ValueError as exc:
114
137
  raise NetworkError(f"Non-JSON response from API: {response.text[:200]!r}") from exc
115
138
 
139
+ if not isinstance(data, dict):
140
+ raise NetworkError(f"Unexpected API response shape: {type(data).__name__}")
116
141
  return data
117
142
 
118
143
  def _ensure_success(self, data: Dict[str, Any]) -> None:
@@ -143,6 +168,9 @@ class AsyncCaptchaClient:
143
168
  ApiError: The API rejected the task or its parameters.
144
169
  NetworkError: The request failed at the transport level.
145
170
  CaptchaTimeoutError: The HTTP request timed out.
171
+
172
+ Example:
173
+ task_id = await client.create_task(task, language_pool="en")
146
174
  """
147
175
  payload: Dict[str, Any] = {
148
176
  "clientKey": self.client_key,
@@ -154,7 +182,7 @@ class AsyncCaptchaClient:
154
182
 
155
183
  data = await self._request("createTask", payload)
156
184
  self._ensure_success(data)
157
- return data["taskId"]
185
+ return int(data["taskId"])
158
186
 
159
187
  async def get_task_result(self, task_id: int) -> Dict[str, Any]:
160
188
  """Fetch the current status of a previously submitted task.
@@ -169,13 +197,20 @@ class AsyncCaptchaClient:
169
197
  task_id: The ID returned by `create_task()`.
170
198
 
171
199
  Returns:
172
- The raw API response with `status`; ready responses also contain a
173
- solution dictionary.
200
+ The raw API response with `status` (`"processing"` or `"ready"`).
201
+ Ready responses also contain a `solution` dict, e.g.
202
+ `{"gRecaptchaResponse": "..."}` for reCAPTCHA or `{"text": "..."}`
203
+ for `ImageToTextTask`.
174
204
 
175
205
  Raises:
176
206
  ApiError: The API reports an error for the task.
177
207
  NetworkError: The request failed at the transport level.
178
208
  CaptchaTimeoutError: The HTTP request timed out.
209
+
210
+ Example:
211
+ result = await client.get_task_result(task_id)
212
+ if result["status"] == "ready":
213
+ solution = result["solution"]
179
214
  """
180
215
  payload = {
181
216
  "clientKey": self.client_key,
@@ -199,11 +234,14 @@ class AsyncCaptchaClient:
199
234
  ApiError: The API key is invalid or the account cannot be resolved.
200
235
  NetworkError: The request failed at the transport level.
201
236
  CaptchaTimeoutError: The HTTP request timed out.
237
+
238
+ Example:
239
+ balance = await client.get_balance()
202
240
  """
203
241
  payload = {"clientKey": self.client_key}
204
242
  data = await self._request("getBalance", payload)
205
243
  self._ensure_success(data)
206
- return data["balance"]
244
+ return float(data["balance"])
207
245
 
208
246
  async def solve(
209
247
  self,
@@ -224,16 +262,31 @@ class AsyncCaptchaClient:
224
262
  task: A task object from `captcha_solver_api.tasks`.
225
263
  language_pool: Optional worker pool selector. Falls back to the
226
264
  client's configured pool.
227
- timeout: Maximum polling time for this call, in seconds. Overrides
228
- the client's default timeout.
265
+ timeout: Polling timeout in seconds, starting after task creation.
266
+ `None` uses the client's default (120 unless configured otherwise).
267
+ Each HTTP request has a separate 30-second timeout, so this is
268
+ not a strict deadline for the entire call.
229
269
 
230
270
  Returns:
231
- The solution dictionary once the task status becomes `"ready"`.
271
+ The `solution` dict once `status` is `"ready"`. Its shape depends on
272
+ the task type -- see the per-type docstrings in `captcha_solver_api.tasks`
273
+ or the README's method reference.
232
274
 
233
275
  Raises:
234
276
  ApiError: The API rejected the task or reported a solving error.
235
- CaptchaTimeoutError: No solution was ready before the deadline.
236
- NetworkError: A request failed at the transport level.
277
+ CaptchaTimeoutError: Polling exceeded its deadline or an HTTP request
278
+ timed out.
279
+ NetworkError: A request failed or the API returned an invalid response.
280
+
281
+ Example:
282
+ from captcha_solver_api.tasks import RecaptchaV2TaskProxyless
283
+
284
+ task = RecaptchaV2TaskProxyless(
285
+ websiteURL="https://example.com",
286
+ websiteKey="SITE_KEY",
287
+ )
288
+ solution = await client.solve(task, timeout=180)
289
+ token = solution["gRecaptchaResponse"]
237
290
  """
238
291
 
239
292
  task_id = await self.create_task(task, language_pool=language_pool)
@@ -248,6 +301,9 @@ class AsyncCaptchaClient:
248
301
  result = await self.get_task_result(task_id)
249
302
 
250
303
  if result.get("status") == "ready":
251
- return result["solution"]
304
+ solution = result["solution"]
305
+ if not isinstance(solution, dict):
306
+ raise NetworkError("API returned a ready task without a solution object")
307
+ return solution
252
308
 
253
309
  raise CaptchaTimeoutError("Task solving timed out.")