python3-capsolver 1.1.1__py3-none-any.whl → 1.2.1__py3-none-any.whl

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.
@@ -1 +1 @@
1
- __version__ = "1.1.1"
1
+ __version__ = "1.2.1"
@@ -30,6 +30,8 @@ class AIOCaptchaInstrument(CaptchaInstrumentBase):
30
30
 
31
31
  # if task created and already ready - return result
32
32
  if self.created_task_data.errorId == 0:
33
+ if str(self.created_task_data.status).lower() == ResponseStatusEnm.Ready.value:
34
+ return self.created_task_data.to_dict()
33
35
  return (await self.__get_result()).to_dict()
34
36
  else:
35
37
  self.created_task_data.status = ResponseStatusEnm.Failed
@@ -72,7 +74,10 @@ class AIOCaptchaInstrument(CaptchaInstrumentBase):
72
74
  ) as resp:
73
75
  if resp.status in VALID_STATUS_CODES:
74
76
  result_data = CaptchaResponseSer(**await resp.json())
75
- if result_data.status in (ResponseStatusEnm.Ready, ResponseStatusEnm.Failed):
77
+ if result_data.status in (
78
+ ResponseStatusEnm.Ready,
79
+ ResponseStatusEnm.Failed,
80
+ ):
76
81
  # if captcha ready\failed or have unknown status - return exist data
77
82
  return result_data
78
83
  else:
@@ -90,10 +95,12 @@ class AIOCaptchaInstrument(CaptchaInstrumentBase):
90
95
  self.result.errorDescription = self.CAPTCHA_UNSOLVABLE_DESCRIPTION
91
96
  self.result.taskId = self.created_task_data.taskId
92
97
  self.result.status = ResponseStatusEnm.Failed
98
+ return self.result
93
99
 
94
100
  @staticmethod
95
101
  async def send_post_request(
96
- payload: Optional[dict] = None, url_postfix: EndpointPostfixEnm = EndpointPostfixEnm.GET_BALANCE
102
+ payload: Optional[dict] = None,
103
+ url_postfix: EndpointPostfixEnm = EndpointPostfixEnm.GET_BALANCE,
97
104
  ) -> dict:
