python-rucaptcha 6.4.0__tar.gz → 6.5.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.
Files changed (76) hide show
  1. {python_rucaptcha-6.4.0/src/python_rucaptcha.egg-info → python_rucaptcha-6.5.0}/PKG-INFO +3 -2
  2. {python_rucaptcha-6.4.0 → python_rucaptcha-6.5.0}/pyproject.toml +4 -0
  3. python_rucaptcha-6.5.0/src/python_rucaptcha/__version__.py +1 -0
  4. {python_rucaptcha-6.4.0 → python_rucaptcha-6.5.0}/src/python_rucaptcha/core/base.py +49 -27
  5. {python_rucaptcha-6.4.0 → python_rucaptcha-6.5.0}/src/python_rucaptcha/core/config.py +3 -1
  6. {python_rucaptcha-6.4.0 → python_rucaptcha-6.5.0}/src/python_rucaptcha/core/enums.py +8 -0
  7. python_rucaptcha-6.5.0/src/python_rucaptcha/core/result_handler.py +116 -0
  8. python_rucaptcha-6.5.0/src/python_rucaptcha/core/serializer.py +98 -0
  9. {python_rucaptcha-6.4.0 → python_rucaptcha-6.5.0}/src/python_rucaptcha/image_captcha.py +5 -5
  10. python_rucaptcha-6.5.0/src/python_rucaptcha/temu_captcha.py +152 -0
  11. python_rucaptcha-6.5.0/src/python_rucaptcha/vk_captcha.py +120 -0
  12. {python_rucaptcha-6.4.0 → python_rucaptcha-6.5.0/src/python_rucaptcha.egg-info}/PKG-INFO +3 -2
  13. {python_rucaptcha-6.4.0 → python_rucaptcha-6.5.0}/src/python_rucaptcha.egg-info/SOURCES.txt +2 -0
  14. python_rucaptcha-6.4.0/src/python_rucaptcha/__version__.py +0 -1
  15. python_rucaptcha-6.4.0/src/python_rucaptcha/core/result_handler.py +0 -69
  16. python_rucaptcha-6.4.0/src/python_rucaptcha/core/serializer.py +0 -74
  17. {python_rucaptcha-6.4.0 → python_rucaptcha-6.5.0}/LICENSE +0 -0
  18. {python_rucaptcha-6.4.0 → python_rucaptcha-6.5.0}/MANIFEST.in +0 -0
  19. {python_rucaptcha-6.4.0 → python_rucaptcha-6.5.0}/README.md +0 -0
  20. {python_rucaptcha-6.4.0 → python_rucaptcha-6.5.0}/setup.cfg +0 -0
  21. {python_rucaptcha-6.4.0 → python_rucaptcha-6.5.0}/src/python_rucaptcha/__init__.py +0 -0
  22. {python_rucaptcha-6.4.0 → python_rucaptcha-6.5.0}/src/python_rucaptcha/amazon_waf.py +0 -0
  23. {python_rucaptcha-6.4.0 → python_rucaptcha-6.5.0}/src/python_rucaptcha/atb_captcha.py +0 -0
  24. {python_rucaptcha-6.4.0 → python_rucaptcha-6.5.0}/src/python_rucaptcha/audio_captcha.py +0 -0
  25. {python_rucaptcha-6.4.0 → python_rucaptcha-6.5.0}/src/python_rucaptcha/bounding_box_captcha.py +0 -0
  26. {python_rucaptcha-6.4.0 → python_rucaptcha-6.5.0}/src/python_rucaptcha/captcha_fox.py +0 -0
  27. {python_rucaptcha-6.4.0 → python_rucaptcha-6.5.0}/src/python_rucaptcha/capy_puzzle.py +0 -0
  28. {python_rucaptcha-6.4.0 → python_rucaptcha-6.5.0}/src/python_rucaptcha/control.py +0 -0
  29. {python_rucaptcha-6.4.0 → python_rucaptcha-6.5.0}/src/python_rucaptcha/coordinates_captcha.py +0 -0
  30. {python_rucaptcha-6.4.0 → python_rucaptcha-6.5.0}/src/python_rucaptcha/core/__init__.py +0 -0
  31. {python_rucaptcha-6.4.0 → python_rucaptcha-6.5.0}/src/python_rucaptcha/cutcaptcha.py +0 -0
  32. {python_rucaptcha-6.4.0 → python_rucaptcha-6.5.0}/src/python_rucaptcha/cyber_siara_captcha.py +0 -0
  33. {python_rucaptcha-6.4.0 → python_rucaptcha-6.5.0}/src/python_rucaptcha/datadome_captcha.py +0 -0
  34. {python_rucaptcha-6.4.0 → python_rucaptcha-6.5.0}/src/python_rucaptcha/draw_around_captcha.py +0 -0
  35. {python_rucaptcha-6.4.0 → python_rucaptcha-6.5.0}/src/python_rucaptcha/friendly_captcha.py +0 -0
  36. {python_rucaptcha-6.4.0 → python_rucaptcha-6.5.0}/src/python_rucaptcha/fun_captcha.py +0 -0
  37. {python_rucaptcha-6.4.0 → python_rucaptcha-6.5.0}/src/python_rucaptcha/gee_test.py +0 -0
  38. {python_rucaptcha-6.4.0 → python_rucaptcha-6.5.0}/src/python_rucaptcha/grid_captcha.py +0 -0
  39. {python_rucaptcha-6.4.0 → python_rucaptcha-6.5.0}/src/python_rucaptcha/hcaptcha.py +0 -0
  40. {python_rucaptcha-6.4.0 → python_rucaptcha-6.5.0}/src/python_rucaptcha/key_captcha.py +0 -0
  41. {python_rucaptcha-6.4.0 → python_rucaptcha-6.5.0}/src/python_rucaptcha/lemin_captcha.py +0 -0
  42. {python_rucaptcha-6.4.0 → python_rucaptcha-6.5.0}/src/python_rucaptcha/mt_captcha.py +0 -0
  43. {python_rucaptcha-6.4.0 → python_rucaptcha-6.5.0}/src/python_rucaptcha/prosopo.py +0 -0
  44. {python_rucaptcha-6.4.0 → python_rucaptcha-6.5.0}/src/python_rucaptcha/re_captcha.py +0 -0
  45. {python_rucaptcha-6.4.0 → python_rucaptcha-6.5.0}/src/python_rucaptcha/rotate_captcha.py +0 -0
  46. {python_rucaptcha-6.4.0 → python_rucaptcha-6.5.0}/src/python_rucaptcha/tencent.py +0 -0
  47. {python_rucaptcha-6.4.0 → python_rucaptcha-6.5.0}/src/python_rucaptcha/text_captcha.py +0 -0
  48. {python_rucaptcha-6.4.0 → python_rucaptcha-6.5.0}/src/python_rucaptcha/turnstile.py +0 -0
  49. {python_rucaptcha-6.4.0 → python_rucaptcha-6.5.0}/src/python_rucaptcha.egg-info/dependency_links.txt +0 -0
  50. {python_rucaptcha-6.4.0 → python_rucaptcha-6.5.0}/src/python_rucaptcha.egg-info/requires.txt +0 -0
  51. {python_rucaptcha-6.4.0 → python_rucaptcha-6.5.0}/src/python_rucaptcha.egg-info/top_level.txt +0 -0
  52. {python_rucaptcha-6.4.0 → python_rucaptcha-6.5.0}/tests/test_amazon.py +0 -0
  53. {python_rucaptcha-6.4.0 → python_rucaptcha-6.5.0}/tests/test_audio.py +0 -0
  54. {python_rucaptcha-6.4.0 → python_rucaptcha-6.5.0}/tests/test_bounding_box.py +0 -0
  55. {python_rucaptcha-6.4.0 → python_rucaptcha-6.5.0}/tests/test_capypuzzle.py +0 -0
  56. {python_rucaptcha-6.4.0 → python_rucaptcha-6.5.0}/tests/test_control.py +0 -0
  57. {python_rucaptcha-6.4.0 → python_rucaptcha-6.5.0}/tests/test_coordinates.py +0 -0
  58. {python_rucaptcha-6.4.0 → python_rucaptcha-6.5.0}/tests/test_core.py +0 -0
  59. {python_rucaptcha-6.4.0 → python_rucaptcha-6.5.0}/tests/test_cutcaptcha.py +0 -0
  60. {python_rucaptcha-6.4.0 → python_rucaptcha-6.5.0}/tests/test_cybersiara.py +0 -0
  61. {python_rucaptcha-6.4.0 → python_rucaptcha-6.5.0}/tests/test_datadome.py +0 -0
  62. {python_rucaptcha-6.4.0 → python_rucaptcha-6.5.0}/tests/test_draw_around.py +0 -0
  63. {python_rucaptcha-6.4.0 → python_rucaptcha-6.5.0}/tests/test_friendly_captcha.py +0 -0
  64. {python_rucaptcha-6.4.0 → python_rucaptcha-6.5.0}/tests/test_funcaptcha.py +0 -0
  65. {python_rucaptcha-6.4.0 → python_rucaptcha-6.5.0}/tests/test_geetest.py +0 -0
  66. {python_rucaptcha-6.4.0 → python_rucaptcha-6.5.0}/tests/test_grid.py +0 -0
  67. {python_rucaptcha-6.4.0 → python_rucaptcha-6.5.0}/tests/test_hcaptcha.py +0 -0
  68. {python_rucaptcha-6.4.0 → python_rucaptcha-6.5.0}/tests/test_image.py +0 -0
  69. {python_rucaptcha-6.4.0 → python_rucaptcha-6.5.0}/tests/test_key_captcha.py +0 -0
  70. {python_rucaptcha-6.4.0 → python_rucaptcha-6.5.0}/tests/test_lemin.py +0 -0
  71. {python_rucaptcha-6.4.0 → python_rucaptcha-6.5.0}/tests/test_mtcaptcha.py +0 -0
  72. {python_rucaptcha-6.4.0 → python_rucaptcha-6.5.0}/tests/test_recaptcha.py +0 -0
  73. {python_rucaptcha-6.4.0 → python_rucaptcha-6.5.0}/tests/test_rotate.py +0 -0
  74. {python_rucaptcha-6.4.0 → python_rucaptcha-6.5.0}/tests/test_tencent.py +0 -0
  75. {python_rucaptcha-6.4.0 → python_rucaptcha-6.5.0}/tests/test_text.py +0 -0
  76. {python_rucaptcha-6.4.0 → python_rucaptcha-6.5.0}/tests/test_turnstile.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python-rucaptcha
