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.
- python3_capsolver/__version__.py +1 -1
- python3_capsolver/aws_waf.py +122 -95
- python3_capsolver/cloudflare.py +113 -96
- python3_capsolver/control.py +31 -29
- python3_capsolver/core/aio_captcha_instrument.py +109 -0
- python3_capsolver/core/base.py +49 -194
- python3_capsolver/core/captcha_instrument.py +145 -0
- python3_capsolver/core/const.py +27 -0
- python3_capsolver/core/context_instr.py +25 -0
- python3_capsolver/core/enum.py +21 -76
- python3_capsolver/core/serializer.py +35 -128
- python3_capsolver/core/sio_captcha_instrument.py +116 -0
- python3_capsolver/core/{config.py → utils.py} +1 -10
- python3_capsolver/datadome_slider.py +56 -84
- python3_capsolver/friendly_captcha.py +105 -0
- python3_capsolver/gee_test.py +58 -90
- python3_capsolver/image_to_text.py +86 -116
- python3_capsolver/mt_captcha.py +49 -108
- python3_capsolver/recaptcha.py +65 -129
- python3_capsolver/vision_engine.py +102 -0
- python3_capsolver/yandex.py +73 -0
- {python3_capsolver-0.9.4.dist-info → python3_capsolver-1.0.1.dist-info}/METADATA +12 -12
- python3_capsolver-1.0.1.dist-info/RECORD +28 -0
- {python3_capsolver-0.9.4.dist-info → python3_capsolver-1.0.1.dist-info}/WHEEL +1 -1
- python3_capsolver/akamai.py +0 -192
- python3_capsolver/binance.py +0 -112
- python3_capsolver/cyber_si_ara.py +0 -128
- python3_capsolver/fun_captcha.py +0 -251
- python3_capsolver/hcaptcha.py +0 -197
- python3_capsolver/imperva.py +0 -120
- python3_capsolver-0.9.4.dist-info/RECORD +0 -26
- {python3_capsolver-0.9.4.dist-info → python3_capsolver-1.0.1.dist-info}/LICENSE +0 -0
- {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
|
python3_capsolver/core/base.py
CHANGED
|
@@ -1,25 +1,19 @@
|
|
|
1
|
-
import
|
|
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
|
|
8
|
-
import
|
|
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
|
|
13
|
-
from
|
|
14
|
-
from
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
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
|
-
|
|
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.
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
# prepare
|
|
45
|
-
self.
|
|
46
|
-
self.
|
|
47
|
-
self.
|
|
48
|
-
|
|
49
|
-
|
|
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
|
-
|
|
46
|
+
Synchronous method for captcha solving
|
|
52
47
|
|
|
53
48
|
Args:
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
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
|
-
|
|
93
|
-
|
|
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
|
-
|
|
57
|
+
Notes:
|
|
58
|
+
Check class docstirng for more info
|
|
101
59
|
"""
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
194
|
-
|
|
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
|