98
105
  """
99
106
  Function send ASYNC request to service and wait for result
@@ -83,7 +83,10 @@ class FileInstrument:
83
83
  async for attempt in ASYNC_RETRIES:
84
84
  with attempt:
85
85
  async with session.get(url=url, **kwargs) as resp:
86
- return await resp.content.read()
86
+ if resp.status == 200:
87
+ return await resp.content.read()
88
+ return b""
89
+ return b""
87
90
 
88
91
  def file_processing(
89
92
  self,
@@ -1,12 +1,18 @@
1
1
  from enum import Enum
2
- from typing import Any, Dict, Literal, Optional
2
+ from typing import Any, Dict, Union, Optional
3
3
 
4
4
  from msgspec import Struct
5
5
 
6
6
  from .enum import ResponseStatusEnm
7
7
  from .const import APP_ID
8
8
 
9
- __all__ = ("PostRequestSer", "TaskSer", "RequestCreateTaskSer", "CaptchaResponseSer", "RequestGetTaskResultSer")
9
+ __all__ = (
10
+ "PostRequestSer",
11
+ "TaskSer",
12
+ "RequestCreateTaskSer",
13
+ "CaptchaResponseSer",
14
+ "RequestGetTaskResultSer",
15
+ )
10
16
 
11
17
 
12
18
  class MyBaseModel(Struct):
@@ -36,7 +42,7 @@ class TaskSer(MyBaseModel):
36
42
 
37
43
 
38
44
  class RequestCreateTaskSer(PostRequestSer):
39
- appId: Literal[APP_ID] = APP_ID
45
+ appId: str = APP_ID
40
46
 
41
47
 
42
48
  class RequestGetTaskResultSer(MyBaseModel):
@@ -58,5 +64,5 @@ class ResponseSer(MyBaseModel):
58
64
 
59
65
  class CaptchaResponseSer(ResponseSer):
60
66
  taskId: Optional[str] = None
61
- status: ResponseStatusEnm = ResponseStatusEnm.Processing
67
+ status: Union[ResponseStatusEnm, str] = ResponseStatusEnm.Processing
62
68
  solution: Optional[Dict[str, Any]] = None
@@ -24,6 +24,7 @@ class SIOCaptchaInstrument(CaptchaInstrumentBase):
24
24
  super().__init__()
25
25
  self.captcha_params = captcha_params
26
26
  self.created_task_data = CaptchaResponseSer
27
+
27
28
  # prepare session
28
29
  self.session = requests.Session()
29
30
  self.session.mount("http://", HTTPAdapter(max_retries=RETRIES))
@@ -37,6 +38,8 @@ class SIOCaptchaInstrument(CaptchaInstrumentBase):
37
38
 
38
39
  # if task created and ready - return result
39
40
  if self.created_task_data.errorId == 0:
41
+ if str(self.created_task_data.status).lower() == ResponseStatusEnm.Ready.value:
42
+ return self.created_task_data.to_dict()
40
43
  return self.__get_result().to_dict()
41
44
  else:
42
45
  self.created_task_data.status = ResponseStatusEnm.Failed
@@ -78,7 +81,10 @@ class SIOCaptchaInstrument(CaptchaInstrumentBase):
78
81
  )
79
82
  if resp.status_code in VALID_STATUS_CODES:
80
83
  result_data = CaptchaResponseSer(**resp.json())
81
- if result_data.status in (ResponseStatusEnm.Ready, ResponseStatusEnm.Failed):
84
+ if result_data.status in (
85
+ ResponseStatusEnm.Ready,
86
+ ResponseStatusEnm.Failed,
87
+ ):
82
88
  # if captcha ready\failed or have unknown status - return exist data
83
89
  return result_data
84
90
  else:
@@ -89,12 +95,14 @@ class SIOCaptchaInstrument(CaptchaInstrumentBase):
89
95
 
90
96
  # if captcha just created or in processing now - wait
91
97
  time.sleep(self.captcha_params.sleep_time)
98
+
92
99
  # default response if server is silent
93
100
  self.result.errorId = 1
94
101
  self.result.errorCode = self.CAPTCHA_UNSOLVABLE
95
102
  self.result.errorDescription = self.CAPTCHA_UNSOLVABLE_DESCRIPTION
96
103
  self.result.taskId = self.created_task_data.taskId
97
104
  self.result.status = ResponseStatusEnm.Failed
105
+ return self.result
98
106
 
99
107
  @staticmethod
100
108
  def send_post_request(
@@ -83,7 +83,12 @@ class ImageToText(CaptchaParams):
83
83
  """
84
84
 
85
85
  def __init__(
86
- self, api_key: str, captcha_type: Union[CaptchaTypeEnm, str] = CaptchaTypeEnm.ImageToTextTask, **kwargs
86
+ self,
87
+ api_key: str,
88
+ captcha_type: Union[CaptchaTypeEnm, str] = CaptchaTypeEnm.ImageToTextTask,
89
+ **kwargs,
87
90
  ):
91
+ if isinstance(captcha_type, str):
92
+ captcha_type = CaptchaTypeEnm(captcha_type)
88
93
 
89
94
  super().__init__(api_key=api_key, captcha_type=captcha_type, **kwargs)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python3-capsolver
3
- Version: 1.1.1
3
+ Version: 1.2.1
4
4
  Summary: Python 3.8+ Capsolver library with AIO module.
5
5
  Author-email: AndreiDrang <python-captcha@pm.me>
6
6
  License: MIT License
@@ -30,7 +30,7 @@ Description-Content-Type: text/markdown
30
30
  License-File: LICENSE
31
31
  Requires-Dist: requests>=2.21.0
32
32
  Requires-Dist: aiohttp>=3.9.2
33
- Requires-Dist: msgspec<=0.21,>=0.18
33
+ Requires-Dist: msgspec>=0.18
34
34
  Requires-Dist: tenacity<10,>=8
35
35
  Dynamic: license-file
36
36
 
@@ -61,11 +61,31 @@ Tested on UNIX based OS.
61
61
 