3
- Version: 6.4.0
3
+ Version: 6.5.0
4
4
  Summary: Python 3.9+ RuCaptcha library with AIO module.
5
5
  Author-email: AndreiDrang <python-captcha@pm.me>
6
6
  License-Expression: MIT
@@ -9,7 +9,7 @@ Project-URL: Documentation, https://andreidrang.github.io/python-rucaptcha/
9
9
  Project-URL: Repository, https://github.com/AndreiDrang/python-rucaptcha
10
10
  Project-URL: Issues, https://github.com/AndreiDrang/python-rucaptcha/issues
11
11
  Project-URL: Changelog, https://github.com/AndreiDrang/python-rucaptcha/releases
12
- Keywords: captcha,rucaptcha,2captcha,deathbycaptcha,recaptcha,geetest,hcaptcha,capypuzzle,rotatecaptcha,funcaptcha,keycaptcha,python3,recaptcha,captcha,security,tencent,atb_captcha,python-library,python-rucaptcha,rucaptcha-client,yandex,turnstile,amazon,amazon_waf,friendly-captcha
12
+ Keywords: captcha,rucaptcha,2captcha,deathbycaptcha,recaptcha,geetest,hcaptcha,capypuzzle,rotatecaptcha,funcaptcha,keycaptcha,python3,recaptcha,captcha,security,tencent,atb_captcha,python-library,python-rucaptcha,rucaptcha-client,yandex,turnstile,amazon,amazon_waf,vk-captcha,fox-captcha,temu-captcha,friendly-captcha
13
13
  Classifier: Development Status :: 5 - Production/Stable
14
14
  Classifier: Programming Language :: Python
15
15
  Classifier: Programming Language :: Python :: 3
@@ -18,6 +18,7 @@ Classifier: Programming Language :: Python :: 3.9
18
18
  Classifier: Programming Language :: Python :: 3.10
19
19
  Classifier: Programming Language :: Python :: 3.11
20
20
  Classifier: Programming Language :: Python :: 3.12
21
+ Classifier: Programming Language :: Python :: 3.13
21
22
  Classifier: Framework :: AsyncIO
22
23
  Classifier: Operating System :: Unix
23
24
  Classifier: Operating System :: Microsoft :: Windows
@@ -66,6 +66,9 @@ keywords = [ "captcha",
66
66
  "turnstile",
67
67
  "amazon",
68
68
  "amazon_waf",
69
+ "vk-captcha",
70
+ "fox-captcha",
71
+ "temu-captcha",
69
72
  "friendly-captcha"
70
73
  ]
