python3-capsolver 0.9.4__py3-none-any.whl → 1.0.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.
Files changed (33) hide show
  1. python3_capsolver/__version__.py +1 -1
  2. python3_capsolver/aws_waf.py +122 -95
  3. python3_capsolver/cloudflare.py +113 -96
  4. python3_capsolver/control.py +31 -29
  5. python3_capsolver/core/aio_captcha_instrument.py +109 -0
  6. python3_capsolver/core/base.py +49 -194
  7. python3_capsolver/core/captcha_instrument.py +145 -0
  8. python3_capsolver/core/const.py +27 -0
  9. python3_capsolver/core/context_instr.py +25 -0
  10. python3_capsolver/core/enum.py +21 -76
  11. python3_capsolver/core/serializer.py +35 -128
  12. python3_capsolver/core/sio_captcha_instrument.py +116 -0
  13. python3_capsolver/core/{config.py → utils.py} +1 -10
  14. python3_capsolver/datadome_slider.py +56 -84
  15. python3_capsolver/friendly_captcha.py +105 -0
  16. python3_capsolver/gee_test.py +58 -90
  17. python3_capsolver/image_to_text.py +86 -116
  18. python3_capsolver/mt_captcha.py +49 -108
  19. python3_capsolver/recaptcha.py +65 -129
  20. python3_capsolver/vision_engine.py +102 -0
  21. python3_capsolver/yandex.py +73 -0
  22. {python3_capsolver-0.9.4.dist-info → python3_capsolver-1.0.1.dist-info}/METADATA +12 -12
  23. python3_capsolver-1.0.1.dist-info/RECORD +28 -0
  24. {python3_capsolver-0.9.4.dist-info → python3_capsolver-1.0.1.dist-info}/WHEEL +1 -1
  25. python3_capsolver/akamai.py +0 -192
  26. python3_capsolver/binance.py +0 -112
  27. python3_capsolver/cyber_si_ara.py +0 -128
  28. python3_capsolver/fun_captcha.py +0 -251
  29. python3_capsolver/hcaptcha.py +0 -197
  30. python3_capsolver/imperva.py +0 -120
  31. python3_capsolver-0.9.4.dist-info/RECORD +0 -26
  32. {python3_capsolver-0.9.4.dist-info → python3_capsolver-1.0.1.dist-info}/LICENSE +0 -0
  33. {python3_capsolver-0.9.4.dist-info → python3_capsolver-1.0.1.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,109 @@
1
+ import asyncio
2
+ import logging
3
+ from typing import Optional
4
+ from urllib import parse
5
+
6
+ import aiohttp
7
+
8
+ from .enum import ResponseStatusEnm, EndpointPostfixEnm
9
+ from .const import REQUEST_URL, VALID_STATUS_CODES, GET_BALANCE_POSTFIX
10
+ from .utils import attempts_generator
11
+ from .serializer import CaptchaResponseSer
12
+ from .captcha_instrument import CaptchaInstrument
13
+
14
+ __all__ = ("AIOCaptchaInstrument",)
15
+
16
+
17
+ class AIOCaptchaInstrument(CaptchaInstrument):
18
+ """
19
+ Instrument for working with async captcha
20
+ """
21
+
22
+ def __init__(self, captcha_params: "CaptchaParams"):
23
+ super().__init__()
24
+ self.captcha_params = captcha_params
25
+ self.created_task_data = CaptchaResponseSer
26
+
27
+ async def processing_captcha(self) -> dict:
28
+ self.captcha_params.create_task_payload.task = self.captcha_params.task_params
29
+ self.created_task_data = CaptchaResponseSer(**await self.__create_task())
30
+
31
+ # if task created and already ready - return result
32
+ if self.created_task_data.errorId == 0 and self.created_task_data.status == ResponseStatusEnm.Processing.value:
33
+ return (await self.__get_result()).to_dict()
34
+ elif self.created_task_data.errorId != 0:
35
+ self.created_task_data.status = ResponseStatusEnm.Failed
36
+
37
+ return self.created_task_data.to_dict()
38
+
39
+ async def __create_task(self, url_postfix: str = EndpointPostfixEnm.CREATE_TASK.value) -> dict:
40
+ """
41
+ Function send the ASYNC request to service and wait for result
42
+ """
43
+ async with aiohttp.ClientSession() as session:
44
+ try:
45
+ async with session.post(
46
+ parse.urljoin(self.captcha_params.request_url, url_postfix),
47
+ json=self.captcha_params.create_task_payload.to_dict(),
48
+ ) as resp:
49
+ if resp.status in VALID_STATUS_CODES:
50
+ return await resp.json()
51
+ else:
52
+ raise ValueError(resp.reason)
53
+ except Exception as error:
54
+ logging.exception(error)
55
+ raise
56
+
57
+ async def __get_result(self, url_postfix: str = EndpointPostfixEnm.GET_TASK_RESULT.value) -> CaptchaResponseSer:
58
+ """
59
+ Function send the ASYNC request to service and wait for result
60
+ """
61
+ # initial waiting
62
+ await asyncio.sleep(self.captcha_params.sleep_time)
63
+
64
+ self.captcha_params.get_result_params.taskId = self.created_task_data.taskId
65
+ attempts = attempts_generator()
66
+ async with aiohttp.ClientSession() as session:
67
+ for _ in attempts:
68
+ try:
69
+ async with session.post(
70
+ parse.urljoin(self.captcha_params.request_url, url_postfix),
71
+ json=self.captcha_params.get_result_params.to_dict(),
72
+ ) as resp:
73
+ if resp.status in VALID_STATUS_CODES:
74
+ result_data = CaptchaResponseSer(**await resp.json())
75
+ if result_data.status in (ResponseStatusEnm.Ready, ResponseStatusEnm.Failed):
76
+ # if captcha ready\failed or have unknown status - return exist data
77
+ return result_data
78
+ else:
79
+ raise ValueError(resp.reason)
80
+ except Exception as error:
81
+ logging.exception(error)
82
+ raise
83
+
84
+ # if captcha just created or in processing now - wait
85
+ await asyncio.sleep(self.captcha_params.sleep_time)
86
+
87
+ # default response if server is silent
88
+ self.result.errorId = 1
89
+ self.result.errorCode = self.CAPTCHA_UNSOLVABLE
90
+ self.result.errorDescription = "Captcha not recognized"
91
+ self.result.taskId = self.created_task_data.taskId
92
+ self.result.status = ResponseStatusEnm.Failed
93
+
94
+ @staticmethod
95
+ async def send_post_request(payload: Optional[dict] = None, url_postfix: str = GET_BALANCE_POSTFIX) -> dict:
96
+ """
97
+ Function send ASYNC request to service and wait for result
98
+ """
99
+
100
+ async with aiohttp.ClientSession() as session:
101
+ try:
102
+ async with session.post(parse.urljoin(REQUEST_URL, url_postfix), json=payload) as resp:
103
+ if resp.status == 200:
104
+ return await resp.json()
105
+ else:
106
+ raise ValueError(resp.status)
107
+ except Exception as error:
108
+ logging.exception(error)
109
+ raise
@@ -1,25 +1,19 @@
1
- import time
2
- import asyncio
3
- import logging
4
- from typing import Any, Dict, Type
5
- from urllib import parse
1
+ from typing import Any, Dict
6
2
 
7
- import aiohttp
8
- import requests
9
- from pydantic import BaseModel
10
- from requests.adapters import HTTPAdapter
3
+ from python3_capsolver.core.enum import CaptchaTypeEnm
4
+ from python3_capsolver.core.serializer import TaskSer
11
5
 
12
- from python3_capsolver.core.enum import ResponseStatusEnm, EndpointPostfixEnm
13
- from python3_capsolver.core.config import RETRIES, REQUEST_URL, VALID_STATUS_CODES, attempts_generator
14
- from python3_capsolver.core.serializer import (
15
- CaptchaOptionsSer,
16
- CaptchaResponseSer,
17
- RequestCreateTaskSer,
18
- RequestGetTaskResultSer,
19
- )
6
+ from .const import REQUEST_URL
7
+ from .serializer import RequestCreateTaskSer, RequestGetTaskResultSer
8
+ from .context_instr import AIOContextManager, SIOContextManager
9
+ from .captcha_instrument import CaptchaInstrument
10
+ from .aio_captcha_instrument import AIOCaptchaInstrument
11
+ from .sio_captcha_instrument import SIOCaptchaInstrument
20
12
 
13
+ __all__ = ("CaptchaParams",)
21
14
 
22
- class BaseCaptcha:
15
+
16
+ class CaptchaParams(SIOContextManager, AIOContextManager):
23
17
  """
24
18
  Basic Captcha solving class
25
19
 
@@ -33,195 +27,56 @@ class BaseCaptcha:
33
27
  def __init__(
34
28
  self,
35
29
  api_key: str,
30
+ captcha_type: CaptchaTypeEnm,
36
31
  sleep_time: int = 5,
37
32
  request_url: str = REQUEST_URL,
38
- **kwargs,
39
33
  ):
40
34
  # assign args to validator
41
- self.__params = CaptchaOptionsSer(**locals())
42
- self.__request_url = request_url
43
-
44
- # prepare session
45
- self.__session = requests.Session()
46
- self.__session.mount("http://", HTTPAdapter(max_retries=RETRIES))
47
- self.__session.mount("https://", HTTPAdapter(max_retries=RETRIES))
48
-
49
- def _prepare_create_task_payload(self, serializer: Type[BaseModel], create_params: Dict[str, Any] = None) -> None:
35
+ self.create_task_payload = RequestCreateTaskSer(clientKey=api_key)
36
+ # `task` body for task creation payload
37
+ self.task_params = TaskSer(type=captcha_type.value).to_dict()
38
+ # prepare `get task result` payload
39
+ self.get_result_params = RequestGetTaskResultSer(clientKey=api_key)
40
+ self.request_url = request_url
41
+ self._captcha_handling_instrument = CaptchaInstrument()
42
+ self.sleep_time = sleep_time
43
+
44
+ def captcha_handler(self, task_payload: Dict) -> Dict[str, Any]:
50
45
  """
51
- Method prepare `createTask` payload
46
+ Synchronous method for captcha solving
52
47
 
53
48
  Args:
54
- serializer: Serializer for task creation
55
- create_params: Parameters for task creation payload
56
-
57
- Examples:
58
-
59
- >>> self._prepare_create_task_payload(serializer=PostRequestSer, create_params={})
60
-
61
- """
62
- self.task_payload = serializer(clientKey=self.__params.api_key)
63
- # added task params to payload
64
- self.task_payload.task = {**create_params} if create_params else {}
65
-
66
- def __enter__(self):
67
- return self
68
-
69
- def __exit__(self, exc_type, exc_value, traceback):
70
- if exc_type:
71
- return False
72
- return True
73
-
74
- async def __aenter__(self):
75
- return self
76
-
77
- async def __aexit__(self, exc_type, exc_value, traceback):
78
- if exc_type:
79
- return False
80
- return True
81
-
82
- """
83
- Sync part
84
- """
85
-
86
- def _processing_captcha(
87
- self, create_params: dict, serializer: Type[BaseModel] = RequestCreateTaskSer
88
- ) -> CaptchaResponseSer:
89
- self._prepare_create_task_payload(serializer=serializer, create_params=create_params)
90
- self.created_task_data = CaptchaResponseSer(**self._create_task())
49
+ task_payload: Some additional parameters that will be used in creating the task
50
+ and will be passed to the payload under ``task`` key.
51
+ Like ``websiteURL``, ``image``, ``proxyPassword``, ``websiteKey`` and etc.
52
+ more info in service docs
91
53
 
92
- # if task created and ready - return result
93
- if self.created_task_data.status == ResponseStatusEnm.Ready.value:
94
- return self.created_task_data
95
- # if captcha is not ready but task success created - waiting captcha result
96
- elif self.created_task_data.errorId == 0:
97
- return self._get_result()
98
- return self.created_task_data
54
+ Returns:
55
+ Dict with full server response
99
56
 
100
- def _create_task(self, url_postfix: str = EndpointPostfixEnm.CREATE_TASK.value) -> dict:
57
+ Notes:
58
+ Check class docstirng for more info
101
59
  """
102
- Function send SYNC request to service and wait for result
103
- """
104
- try:
105
- resp = self.__session.post(
106
- parse.urljoin(self.__request_url, url_postfix), json=self.task_payload.dict(exclude_none=True)
107
- )
108
- if resp.status_code in VALID_STATUS_CODES:
109
- return resp.json()
110
- else:
111
- raise ValueError(resp.raise_for_status())
112
- except Exception as error:
113
- logging.exception(error)
114
- raise
60
+ self.task_params.update(task_payload)
61
+ self._captcha_handling_instrument = SIOCaptchaInstrument(captcha_params=self)
62
+ return self._captcha_handling_instrument.processing_captcha()
115
63
 
116
- def _get_result(self, url_postfix: str = EndpointPostfixEnm.GET_TASK_RESULT.value) -> CaptchaResponseSer:
117
- """
118
- Method send SYNC request to service and wait for result
64
+ async def aio_captcha_handler(self, task_payload: Dict) -> Dict[str, Any]:
119
65
  """
120
- # initial waiting
121
- time.sleep(self.__params.sleep_time)
122
-
123
- get_result_payload = RequestGetTaskResultSer(
124
- clientKey=self.__params.api_key, taskId=self.created_task_data.taskId
125
- )
126
- attempts = attempts_generator()
127
- for _ in attempts:
128
- try:
129
- resp = self.__session.post(
130
- parse.urljoin(self.__request_url, url_postfix), json=get_result_payload.dict(exclude_none=True)
131
- )
132
- if resp.status_code in VALID_STATUS_CODES:
133
- result_data = CaptchaResponseSer(**resp.json())
134
- if result_data.status in (ResponseStatusEnm.Ready, ResponseStatusEnm.Failed):
135
- # if captcha ready\failed or have unknown status - return exist data
136
- return result_data
137
- else:
138
- raise ValueError(resp.raise_for_status())
139
- except Exception as error:
140
- logging.exception(error)
141
- raise
142
-
143
- # if captcha just created or in processing now - wait
144
- time.sleep(self.__params.sleep_time)
145
- # default response if server is silent
146
- return CaptchaResponseSer(
147
- errorId=1,
148
- errorCode="ERROR_CAPTCHA_UNSOLVABLE",
149
- errorDescription="Captcha not recognized",
150
- taskId=self.created_task_data.taskId,
151
- status=ResponseStatusEnm.Failed,
152
- )
153
-
154
- """
155
- Async part
156
- """
157
-
158
- async def _aio_processing_captcha(
159
- self, create_params: dict, serializer: Type[BaseModel] = RequestCreateTaskSer
160
- ) -> CaptchaResponseSer:
161
- self._prepare_create_task_payload(serializer=serializer, create_params=create_params)
162
- self.created_task_data = CaptchaResponseSer(**await self._aio_create_task())
66
+ Asynchronous method for captcha solving
163
67
 
164
- # if task created and already ready - return result
165
- if self.created_task_data.status == ResponseStatusEnm.Ready.value:
166
- return self.created_task_data
167
- # if captcha is not ready but task success created - waiting captcha result
168
- elif self.created_task_data.errorId == 0:
169
- return await self._aio_get_result()
170
- return self.created_task_data
68
+ Args:
69
+ task_payload: Some additional parameters that will be used in creating the task
70
+ and will be passed to the payload under ``task`` key.
71
+ Like ``websiteURL``, ``image``, ``proxyPassword``, ``websiteKey`` and etc.
72
+ more info in service docs
171
73
 
172
- async def _aio_create_task(self, url_postfix: str = EndpointPostfixEnm.CREATE_TASK.value) -> dict:
173
- """
174
- Function send the ASYNC request to service and wait for result
175
- """
176
- async with aiohttp.ClientSession() as session:
177
- try:
178
- async with session.post(
179
- parse.urljoin(self.__request_url, url_postfix), json=self.task_payload.dict(exclude_none=True)
180
- ) as resp:
181
- if resp.status in VALID_STATUS_CODES:
182
- return await resp.json()
183
- else:
184
- raise ValueError(resp.reason)
185
- except Exception as error:
186
- logging.exception(error)
187
- raise
74
+ Returns:
75
+ Dict with full server response
188
76
 
189
- async def _aio_get_result(self, url_postfix: str = EndpointPostfixEnm.GET_TASK_RESULT.value) -> CaptchaResponseSer:
190
- """
191
- Function send the ASYNC request to service and wait for result
77
+ Notes:
78
+ Check class docstirng for more info
192
79
  """
193
- # initial waiting
194
- await asyncio.sleep(self.__params.sleep_time)
195
-
196
- get_result_payload = RequestGetTaskResultSer(
197
- clientKey=self.__params.api_key, taskId=self.created_task_data.taskId
198
- )
199
- attempts = attempts_generator()
200
- async with aiohttp.ClientSession() as session:
201
- for _ in attempts:
202
- try:
203
- async with session.post(
204
- parse.urljoin(self.__request_url, url_postfix), json=get_result_payload.dict(exclude_none=True)
205
- ) as resp:
206
- if resp.status in VALID_STATUS_CODES:
207
- result_data = CaptchaResponseSer(**await resp.json())
208
- if result_data.status in (ResponseStatusEnm.Ready, ResponseStatusEnm.Failed):
209
- # if captcha ready\failed or have unknown status - return exist data
210
- return result_data
211
- else:
212
- raise ValueError(resp.reason)
213
- except Exception as error:
214
- logging.exception(error)
215
- raise
216
-
217
- # if captcha just created or in processing now - wait
218
- await asyncio.sleep(self.__params.sleep_time)
219
-
220
- # default response if server is silent
221
- return CaptchaResponseSer(
222
- errorId=1,
223
- errorCode="ERROR_CAPTCHA_UNSOLVABLE",
224
- errorDescription="Captcha not recognized",
225
- taskId=self.created_task_data.taskId,
226
- status=ResponseStatusEnm.Failed,
227
- )
80
+ self.task_params.update(task_payload)
81
+ self._captcha_handling_instrument = AIOCaptchaInstrument(captcha_params=self)
82
+ return await self._captcha_handling_instrument.processing_captcha()
@@ -0,0 +1,145 @@
1
+ import os
2
+ import uuid
3
+ import base64
4
+ import shutil
5
+ from typing import Optional
6
+ from pathlib import Path
7
+
8
+ import aiohttp
9
+ import requests
10
+ from requests.adapters import HTTPAdapter
11
+
12
+ from .enum import SaveFormatsEnm
13
+ from .const import RETRIES, ASYNC_RETRIES
14
+ from .serializer import CaptchaResponseSer
15
+
16
+ __all__ = ("CaptchaInstrument", "FileInstrument")
17
+
18
+
19
+ class FileInstrument:
20
+ @staticmethod
21
+ def _local_file_captcha(captcha_file: str):
22
+ """
23
+ Method get local file, read it and prepare for sending to Captcha solving service
24
+ """
25
+ with open(captcha_file, "rb") as file:
26
+ return file.read()
27
+
28
+ @staticmethod
29
+ def _file_const_saver(content: bytes, file_path: str, file_extension: str = "png") -> str:
30
+ """
31
+ Method create and save file in folder
32
+ """
33
+ Path(file_path).mkdir(parents=True, exist_ok=True)
34
+
35
+ # generate image name
36
+ file_name = f"file-{uuid.uuid4()}.{file_extension}"
37
+
38
+ full_file_path = os.path.join(file_path, file_name)
39
+
40
+ # save image to folder
41
+ with open(full_file_path, "wb") as out_image:
42
+ out_image.write(content)
43
+ return full_file_path
44
+
45
+ @staticmethod
46
+ def _file_clean(full_file_path: str):
47
+ shutil.rmtree(full_file_path, ignore_errors=True)
48
+
49
+ @staticmethod
50
+ def _url_read(url: str, **kwargs):
51
+ """
52
+ Method open links
53
+ """
54
+ # prepare session
55
+ session = requests.Session()
56
+ session.mount("http://", HTTPAdapter(max_retries=RETRIES))
57
+ session.mount("https://", HTTPAdapter(max_retries=RETRIES))
58
+ session.verify = False
59
+ return session.get(url=url, **kwargs)
60
+
61
+ @staticmethod
62
+ async def _aio_url_read(url: str, **kwargs) -> bytes:
63
+ """
64
+ Async method read bytes from link
65
+ """
66
+ async with aiohttp.ClientSession() as session:
67
+ async for attempt in ASYNC_RETRIES:
68
+ with attempt:
69
+ async with session.get(url=url, **kwargs) as resp:
70
+ return await resp.content.read()
71
+
72
+ def file_processing(
73
+ self,
74
+ captcha_link: Optional[str] = None,
75
+ captcha_file: Optional[str] = None,
76
+ captcha_base64: Optional[bytes] = None,
77
+ save_format: SaveFormatsEnm = SaveFormatsEnm.TEMP,
78
+ img_clearing: bool = True,
79
+ file_path: str = "/tmp/",
80
+ file_extension: str = "png",
81
+ **kwargs,
82
+ ) -> str:
83
+ # if a local file link is passed
84
+ if captcha_file:
85
+ return base64.b64encode(self._local_file_captcha(captcha_file=captcha_file)).decode("utf-8")
86
+ # if the file is transferred in base64 encoding
87
+ elif captcha_base64:
88
+ return base64.b64encode(captcha_base64).decode("utf-8")
89
+ # if a URL is passed
90
+ elif captcha_link:
91
+ content = self._url_read(url=captcha_link, **kwargs).content
92
+ # according to the value of the passed parameter, select the function to save the image
93
+ if save_format == SaveFormatsEnm.CONST.value:
94
+ full_file_path = self._file_const_saver(content, file_path, file_extension=file_extension)
95
+ if img_clearing:
96
+ self._file_clean(full_file_path=full_file_path)
97
+ return base64.b64encode(content).decode("utf-8")
98
+ else:
99
+ raise ValueError("No valid captcha variant is set.")
100
+
101
+ async def aio_file_processing(
102
+ self,
103
+ captcha_link: Optional[str] = None,
104
+ captcha_file: Optional[str] = None,
105
+ captcha_base64: Optional[bytes] = None,
106
+ save_format: SaveFormatsEnm = SaveFormatsEnm.TEMP,
107
+ img_clearing: bool = True,
108
+ file_path: str = "/tmp/",
109
+ file_extension: str = "png",
110
+ **kwargs,
111
+ ) -> str:
112
+ # if a local file link is passed
113
+ if captcha_file:
114
+ return base64.b64encode(self._local_file_captcha(captcha_file=captcha_file)).decode("utf-8")
115
+ # if the file is transferred in base64 encoding
116
+ elif captcha_base64:
117
+ return base64.b64encode(captcha_base64).decode("utf-8")
118
+ # if a URL is passed
119
+ elif captcha_link:
120
+ content = await self._aio_url_read(url=captcha_link, **kwargs)
121
+ # according to the value of the passed parameter, select the function to save the image
122
+ if save_format == SaveFormatsEnm.CONST.value:
123
+ full_file_path = self._file_const_saver(content, file_path, file_extension=file_extension)
124
+ if img_clearing:
125
+ self._file_clean(full_file_path=full_file_path)
126
+ return base64.b64encode(content).decode("utf-8")
127
+
128
+ else:
129
+ raise ValueError("No valid captcha variant is set.")
130
+
131
+
132
+ class CaptchaInstrument(FileInstrument):
133
+ CAPTCHA_UNSOLVABLE = "ERROR_CAPTCHA_UNSOLVABLE"
134
+ """
135
+ Basic Captcha solving class
136
+
137
+ Args:
138
+ api_key: Capsolver API key
139
+ captcha_type: Captcha type name, like `ReCaptchaV2Task` and etc.
140
+ sleep_time: The waiting time between requests to get the result of the Captcha
141
+ request_url: API address for sending requests
142
+ """
143
+
144
+ def __init__(self):
145
+ self.result = CaptchaResponseSer()
@@ -0,0 +1,27 @@
1
+ import urllib3
2
+ from tenacity import AsyncRetrying, wait_fixed, stop_after_attempt
3
+ from requests.adapters import Retry
4
+
5
+ __all__ = (
6
+ "APP_ID",
7
+ "RETRIES",
8
+ "REQUEST_URL",
9
+ "ASYNC_RETRIES",
10
+ "GET_RESULT_POSTFIX",
11
+ "VALID_STATUS_CODES",
12
+ "GET_BALANCE_POSTFIX",
13
+ "CREATE_TASK_POSTFIX",
14
+ )
15
+
16
+ urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
17
+
18
+ RETRIES = Retry(total=5, backoff_factor=0.9, status_forcelist=[500, 502, 503, 504])
19
+ ASYNC_RETRIES = AsyncRetrying(wait=wait_fixed(5), stop=stop_after_attempt(5), reraise=True)
20
+
21
+ REQUEST_URL = "https://api.capsolver.com"
22
+ CREATE_TASK_POSTFIX = "/createTask"
23
+ GET_RESULT_POSTFIX = "/getTaskResult"
24
+ GET_BALANCE_POSTFIX = "/getBalance"
25
+ VALID_STATUS_CODES = (200, 202, 400, 401, 405)
26
+
27
+ APP_ID = "3E36E3CD-7EB5-4CAF-AA15-91011E652321"
@@ -0,0 +1,25 @@
1
+ __all__ = ("SIOContextManager", "AIOContextManager")
2
+
3
+
4
+ class SIOContextManager:
5
+
6
+ # Context methods
7
+ def __enter__(self):
8
+ return self
9
+
10
+ def __exit__(self, exc_type, exc_value, traceback):
11
+ if exc_type:
12
+ return False
13
+ return True
14
+
15
+
16
+ class AIOContextManager:
17
+
18
+ # Context methods
19
+ async def __aenter__(self):
20
+ return self
21
+
22
+ async def __aexit__(self, exc_type, exc_value, traceback):
23
+ if exc_type:
24
+ return False
25
+ return True