python3-capsolver 1.1.0__py3-none-any.whl → 1.2.0__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.0"
1
+ __version__ = "1.2.0"
@@ -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.0
3
+ Version: 1.2.0
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.20,>=0.18
33
+ Requires-Dist: msgspec<=0.21,>=0.18
34
34
  Requires-Dist: tenacity<10,>=8
35
35
  Dynamic: license-file
36
36
 
@@ -61,6 +61,13 @@ 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
+ - **Sync & Async Support**: Full support for both synchronous (`requests`) and asynchronous (`aiohttp`) operations.
66
+ - **Type Safety**: Enums for captcha types and response statuses.
67
+ - **Resilience**: Built-in retries using `tenacity`.
68
+ - **Performance**: High-speed JSON serialization with `msgspec`.
69
+ - **Coverage**: Supports ReCaptcha (V2/V3), Cloudflare, DataDome, GeeTest, MtCaptcha, AWS WAF, Yandex, and ImageToText.
70
+
64
71
  ## How to install?
65
72
 
66
73
  We recommend using the latest version of Python. `python3-capsolver` supports Python 3.7+.
@@ -73,8 +80,74 @@ pip install python3-capsolver
73
80
 
74
81
  ## How to use?
75
82
 
76
- Is described in the [documentation-website](https://andreidrang.github.io/python3-capsolver/).
83
+ Detailed documentation is available on the [website](https://andreidrang.github.io/python3-capsolver/).
84
+
85
+ ### Quick Start
86
+
87
+ #### Synchronous Example (ImageToText)
88
+ ```python
89
+ from python3_capsolver.image_to_text import ImageToText
90
+
91
+ # 1. Initialize with API Key
92
+ solver = ImageToText(api_key="YOUR_API_KEY")
93
+
94
+ # 2. Solve
95
+ result = solver.captcha_handler(
96
+ task_payload={
97
+ "body": "base64_encoded_image_string"
98
+ }
99
+ )
100
+
101
+ # 3. Check result
102
+ if result["errorId"] == 0:
103
+ print("Solution:", result["solution"])
104
+ else:
105
+ print("Error:", result["errorCode"])
106
+ ```
107
+
108
+ #### Asynchronous Example (ReCaptcha)
109
+ ```python
110
+ import asyncio
111
+ from python3_capsolver.recaptcha import ReCaptcha
112
+ from python3_capsolver.core.enum import CaptchaTypeEnm
113
+
114
+ async def main():
115
+ # 1. Initialize
116
+ solver = ReCaptcha(
117
+ api_key="YOUR_API_KEY",
118
+ captcha_type=CaptchaTypeEnm.ReCaptchaV2TaskProxyLess
119
+ )
120
+
121
+ # 2. Solve
122
+ result = await solver.aio_captcha_handler(
123
+ task_payload={
124
+ "websiteURL": "https://example.com",
125
+ "websiteKey": "SITE_KEY"
126
+ }
127
+ )
128
+
129
+ print(result)
130
+
131
+ if __name__ == "__main__":
132
+ asyncio.run(main())
133
+ ```
77
134
 
135
+ ## Supported Captcha Types
136
+ - **ReCaptcha**: V2 (Task/Enterprise), V3 (Task/Enterprise)
137
+ - **HCaptcha**: Task, Enterprise
138
+ - **Cloudflare**: Turnstile
139
+ - **GeeTest**: V3, V4
140
+ - **DataDome**: Slider
141
+ - **MtCaptcha**
142
+ - **AWS WAF**
143
+ - **Yandex SmartCaptcha**
144
+ - **ImageToText**: General image CAPTCHAs
145
+
146
+ ## Documentation & Context (For LLMs)
147
+ - **Project Structure**: See `AGENTS.md` in root and subdirectories for internal architecture.
148
+ - **Entry Points**: `src/python3_capsolver/*.py` contains service-specific classes (e.g., `ReCaptcha`, `HCaptcha`).
149
+ - **Core Logic**: `src/python3_capsolver/core/base.py` handles the API communication loop.
150
+ - **Enums**: Use `python3_capsolver.core.enum` for type-safe parameters.
78
151
 
79
152
  ## How to test?
80
153
 
@@ -1,28 +1,28 @@
1
1
  python3_capsolver/__init__.py,sha256=141uoiYvgRblIWZAy7AhQJz6iVqzY4b5cLxExIaKUlg,62
2
- python3_capsolver/__version__.py,sha256=LGVQyDsWifdACo7qztwb8RWWHds1E7uQ-ZqD8SAjyw4,22
2
+ python3_capsolver/__version__.py,sha256=MpAT5hgNoHnTtG1XRD_GV_A7QrHVU6vJjGSw_8qMGA4,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.0.dist-info/licenses/LICENSE,sha256=N_utAsqhTp1pXXp-PTE-CFMg5BfIIqTbF-phwwzOHeQ,1063
25
- python3_capsolver-1.1.0.dist-info/METADATA,sha256=8E9C3Dl89H0gqLBRTIu6l13H_c3DLPKqNHvbD7UARK0,5370
26
- python3_capsolver-1.1.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
27
- python3_capsolver-1.1.0.dist-info/top_level.txt,sha256=yws7CqjoBfrn2ebCkAQmEaVlZ-zhbtflqpCDwAEX4kI,18
28
- python3_capsolver-1.1.0.dist-info/RECORD,,
24
+ python3_capsolver-1.2.0.dist-info/licenses/LICENSE,sha256=N_utAsqhTp1pXXp-PTE-CFMg5BfIIqTbF-phwwzOHeQ,1063
25
+ python3_capsolver-1.2.0.dist-info/METADATA,sha256=7OfV6UwZU3MV3FQBKryNWmu5TAUqpPvg3Pli9_1piZM,7573
26
+ python3_capsolver-1.2.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
27
+ python3_capsolver-1.2.0.dist-info/top_level.txt,sha256=yws7CqjoBfrn2ebCkAQmEaVlZ-zhbtflqpCDwAEX4kI,18
28
+ python3_capsolver-1.2.0.dist-info/RECORD,,