71
74
  license = "MIT"
@@ -78,6 +81,7 @@ classifiers = [
78
81
  "Programming Language :: Python :: 3.10",
79
82
  "Programming Language :: Python :: 3.11",
80
83
  "Programming Language :: Python :: 3.12",
84
+ "Programming Language :: Python :: 3.13",
81
85
  "Framework :: AsyncIO",
82
86
  "Operating System :: Unix",
83
87
  "Operating System :: Microsoft :: Windows",
@@ -0,0 +1 @@
1
+ __version__ = "6.5.0"
@@ -3,7 +3,7 @@ import time
3
3
  import uuid
4
4
  import base64
5
5
  import asyncio
6
- from typing import Optional
6
+ from typing import Any, Optional
7
7
  from pathlib import Path
8
8
 
9
9
  import aiohttp
@@ -30,16 +30,32 @@ class BaseCaptcha:
30
30
  rucaptcha_key: str,
31
31
  method: str,
32
32
  sleep_time: int = 10,
33
- service_type: str = ServiceEnm.TWOCAPTCHA.value,
34
- **kwargs,
33
+ service_type: ServiceEnm | str = ServiceEnm.TWOCAPTCHA,
34
+ **kwargs: dict[str, Any],
35
35
  ):
36
36
  """
37
- :param rucaptcha_key: User API key
38
- :param method: Captcha type
39
- :param sleep_time: Time to wait for captcha solution
40
- :param service_type: URL with which the program will work, "2captcha" option is possible (standard)
41
- and "rucaptcha"
42
- :param kwargs: Designed to pass OPTIONAL parameters to the payload for a request to RuCaptcha
37
+ Base class for interacting with CAPTCHA-solving services such as 2Captcha and RuCaptcha.
38
+
39
+ This class handles the setup of request payloads, session configuration, and service-specific
40
+ parameters required to submit CAPTCHA tasks and retrieve their results. It supports optional
41
+ customization of task parameters via keyword arguments and includes retry logic for HTTP requests.
42
+
43
+ Args:
44
+ rucaptcha_key (str):
45
+ API key provided by the CAPTCHA-solving service.
46
+ method (str):
47
+ Type of CAPTCHA to solve (e.g., "ImageToText", "ReCaptchaV2").
48
+ sleep_time (int, optional):
49
+ Time in seconds to wait between polling attempts. Defaults to 10.
50
+ service_type (ServiceEnm | str, optional):
51
+ Service provider to use. Accepts `ServiceEnm.TWOCAPTCHA` or `"rucaptcha"`. Defaults to TWOCAPTCHA.
52
+ **kwargs (dict[str, Any]):
53
+ Optional parameters to be injected into the task payload (e.g., `websiteURL`, `siteKey`, `proxy`).
54
+
55
+ Example:
56
+ >>> captcha = BaseCaptcha("your-api-key", method="ReCaptchaV2", websiteURL="https://example.com", siteKey="abc123")
57
+ >>> captcha.create_task_payload
58
+ {'clientKey': 'your-api-key', 'task': {'type': 'ReCaptchaV2', 'websiteURL': 'https://example.com', 'siteKey': 'abc123'}}
43
59
  """
44
60
  self.result = GetTaskResultResponseSer()
45
61
  # assign args to validator
@@ -48,7 +64,7 @@ class BaseCaptcha:
48
64
 
49
65
  # prepare create task payload
50
66
  self.create_task_payload = CreateTaskBaseSer(
51
- clientKey=rucaptcha_key, task=TaskSer(type=method).to_dict()
67
+ clientKey=rucaptcha_key, task=TaskSer(type=method)
52
68
  ).to_dict()
53
69
  # prepare get task result data payload
54
70
  self.get_task_payload = GetTaskResultRequestSer(clientKey=rucaptcha_key)
@@ -61,7 +77,7 @@ class BaseCaptcha:
61
77
  self.session.mount("http://", HTTPAdapter(max_retries=RETRIES))
62
78
  self.session.mount("https://", HTTPAdapter(max_retries=RETRIES))
63
79
 
64
- def _processing_response(self, **kwargs: dict) -> dict:
80
+ def _processing_response(self, **kwargs: dict[str, Any]) -> dict[str, Any]:
65
81
  """
66
82
  Method processing captcha solving task creation result
67
83
  :param kwargs: additional params for Requests library
@@ -90,13 +106,13 @@ class BaseCaptcha:
90
106
  url_response=self.params.url_response,
91
107
  )
92
108
 
93
- def url_open(self, url: str, **kwargs):
109
+ def url_open(self, url: str, **kwargs: dict[str, Any]):
94
110
  """
95
111
  Method open links
96
112
  """
97
113
  return self.session.get(url=url, **kwargs)
98
114
 
99
- async def aio_url_read(self, url: str, **kwargs) -> bytes:
115
+ async def aio_url_read(self, url: str, **kwargs: dict[str, Any]) -> bytes | None:
100
116
  """
101
117
  Async method read bytes from link
102
118
  """
@@ -106,7 +122,7 @@ class BaseCaptcha:
106
122
  async with session.get(url=url, **kwargs) as resp:
107
123
  return await resp.content.read()
108
124
 
109
- async def _aio_processing_response(self) -> dict:
125
+ async def _aio_processing_response(self) -> dict[str, Any]:
110
126
  """
111
127
  Method processing async captcha solving task creation result