62
62
  The library is intended for software developers and is used to work with the [Capsolver](https://dashboard.capsolver.com/passport/register?inviteCode=kQTn-tG07Jb1) service API.
63
63
 
64
+ ## Features
65
+ - **Modern Tooling**: Uses `uv` for fast, reliable dependency management and environment isolation.
66
+ - **Sync & Async Support**: Full support for both synchronous (`requests`) and asynchronous (`aiohttp`) operations.
67
+ - **Type Safety**: Enums for captcha types and response statuses.
68
+ - **Resilience**: Built-in retries using `tenacity`.
69
+ - **Performance**: High-speed JSON serialization with `msgspec`.
70
+ - **Coverage**: Supports ReCaptcha (V2/V3), Cloudflare, DataDome, GeeTest, MtCaptcha, AWS WAF, Yandex, and ImageToText.
71
+
64
72
  ## How to install?
65
73
 
66
- We recommend using the latest version of Python. `python3-capsolver` supports Python 3.7+.
74
+ We recommend using the latest version of Python. `python3-capsolver` supports Python 3.8+.
75
+
76
+ ### Development (using uv)
67
77
 
68
- ### pip
78
+ This project uses [uv](https://github.com/astral-sh/uv) for fast, reliable dependency management.
79
+
80
+ ```bash
81
+ # Install uv (if not already installed)
82
+ curl -LsSf https://astral.sh/uv/install.sh | sh
83
+
84
+ # Install project dependencies
85
+ uv sync --all-groups
86
+ ```
87
+
88
+ ### Production (pip)
69
89
 
70
90
  ```bash
71
91
  pip install python3-capsolver
@@ -73,18 +93,99 @@ pip install python3-capsolver
73
93
 
74
94
  ## How to use?
75
95
 
76
- Is described in the [documentation-website](https://andreidrang.github.io/python3-capsolver/).
96
+ Detailed documentation is available on the [website](https://andreidrang.github.io/python3-capsolver/).
97
+
98
+ ### Quick Start
99
+
100
+ #### Synchronous Example (ImageToText)
101
+ ```python
102
+ from python3_capsolver.image_to_text import ImageToText
77
103
 
104
+ # 1. Initialize with API Key
105
+ solver = ImageToText(api_key="YOUR_API_KEY")
106
+
107
+ # 2. Solve
108
+ result = solver.captcha_handler(
109
+ task_payload={
110
+ "body": "base64_encoded_image_string"
111
+ }
112
+ )
113
+
114
+ # 3. Check result
115
+ if result["errorId"] == 0:
116
+ print("Solution:", result["solution"])
117
+ else:
118
+ print("Error:", result["errorCode"])
119
+ ```
120
+
121
+ #### Asynchronous Example (ReCaptcha)
122
+ ```python
123
+ import asyncio
124
+ from python3_capsolver.recaptcha import ReCaptcha
125
+ from python3_capsolver.core.enum import CaptchaTypeEnm
126
+
127
+ async def main():
128
+ # 1. Initialize
129
+ solver = ReCaptcha(
130
+ api_key="YOUR_API_KEY",
131
+ captcha_type=CaptchaTypeEnm.ReCaptchaV2TaskProxyLess
132
+ )
133
+
134
+ # 2. Solve
135
+ result = await solver.aio_captcha_handler(
136
+ task_payload={
137
+ "websiteURL": "https://example.com",
138
+ "websiteKey": "SITE_KEY"
139
+ }
140
+ )
141
+
142
+ print(result)
143
+
144
+ if __name__ == "__main__":
145
+ asyncio.run(main())
146
+ ```
147
+
148
+ ## Supported Captcha Types
149
+ - **ReCaptcha**: V2 (Task/Enterprise), V3 (Task/Enterprise)
150
+ - **HCaptcha**: Task, Enterprise
151
+ - **Cloudflare**: Turnstile
152
+ - **GeeTest**: V3, V4
153
+ - **DataDome**: Slider
154
+ - **MtCaptcha**
155
+ - **AWS WAF**
156
+ - **Yandex SmartCaptcha**
157
+ - **ImageToText**: General image CAPTCHAs
158
+
159
+ ## Documentation & Context (For LLMs)
160
+ - **Project Structure**: See `AGENTS.md` in root and subdirectories for internal architecture.
161
+ - **Entry Points**: `src/python3_capsolver/*.py` contains service-specific classes (e.g., `ReCaptcha`, `HCaptcha`).
162
+ - **Core Logic**: `src/python3_capsolver/core/base.py` handles the API communication loop.
163
+ - **Enums**: Use `python3_capsolver.core.enum` for type-safe parameters.
78
164
 
79
165
  ## How to test?
80
166
 
81
- 1. You need set ``API_KEY`` in your environment(get this value from you account).
82
- 2. Run command ``make tests``, from root directory.
167
+ The project uses `uv` for testing and development tasks.
168
+
169
+ ```bash
170
+ # 1. Set API_KEY in your environment (get this value from your account)
171
+ export API_KEY="your_api_key_here"
172
+
173
+ # 2. Run tests (uses uv internally)
174
+ make tests
175
+
176
+ # Other useful make targets:
177
+ # make install # Install dependencies with uv sync
178
+ # make lint # Run linting checks
179
+ # make build # Build the package
180
+ # make doc # Generate documentation
181
+ ```
182
+
183
+ All `make` commands automatically use `uv` to run commands in the isolated environment.
83
184
 
84
185
 
85
186
  ### Changelog
86
187
 
87
- Check [releases page](https://github.com/AndreiDrang/python3-capsolver/releases).
188
+ See [CHANGELOG.md](https://github.com/AndreiDrang/python3-capsolver/blob/main/CHANGELOG.md) for version history and detailed changes.
88
189
 
89
190
  ### How to get API Key to work with the library
90
191
  1. On the page - https://dashboard.capsolver.com/overview/user-center
@@ -1,28 +1,28 @@
1
1
  python3_capsolver/__init__.py,sha256=141uoiYvgRblIWZAy7AhQJz6iVqzY4b5cLxExIaKUlg,62
2
- python3_capsolver/__version__.py,sha256=q8_5C0f-8mHWNb6mMw02zlYPnEGXBqvOmP3z0CEwZKM,22
2
+ python3_capsolver/__version__.py,sha256=Mlm4Gvmb_6yQxwUbv2Ksc-BJFXLPg9H1Vt2iV7wXrA4,22
3
3
  python3_capsolver/aws_waf.py,sha256=wwNjW2bkS-EdxEkTDxW9zwUGCnW_bbEhtruSgw_R94I,5677
4
4
  python3_capsolver/cloudflare.py,sha256=SCuC4femAkNWY9taGELuGiGI8mDI5N2ziWAewNhAQrI,5367
5
5
  python3_capsolver/control.py,sha256=TEhH2xGpJVX5QSiH3senhqoASnuJlDiFZfEZ1CLD1oA,16982
6
6
  python3_capsolver/datadome_slider.py,sha256=kh15W30CQl-RgzcyCm_2ldluYAvbjyTl3mS9SFGj51k,2805
7
7
  python3_capsolver/friendly_captcha.py,sha256=S1nenBwG3P2hiB-In13tWMNnITou68s8q-h3QXplubI,4412
8
8
  python3_capsolver/gee_test.py,sha256=VjBOVggAkVRx6pGRys8kXl0-ZLFNCOMSYK_Bn95zk7o,2903
9
- python3_capsolver/image_to_text.py,sha256=i3ezTvy4cZD98LhVisyWINTbnHf08EKCGYGS_G_XH6o,3372
9
+ python3_capsolver/image_to_text.py,sha256=lYEzENjEoKlBMFiyjGeLHgpczZaa184_X5MPommIOgs,3495
10
10
  python3_capsolver/mt_captcha.py,sha256=mtHyqGat34odh_2KLBviEHMxnFi3SSSvRaVQAE1k0HA,2267
11
11
  python3_capsolver/recaptcha.py,sha256=tiZPC_OGfhA30SH6lnqo2curVDLDwGwGLvx1zVn3gYY,3052
12
12
  python3_capsolver/vision_engine.py,sha256=h82S6NvRbQTQUPTsLKQ1xpGMzlqHXaDGRRtDOSa275Q,2918
13
13
  python3_capsolver/yandex.py,sha256=4NvopCD9pKVyUNLlQqj2Yra3n_YY0NG8Gqc5sVK9Yis,2770
14
14
  python3_capsolver/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
15
- python3_capsolver/core/aio_captcha_instrument.py,sha256=iYbML1dL2X_y7zaqPKhI93K2Ye4-DQQ8ewAVNDudiaE,4532
15
+ python3_capsolver/core/aio_captcha_instrument.py,sha256=9LYx51KodjbDUZ0pcNxlSEW5KCqHQAiPfhCwF2J0PYE,4811
16
16
  python3_capsolver/core/base.py,sha256=WScd52oKm28EE-yxOibYwlJRlaZH_q5sFzs8ynQwau0,3110
17
- python3_capsolver/core/captcha_instrument.py,sha256=tdpfV-3zayJrAqHRSvDz4Ac2JejwKu5zh0nTl5aLPcY,9157
17
+ python3_capsolver/core/captcha_instrument.py,sha256=Lg2fe0mpIre6z5Mb1LDvjHmbi-16BJ5zDS3_sJbMvXE,9262
18
18
  python3_capsolver/core/const.py,sha256=AEU2IFQ6xbMRGdXzBNtZflxNFJ4VTshGx1skBtdrQ2w,613
19
19
  python3_capsolver/core/context_instr.py,sha256=x3JQNd1ydlNdhuGKX_5gc-5Duq2pZJME0fs2YMQyGv4,503
20
20
  python3_capsolver/core/enum.py,sha256=M4gfCzzkIMQ8JZd3qwFsA1iXW8cbfYFxJGTxiVvTUsE,2490
21
- python3_capsolver/core/serializer.py,sha256=rE7VX_6FCisOnK-HS4K90LkuWU3cOVa6GwkvbFgjhnA,1342
22
- python3_capsolver/core/sio_captcha_instrument.py,sha256=NVYS93ZuW2yOaYXla66nKHTDp0Ac4Qn4pZxYfm7Nr3A,4433
21
+ python3_capsolver/core/serializer.py,sha256=048uf015XtPirdtdijDxpO8sg3xoDIFXucUwmHKLUMo,1363
22
+ python3_capsolver/core/sio_captcha_instrument.py,sha256=LZlcftx_L8IjB0xhH2dFdbd7No_l8ZDSS9aX02feWn8,4681
23
23
  python3_capsolver/core/utils.py,sha256=5PMxryy22MIUmUXPIHqz38vg2C2bqa7uXHUNYRF8DlY,633
24
- python3_capsolver-1.1.1.dist-info/licenses/LICENSE,sha256=N_utAsqhTp1pXXp-PTE-CFMg5BfIIqTbF-phwwzOHeQ,1063
25
- python3_capsolver-1.1.1.dist-info/METADATA,sha256=5KcNyaFHh8uTTupKRkvnzekGAHvrRc25Zy6KUPWpPw8,5371
26
- python3_capsolver-1.1.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
27
- python3_capsolver-1.1.1.dist-info/top_level.txt,sha256=yws7CqjoBfrn2ebCkAQmEaVlZ-zhbtflqpCDwAEX4kI,18
28
- python3_capsolver-1.1.1.dist-info/RECORD,,
24
+ python3_capsolver-1.2.1.dist-info/licenses/LICENSE,sha256=N_utAsqhTp1pXXp-PTE-CFMg5BfIIqTbF-phwwzOHeQ,1063
25
+ python3_capsolver-1.2.1.dist-info/METADATA,sha256=ljC80tlxqtijvJwzIu9x-fD3zQWBmHZhjJDaCz_IKqo,8400
26
+ python3_capsolver-1.2.1.dist-info/WHEEL,sha256=YVMoNqKzERt-wjUZwJ33xBGAwnFl-4cqbYkTtWa4itE,91
27
+ python3_capsolver-1.2.1.dist-info/top_level.txt,sha256=yws7CqjoBfrn2ebCkAQmEaVlZ-zhbtflqpCDwAEX4kI,18
28
+ python3_capsolver-1.2.1.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (80.9.0)
2
+ Generator: setuptools (84.0.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5