112
128
  """
@@ -167,23 +183,24 @@ class BaseCaptcha:
167
183
 
168
184
  def _body_file_processing(
169
185
  self,
170
- save_format: SaveFormatsEnm,
186
+ save_format: SaveFormatsEnm | str,
171
187
  file_path: str,
172
188
  file_extension: str = "png",
173
- captcha_link: Optional[str] = None,
174
- captcha_file: Optional[str] = None,
175
- captcha_base64: Optional[bytes] = None,
176
- **kwargs,
189
+ image_key: str = "body",
190
+ captcha_link: str | None = None,
191
+ captcha_file: str | None = None,
192
+ captcha_base64: bytes | None = None,
193
+ **kwargs: dict[str, Any],
177
194
  ):
178
195
  # if a local file link is passed
179
196
  if captcha_file:
180
197
  self.create_task_payload["task"].update(
181
- {"body": base64.b64encode(self._local_file_captcha(captcha_file)).decode("utf-8")}
198
+ {image_key: base64.b64encode(self._local_file_captcha(captcha_file)).decode("utf-8")}
182
199
  )
183
200
  # if the file is transferred in base64 encoding
184
201
  elif captcha_base64:
185
202
  self.create_task_payload["task"].update(
186
- {"body": base64.b64encode(captcha_base64).decode("utf-8")}
203
+ {image_key: base64.b64encode(captcha_base64).decode("utf-8")}
187
204
  )
188
205
  # if a URL is passed
189
206
  elif captcha_link:
@@ -192,7 +209,9 @@ class BaseCaptcha:
192
209
  # according to the value of the passed parameter, select the function to save the image
193
210
  if save_format == SaveFormatsEnm.CONST.value:
194
211
  self._file_const_saver(content, file_path, file_extension=file_extension)
195
- self.create_task_payload["task"].update({"body": base64.b64encode(content).decode("utf-8")})
212
+ self.create_task_payload["task"].update(
213
+ {image_key: base64.b64encode(content).decode("utf-8")}
214
+ )
196
215
  except Exception as error:
197
216
  self.result.errorId = 12
198
217
  self.result.errorCode = self.NO_CAPTCHA_ERR
@@ -204,23 +223,24 @@ class BaseCaptcha:
204
223
 
205
224
  async def _aio_body_file_processing(
206
225
  self,
207
- save_format: SaveFormatsEnm,
226
+ save_format: SaveFormatsEnm | str,
208
227
  file_path: str,
209
228
  file_extension: str = "png",
229
+ image_key: str = "body",
210
230
  captcha_link: Optional[str] = None,
211
231
  captcha_file: Optional[str] = None,
212
232
  captcha_base64: Optional[bytes] = None,
213
- **kwargs,
233
+ **kwargs: dict[str, Any],
214
234
  ):
215
235
  # if a local file link is passed
216
236
  if captcha_file:
217
237
  self.create_task_payload["task"].update(
218
- {"body": base64.b64encode(self._local_file_captcha(captcha_file)).decode("utf-8")}
238
+ {image_key: base64.b64encode(self._local_file_captcha(captcha_file)).decode("utf-8")}
219
239
  )
220
240
  # if the file is transferred in base64 encoding
221
241
  elif captcha_base64:
222
242
  self.create_task_payload["task"].update(
223
- {"body": base64.b64encode(captcha_base64).decode("utf-8")}
243
+ {image_key: base64.b64encode(captcha_base64).decode("utf-8")}
224
244
  )
225
245
  # if a URL is passed
226
246
  elif captcha_link:
@@ -229,7 +249,9 @@ class BaseCaptcha:
229
249
  # according to the value of the passed parameter, select the function to save the image
230
250
  if save_format == SaveFormatsEnm.CONST.value:
231
251
  self._file_const_saver(content, file_path, file_extension=file_extension)
232
- self.create_task_payload["task"].update({"body": base64.b64encode(content).decode("utf-8")})
252
+ self.create_task_payload["task"].update(
253
+ {image_key: base64.b64encode(content).decode("utf-8")}
254
+ )
233
255
  except Exception as error:
234
256
  self.result.errorId = 12
235
257
  self.result.errorCode = self.NO_CAPTCHA_ERR
@@ -1,3 +1,5 @@
1
+ from typing import Generator
2
+
1
3
  from tenacity import AsyncRetrying, wait_fixed, stop_after_attempt
2
4
  from requests.adapters import Retry
3
5
 
@@ -8,7 +10,7 @@ APP_KEY = "1899"
8
10
 
9
11
 
10
12
  # Connection retry generator
11
- def attempts_generator(amount: int = 20):
13
+ def attempts_generator(amount: int = 20) -> Generator[int, None, None]:
12
14
  """
13
15
  Function generates a generator of length equal to `amount`
14
16
 
@@ -168,3 +168,11 @@ class ProsopoEnm(str, MyEnum):
168
168
 
169
169
  class CaptchaFoxEnm(str, MyEnum):
170
170
  CaptchaFoxTask = "CaptchaFoxTask"
171
+
172
+
173
+ class VKCaptchaEnm(str, MyEnum):
174
+ VKCaptchaTask = "VKCaptchaTask"
175
+
176
+
177
+ class TemuCaptchaEnm(str, MyEnum):
178
+ TemuCaptchaTask = "TemuCaptchaTask"
@@ -0,0 +1,116 @@
1
+ import time
2
+ import asyncio
3
+ import logging
4
+ from typing import Any
5
+
6
+ import aiohttp
7
+ import requests
8
+
9
+ from .config import attempts_generator
10
+ from .serializer import GetTaskResultRequestSer, GetTaskResultResponseSer
11
+
12
+
13
+ def get_sync_result(
14
+ get_payload: GetTaskResultRequestSer, sleep_time: int, url_response: str
15
+ ) -> dict[str, str]:
16
+ """
17
+ Periodically sends a synchronous request to a remote service to retrieve the result
18
+ of a CAPTCHA-solving task.
19
+
20
+ This function polls the service using blocking HTTP requests until the CAPTCHA is solved,
21
+ an error is returned, or the task times out. It handles intermediate states and retries
22
+ with a configurable sleep interval between attempts.
23
+
24
+ Args:
25
+ get_payload (GetTaskResultRequestSer):
26
+ Serialized request object containing the task ID and payload data.
27
+ sleep_time (int):
28
+ Time in seconds to wait between polling attempts when the task is still processing.
29
+ url_response (str):
30
+ Endpoint URL to query for the CAPTCHA-solving result.
31
+
32
+ Returns:
33
+ dict[str, str]:
34
+ A dictionary containing the final task result. If the task fails or an exception
35
+ occurs, the dictionary includes error details such as status, errorId, errorCode,
36
+ and errorDescription.
37
+ """
38
+ logging.warning(f"{url_response = }")
39
+ response_ser = GetTaskResultResponseSer(taskId=get_payload.taskId)
40
+ # generator for repeated attempts to connect to the server
41
+ attempts = attempts_generator()
42
+ for _ in attempts:
43
+ try:
44
+ # send a request for the result of solving the captcha
45
+ result: dict[str, Any] = requests.post(url_response, json=get_payload.to_dict()).json()
46
+ logging.info(f"Received captcha sync result - {result = }")
47
+ response_ser = GetTaskResultResponseSer(**result, taskId=get_payload.taskId)
48
+ # if the captcha has not been resolved yet, wait
49
+ if response_ser.status == "processing":
50
+ time.sleep(sleep_time)
51
+ continue
52
+ elif response_ser.status == "ready":
53
+ break
54
+ elif response_ser.errorId != 0:
55
+ return response_ser.to_dict()
56
+ except Exception as error:
57
+ response_ser.status = "failed"
58
+ response_ser.errorId = 12
59
+ response_ser.errorCode = "System error"
60
+ response_ser.errorDescription = str(error)
61
+ return response_ser.to_dict()
62
+
63
+
64
+ async def get_async_result(
65
+ get_payload: GetTaskResultRequestSer, sleep_time: int, url_response: str
66
+ ) -> dict[str, str]:
67
+ """
68
+ Periodically sends an asynchronous request to a remote service to retrieve the result
69
+ of a CAPTCHA-solving task.
70
+
71
+ This function polls the service at regular intervals until the CAPTCHA is solved,
72
+ an error occurs, or the task times out. It uses aiohttp for asynchronous HTTP requests
73
+ and handles various response states including 'processing', 'ready', and error conditions.
74
+
75
+ Args:
76
+ get_payload (GetTaskResultRequestSer):
77
+ Serialized request object containing the task ID and payload data.
78
+ sleep_time (int):
79
+ Time in seconds to wait between polling attempts when the task is still processing.
80
+ url_response (str):
81
+ Endpoint URL to query for the CAPTCHA-solving result.
82
+
83
+ Returns:
84
+ dict[str, str]:
85
+ A dictionary containing the final task result if successful or partially failed.
86
+ If an exception occurs during the request, returns a dictionary with error details
87
+ including status, errorId, errorCode, and errorDescription.
88
+ """
89
+ response_ser = GetTaskResultResponseSer(taskId=get_payload.taskId)
90
+ # generator for repeated attempts to connect to the server
91
+ attempts = attempts_generator()
92
+ async with aiohttp.ClientSession() as session:
93
+ for _ in attempts:
94
+ try:
95
+ # send a request for the result of solving the captcha
96
+ async with session.post(
97
+ url_response, json=get_payload.to_dict(), raise_for_status=True
98
+ ) as resp:
99
+ result: dict[str, Any] = await resp.json(content_type=None)
100
+ logging.info(f"Received captcha async result - {result = }")
101
+ response_ser = GetTaskResultResponseSer(**result, taskId=get_payload.taskId)
102
+
103
+ # if the captcha has not been resolved yet, wait
104
+ if response_ser.status == "processing":
105
+ await asyncio.sleep(sleep_time)
106
+ continue
107
+ elif response_ser.status == "ready":
108
+ break
109
+ elif response_ser.errorId != 0:
110
+ return response_ser.to_dict()
111
+ except Exception as error:
112
+ response_ser.status = "failed"
113
+ response_ser.errorId = 12
114
+ response_ser.errorCode = "System error"
115
+ response_ser.errorDescription = str(error)
116
+ return response_ser.to_dict()
@@ -0,0 +1,98 @@
1
+ from typing import Any, Literal
2
+ from decimal import Decimal
3
+ from datetime import date, datetime
4
+
5
+ from msgspec import Struct
6
+
7
+ from . import enums
8
+ from .config import APP_KEY
9
+
10
+
11
+ class MyBaseModel(Struct):
12
+ def to_dict(self) -> dict[str, Any]:
13
+ result = {}
14
+ for field in self.__struct_fields__:
15
+ value = getattr(self, field)
16
+
17
+ if isinstance(value, MyBaseModel):
18
+ result[field] = value.to_dict()
19
+
20
+ elif isinstance(value, (list, tuple)) and all(isinstance(el, Struct) for el in value):
21
+ result[field] = [el.to_dict() for el in value]
22
+
23
+ elif isinstance(value, (date, datetime)):
24
+ result[field] = value.isoformat()
25
+
26
+ elif isinstance(value, Decimal):
27
+ result[field] = str(value)
28
+
29
+ else:
30
+ result[field] = value
31
+
32
+ return result
33
+
34
+
35
+ """
36
+ HTTP API Serializers
37
+ """
38
+
39
+
40
+ class TaskSer(MyBaseModel):
41
+ type: str
42
+
43
+
44
+ class CreateTaskBaseSer(MyBaseModel):
45
+ clientKey: str
46
+ task: TaskSer
47
+ languagePool: str = "en"
48
+ callbackUrl: str | None = None
49
+ soft_id: Literal[APP_KEY] = APP_KEY
50
+
51
+
52
+ class GetTaskResultRequestSer(MyBaseModel):
53
+ clientKey: str
54
+ taskId: int | None = None
55
+
56
+
57
+ class CaptchaOptionsSer(MyBaseModel):
58
+ sleep_time: int = 10
59
+ service_type: enums.ServiceEnm | str = enums.ServiceEnm.TWOCAPTCHA
60
+
61
+ url_request: str = f"http://api.{enums.ServiceEnm.TWOCAPTCHA.value}.com/2captcha/in.php"
62
+ url_response: str = f"http://api.{enums.ServiceEnm.TWOCAPTCHA.value}.com/2captcha/res.php"
63
+
64
+ def urls_set(self):
65
+ """
66
+ Set request/response URLs if they not set previously
67
+ """
68
+ if isinstance(self.service_type, enums.ServiceEnm):
69
+ self.service_type = self.service_type.value
70
+
71
+ if self.service_type == enums.ServiceEnm.DEATHBYCAPTCHA:
72
+ self.url_request = f"http://api.{self.service_type}.com/2captcha/in.php"
73
+ self.url_response = f"http://api.{self.service_type}.com/2captcha/res.php"
74
+ else:
75
+ self.url_request = f"https://api.{self.service_type}.com/createTask"
76
+ self.url_response = f"https://api.{self.service_type}.com/getTaskResult"
77
+
78
+
79
+ """
80
+ HTTP API Response
81
+ """
82
+
83
+
84
+ class GetTaskResultResponseSer(MyBaseModel):
85
+ status: str = "ready"
86
+ solution: dict[str, str] | None = None
87
+ cost: float = 0.0
88
+ ip: str | None = None
89
+ createTime: int | None = None
90
+ endTime: int | None = None
91
+ solveCount: int | None = None
92
+ taskId: int | None = None
93
+ # control method params
94
+ balance: float | None = None
95
+ # error info
96
+ errorId: int = 0
97
+ errorCode: str | None = None
98
+ errorDescription: str | None = None
@@ -1,5 +1,5 @@
1
1
  import shutil
2
- from typing import Union, Optional
2
+ from typing import Any, Union, Optional
3
3
 
4
4
  from .core.base import BaseCaptcha
5
5
  from .core.enums import SaveFormatsEnm, ImageCaptchaEnm
@@ -181,8 +181,8 @@ class ImageCaptcha(BaseCaptcha):
181
181
  captcha_link: Optional[str] = None,
182
182
  captcha_file: Optional[str] = None,
183
183
  captcha_base64: Optional[bytes] = None,
184
- **kwargs,
185
- ) -> dict:
184
+ **kwargs: dict[str, Any],
185
+ ) -> dict[str, Any]:
186
186
  """
187
187
  Sync solving method
188
188
 
@@ -215,8 +215,8 @@ class ImageCaptcha(BaseCaptcha):
215
215
  captcha_link: Optional[str] = None,
216
216
  captcha_file: Optional[str] = None,
217
217
  captcha_base64: Optional[bytes] = None,
218
- **kwargs,
219
- ) -> dict:
218
+ **kwargs: dict[str, Any],
219
+ ) -> dict[str, Any]:
220
220
  """
221
221
  Async solving method
222
222
 
@@ -0,0 +1,152 @@
1
+ import shutil
2
+ from typing import Any, Union
3
+
4
+ from .core.base import BaseCaptcha
5
+ from .core.enums import SaveFormatsEnm, TemuCaptchaEnm
6
+
7
+
8
+ class TemuCaptcha(BaseCaptcha):
9
+ def __init__(
10
+ self,
11
+ save_format: Union[str, SaveFormatsEnm] = SaveFormatsEnm.TEMP,
12
+ img_clearing: bool = True,
13
+ img_path: str = "PythonRuCaptchaImages",
14
+ *args,
15
+ **kwargs: dict[str, Any],
16
+ ):
17
+ """
18
+ Solve TemuImageTask CAPTCHA via 2Captcha/RuCaptcha API.
19
+
20
+ This class creates and monitors TemuImageTask jobs, which require
21
+ a base64‐encoded background image plus an array of movable image
22
+ pieces (parts) in base64 format. It extends BaseCaptcha to handle
23
+ the low‐level request/response workflow.
24
+
25
+ Args:
26
+ save_format (str | SaveFormatsEnm): Where to save temporary images.
27
+ - SaveFormatsEnm.TEMP: use system temp directory
28
+ - SaveFormatsEnm.CONST: keep files in img_path until deletion
29
+ img_clearing (bool): If True and save_format is CONST, delete the
30
+ img_path directory when this instance is destroyed.
31
+ img_path (str): Directory under which to store downloaded or decoded
32
+ images before sending to the API.
33
+ *args: Positional args forwarded to BaseCaptcha constructor (e.g.
34
+ client_key, method override).
35
+ **kwargs: Keyword args forwarded to BaseCaptcha for task creation.
36
+ Common params include:
37
+ - redirectUri: URL to confirm CAPTCHA resolution
38
+ - any other API‐supported parameters
39
+
40
+ Examples:
41
+ >>> captcha = TemuCaptcha(rucaptcha_key="YOUR_API_KEY")
42
+ >>> response = captcha.captcha_handler(
43
+ ... parts=["part1_b64", "part2_b64", "part3_b64"],
44
+ ... captcha_base64=b"full_image_b64"
45
+ ... )
46
+ >>> print(response)
47
+ {
48
+ "errorId": 0,
49
+ "status": "ready",
50
+ "solution": {
51
+ "coordinates": [{"x":155,"y":358}, {"x":152,"y":153}, {"x":251,"y":333}]
52
+ },
53
+ "cost": "0.0012",
54
+ "createTime": 1754563182,
55
+ "endTime": 1754563190,
56
+ "taskId": 80306543329,
57
+ "ip": "46.53.232.76",
58
+ "solveCount": 1
59
+ }
60
+
61
+ Notes:
62
+ https://2captcha.com/api-docs/temu-captcha
63
+
64
+ https://rucaptcha.com/api-docs/temu-captcha
65
+ """
66
+ super().__init__(method=TemuCaptchaEnm.TemuCaptchaTask, *args, **kwargs)
67
+
68
+ self.save_format = save_format
69
+ self.img_clearing = img_clearing
70
+ self.img_path = img_path
71
+
72
+ def captcha_handler(
73
+ self,
74
+ parts: list[str],
75
+ captcha_link: str | None = None,
76
+ captcha_file: str | None = None,
77
+ captcha_base64: bytes | None = None,
78
+ **kwargs: dict[str, Any],
79
+ ) -> dict[str, Any]:
80
+ """
81
+ Synchronously solve a TemuImageTask.
82
+
83
+ Args:
84
+ parts (list[str]): List of base64‐encoded strings for each
85
+ movable image piece.
86
+ captcha_link (str | None): URL to background image. Overrides
87
+ captcha_file and captcha_base64 if provided.
88
+ captcha_file (str | None): Path to an image file to read & send.
89
+ captcha_base64 (bytes | None): Raw bytes or base64 string of
90
+ the background image.
91
+ **kwargs: Passed through to the HTTP request call (e.g. timeout,
92
+ headers).
93
+
94
+ Returns:
95
+ dict[str, Any]: Full JSON response from the 2Captcha/RuCaptcha API,
96
+ including errorId, taskId, status, solution, cost, times, etc.
97
+ """
98
+ self.create_task_payload["task"].update({"parts": parts})
99
+ self._body_file_processing(
100
+ save_format=self.save_format,
101
+ file_path=self.img_path,
102
+ captcha_link=captcha_link,
103
+ captcha_file=captcha_file,
104
+ captcha_base64=captcha_base64,
105
+ image_key="image",
106
+ **kwargs,
107
+ )
108
+ if not self.result.errorId:
109
+ return self._processing_response(**kwargs)
110
+ return self.result.to_dict()
111
+
112
+ async def aio_captcha_handler(
113
+ self,
114
+ parts: list[str],
115
+ captcha_link: str | None = None,
116
+ captcha_file: str | None = None,
117
+ captcha_base64: bytes | None = None,
118
+ ) -> dict[str, Any]:
119
+ """
120
+ Asynchronously solve a TemuImageTask.
121
+
122
+ Args:
123
+ parts (list[str]): List of base64‐encoded strings for each
124
+ movable image piece.
125
+ captcha_link (str | None): URL to background image.
126
+ captcha_file (str | None): Path to an image file to read & send.
127
+ captcha_base64 (bytes | None): Raw bytes or base64 string of image.
128
+ **kwargs: Passed through to the async HTTP request call.
129
+
130
+ Returns:
131
+ dict[str, Any]: API response containing task status and solution.
132
+ """
133
+ self.create_task_payload["task"].update({"parts": parts})
134
+ await self._aio_body_file_processing(
135
+ save_format=self.save_format,
136
+ file_path=self.img_path,
137
+ captcha_link=captcha_link,
138
+ captcha_file=captcha_file,
139
+ captcha_base64=captcha_base64,
140
+ image_key="image",
141
+ **kwargs,
142
+ )
143
+ if not self.result.errorId:
144
+ return await self._aio_processing_response()
145
+ return self.result.to_dict()
146
+
147
+ def __del__(self):
148
+ """
149
+ Cleanup saved images folder if configured to do so.
150
+ """
151
+ if self.save_format == SaveFormatsEnm.CONST.value and self.img_clearing:
152
+ shutil.rmtree(self.img_path)
@@ -0,0 +1,120 @@
1
+ from typing import Any
2
+
3
+ from .core.base import BaseCaptcha
4
+ from .core.enums import VKCaptchaEnm
5
+
6
+
7
+ class VKCaptcha(BaseCaptcha):
8
+ def __init__(
9
+ self,
10
+ redirectUri: str,
11
+ userAgent: str,
12
+ proxyType: str,
13
+ proxyAddress: str,
14
+ proxyPort: str,
15
+ *args,
16
+ **kwargs: dict[str, Any],
17
+ ):
18
+ """
19
+ The class is used to work with VKCaptchaTask.
20
+
21
+ Args:
22
+ rucaptcha_key: User API key
23
+ redirectUri: The URL that is returned on requests to the captcha API.
24
+ userAgent: User-Agent of your browser will be used to load the captcha.
25
+ Use only modern browser's User-Agents
26
+ proxyType: Proxy type - `http`, `socks4`, `socks5`
27
+ proxyAddress: Proxy IP address or hostname
28
+ proxyPort: Proxy port
29
+ method: Captcha type
30
+ kwargs: Not required params for task creation request
31
+
32
+ Examples:
33
+ >>> VKCaptcha(rucaptcha_key="aa9011f31111181111168611f1151122",
34
+ ... redirectUri="https://id.vk.com/not_robot_captcha?domain=vk.com...",
35
+ ... userAgent="Mozilla/5.0 .....",
36
+ ... proxyType="socks5",
37
+ ... proxyAddress="1.2.3.4",
38
+ ... proxyPort="445",
39
+ ... ).captcha_handler()
40
+ {
41
+ "errorId":0,
42
+ "status":"ready",
43
+ "solution":{
44
+ "token":"142000f.....er"
45
+ },
46
+ "cost":"0.002",
47
+ "ip":"1.2.3.4",
48
+ "createTime":1692863536,
49
+ "endTime":1692863556,
50
+ "solveCount":0,
51
+ "taskId": 73243152973,
52
+ }
53
+
54
+ >>> await VKCaptcha(rucaptcha_key="aa9011f31111181111168611f1151122",
55
+ ... redirectUri="https://id.vk.com/not_robot_captcha?domain=vk.com...",
56
+ ... userAgent="Mozilla/5.0 .....",
57
+ ... proxyType="socks5",
58
+ ... proxyAddress="1.2.3.4",
59
+ ... proxyPort="445",
60
+ ... ).aio_captcha_handler()
61
+ {
62
+ "errorId":0,
63
+ "status":"ready",
64
+ "solution":{
65
+ "token":"142000f.....er"
66
+ },
67
+ "cost":"0.002",
68
+ "ip":"1.2.3.4",
69
+ "createTime":1692863536,
70
+ "endTime":1692863556,
71
+ "solveCount":0,
72
+ "taskId": 73243152973,
73
+ }
74
+
75
+ Returns:
76
+ Dict with full server response
77
+
78
+ Notes:
79
+ https://2captcha.com/api-docs/vk-captcha
80
+
81
+ https://rucaptcha.com/api-docs/vk-captcha
82
+ """
83
+ super().__init__(method=VKCaptchaEnm.VKCaptchaTask, *args, **kwargs)
84
+
85
+ self.create_task_payload["task"].update(
86
+ {
87
+ "websiteURL": redirectUri,
88
+ "userAgent": userAgent,
89
+ "proxyType": proxyType,
90
+ "proxyAddress": proxyAddress,
91
+ "proxyPort": proxyPort,
92
+ }
93
+ )
94
+
95
+ def captcha_handler(self, **kwargs: dict[str, Any]) -> dict[str, Any]:
96
+ """
97
+ Sync solving method
98
+
99
+ Args:
100
+ kwargs: additional params for `requests` library
101
+
102
+ Returns:
103
+ Dict with full server response
104
+
105
+ Notes:
106
+ Check class docstirng for more info
107
+ """
108
+ return self._processing_response(**kwargs)
109
+
110
+ async def aio_captcha_handler(self) -> dict[str, Any]:
111
+ """
112
+ Async solving method
113
+
114
+ Returns:
115
+ Dict with full server response
116
+
117
+ Notes:
118
+ Check class docstirng for more info
119
+ """
120
+ return await self._aio_processing_response()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python-rucaptcha
3
- Version: 6.4.0
3
+ Version: 6.5.0
4
4
  Summary: Python 3.9+ RuCaptcha library with AIO module.
5
5
  Author-email: AndreiDrang <python-captcha@pm.me>
6
6
  License-Expression: MIT
@@ -9,7 +9,7 @@ Project-URL: Documentation, https://andreidrang.github.io/python-rucaptcha/
9
9
  Project-URL: Repository, https://github.com/AndreiDrang/python-rucaptcha
10
10
  Project-URL: Issues, https://github.com/AndreiDrang/python-rucaptcha/issues
11
11
  Project-URL: Changelog, https://github.com/AndreiDrang/python-rucaptcha/releases
12
- Keywords: captcha,rucaptcha,2captcha,deathbycaptcha,recaptcha,geetest,hcaptcha,capypuzzle,rotatecaptcha,funcaptcha,keycaptcha,python3,recaptcha,captcha,security,tencent,atb_captcha,python-library,python-rucaptcha,rucaptcha-client,yandex,turnstile,amazon,amazon_waf,friendly-captcha
12
+ Keywords: captcha,rucaptcha,2captcha,deathbycaptcha,recaptcha,geetest,hcaptcha,capypuzzle,rotatecaptcha,funcaptcha,keycaptcha,python3,recaptcha,captcha,security,tencent,atb_captcha,python-library,python-rucaptcha,rucaptcha-client,yandex,turnstile,amazon,amazon_waf,vk-captcha,fox-captcha,temu-captcha,friendly-captcha
13
13
  Classifier: Development Status :: 5 - Production/Stable
14
14
  Classifier: Programming Language :: Python
15
15
  Classifier: Programming Language :: Python :: 3
@@ -18,6 +18,7 @@ Classifier: Programming Language :: Python :: 3.9
18
18
  Classifier: Programming Language :: Python :: 3.10
19
19
  Classifier: Programming Language :: Python :: 3.11
20
20
  Classifier: Programming Language :: Python :: 3.12
21
+ Classifier: Programming Language :: Python :: 3.13
21
22
  Classifier: Framework :: AsyncIO
22
23
  Classifier: Operating System :: Unix
23
24
  Classifier: Operating System :: Microsoft :: Windows
@@ -28,9 +28,11 @@ src/python_rucaptcha/mt_captcha.py
28
28
  src/python_rucaptcha/prosopo.py
29
29
  src/python_rucaptcha/re_captcha.py
30
30
  src/python_rucaptcha/rotate_captcha.py
31
+ src/python_rucaptcha/temu_captcha.py
31
32
  src/python_rucaptcha/tencent.py
32
33
  src/python_rucaptcha/text_captcha.py
33
34
  src/python_rucaptcha/turnstile.py
35
+ src/python_rucaptcha/vk_captcha.py
34
36
  src/python_rucaptcha.egg-info/PKG-INFO
35
37
  src/python_rucaptcha.egg-info/SOURCES.txt
36
38
  src/python_rucaptcha.egg-info/dependency_links.txt
@@ -1 +0,0 @@
1
- __version__ = "6.4.0"
@@ -1,69 +0,0 @@
1
- import time
2
- import asyncio
3
- import logging
4
- from typing import Union
5
-
6
- import aiohttp
7
- import requests
8
-
9
- from .config import attempts_generator
10
- from .serializer import GetTaskResultRequestSer, GetTaskResultResponseSer
11
-
12
-
13
- def get_sync_result(
14
- get_payload: GetTaskResultRequestSer, sleep_time: int, url_response: str
15
- ) -> Union[dict, Exception]:
16
- """
17
- Function periodically send the SYNC request to service and wait for captcha solving result
18
- """
19
- # generator for repeated attempts to connect to the server
20
- attempts = attempts_generator()
21
- for _ in attempts:
22
- try:
23
- # send a request for the result of solving the captcha
24
- captcha_response = GetTaskResultResponseSer(
25
- **requests.post(url_response, json=get_payload.to_dict()).json(), taskId=get_payload.taskId
26
- )
27
- logging.warning(f"{captcha_response = }")
28
- # if the captcha has not been resolved yet, wait
29
- if captcha_response.status == "processing":
30
- time.sleep(sleep_time)
31
- continue
32
- elif captcha_response.status == "ready":
33
- break
34
- elif captcha_response.errorId != 0:
35
- return captcha_response.to_dict()
36
- except Exception as error:
37
- return error
38
- return captcha_response.to_dict()
39
-
40
-
41
- async def get_async_result(
42
- get_payload: GetTaskResultRequestSer, sleep_time: int, url_response: str
43
- ) -> Union[dict, Exception]:
44
- """
45
- Function periodically send the ASYNC request to service and wait for captcha solving result
46
- """
47
- # generator for repeated attempts to connect to the server
48
- attempts = attempts_generator()
49
- async with aiohttp.ClientSession() as session:
50
- for _ in attempts:
51
- try:
52
- # send a request for the result of solving the captcha
53
- async with session.post(
54
- url_response, json=get_payload.to_dict(), raise_for_status=True
55
- ) as resp:
56
- captcha_response = await resp.json(content_type=None)
57
- captcha_response = GetTaskResultResponseSer(**captcha_response, taskId=get_payload.taskId)
58
-
59
- # if the captcha has not been resolved yet, wait
60
- if captcha_response.status == "processing":
61
- await asyncio.sleep(sleep_time)
62
- continue
63
- elif captcha_response.status == "ready":
64
- break
65
- elif captcha_response.errorId != 0:
66
- return captcha_response.to_dict()
67
- except Exception as error:
68
- return error
69
- return captcha_response.to_dict()
@@ -1,74 +0,0 @@
1
- from typing import Literal, Optional
2
-
3
- from msgspec import Struct
4
-
5
- from . import enums
6
- from .config import APP_KEY
7
-
8
-
9
- class MyBaseModel(Struct):
10
- def to_dict(self):
11
- return {f: getattr(self, f) for f in self.__struct_fields__}
12
-
13
-
14
- """
15
- HTTP API Serializers
16
- """
17
-
18
-
19
- class TaskSer(MyBaseModel):
20
- type: str
21
-
22
-
23
- class CreateTaskBaseSer(MyBaseModel):
24
- clientKey: str
25
- task: TaskSer = {}
26
- languagePool: str = "en"
27
- callbackUrl: str = None
28
- soft_id: Literal[APP_KEY] = APP_KEY
29
-
30
-
31
- class GetTaskResultRequestSer(MyBaseModel):
32
- clientKey: str
33
- taskId: int = None
34
-
35
-
36
- class CaptchaOptionsSer(MyBaseModel):
37
- sleep_time: int = 10
38
- service_type: enums.ServiceEnm = enums.ServiceEnm.TWOCAPTCHA.value
39
-
40
- url_request: Optional[str] = None
41
- url_response: Optional[str] = None
42
-
43
- def urls_set(self):
44
- """
45
- Set request/response URLs if they not set previously
46
- """
47
- if self.service_type == enums.ServiceEnm.DEATHBYCAPTCHA:
48
- self.url_request = f"http://api.{self.service_type}.com/2captcha/in.php"
49
- self.url_response = f"http://api.{self.service_type}.com/2captcha/res.php"
50
- else:
51
- self.url_request = f"https://api.{self.service_type}.com/createTask"
52
- self.url_response = f"https://api.{self.service_type}.com/getTaskResult"
53
-
54
-
55
- """
56
- HTTP API Response
57
- """
58
-
59
-
60
- class GetTaskResultResponseSer(MyBaseModel):
61
- status: str = "ready"
62
- solution: dict = None
63
- cost: float = None
64
- ip: str = None
65
- createTime: int = None
66
- endTime: int = None
67
- solveCount: int = None
68
- taskId: int = None
69
- # control method params
70
- balance: float = None
71
- # error info
72
- errorId: int = 0
73
- errorCode: str = None
74
- errorDescription: str = None