python-rucaptcha 5.1.5__py3-none-any.whl → 5.2__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.
- python_rucaptcha/__version__.py +1 -1
- python_rucaptcha/amazon_waf.py +1 -2
- python_rucaptcha/audio_captcha.py +208 -0
- python_rucaptcha/control.py +26 -1
- python_rucaptcha/core/base.py +9 -9
- python_rucaptcha/core/enums.py +13 -1
- python_rucaptcha/core/serializer.py +35 -15
- python_rucaptcha/image_captcha.py +6 -10
- python_rucaptcha/text_captcha.py +2 -2
- {python_rucaptcha-5.1.5.dist-info → python_rucaptcha-5.2.dist-info}/METADATA +4 -1
- {python_rucaptcha-5.1.5.dist-info → python_rucaptcha-5.2.dist-info}/RECORD +13 -12
- {python_rucaptcha-5.1.5.dist-info → python_rucaptcha-5.2.dist-info}/WHEEL +0 -0
- {python_rucaptcha-5.1.5.dist-info → python_rucaptcha-5.2.dist-info}/top_level.txt +0 -0
python_rucaptcha/__version__.py
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
__version__ = "5.
|
|
1
|
+
__version__ = "5.2"
|
python_rucaptcha/amazon_waf.py
CHANGED
|
@@ -5,7 +5,6 @@ from .core.enums import AmazonWAFCaptchaEnm
|
|
|
5
5
|
class AmazonWAF(BaseCaptcha):
|
|
6
6
|
def __init__(
|
|
7
7
|
self,
|
|
8
|
-
rucaptcha_key: str,
|
|
9
8
|
pageurl: str,
|
|
10
9
|
sitekey: str,
|
|
11
10
|
iv: str,
|
|
@@ -56,7 +55,7 @@ class AmazonWAF(BaseCaptcha):
|
|
|
56
55
|
Notes:
|
|
57
56
|
https://rucaptcha.com/api-rucaptcha#amazon-waf
|
|
58
57
|
"""
|
|
59
|
-
super().__init__(
|
|
58
|
+
super().__init__(method=method, *args, **kwargs)
|
|
60
59
|
|
|
61
60
|
self.post_payload.update({"sitekey": sitekey, "pageurl": pageurl, "iv": iv, "context": context})
|
|
62
61
|
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
import base64
|
|
2
|
+
import shutil
|
|
3
|
+
from typing import Optional
|
|
4
|
+
|
|
5
|
+
from .core.base import BaseCaptcha
|
|
6
|
+
from .core.enums import SaveFormatsEnm, AudioCaptchaEnm
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class AudioCaptcha(BaseCaptcha):
|
|
10
|
+
def __init__(
|
|
11
|
+
self,
|
|
12
|
+
save_format: str = SaveFormatsEnm.TEMP.value,
|
|
13
|
+
img_clearing: bool = True,
|
|
14
|
+
img_path: str = "PythonRuCaptchaAudio",
|
|
15
|
+
lang: str = "en",
|
|
16
|
+
*args,
|
|
17
|
+
**kwargs,
|
|
18
|
+
):
|
|
19
|
+
"""
|
|
20
|
+
The class is used to work with Text Captcha.
|
|
21
|
+
|
|
22
|
+
Args:
|
|
23
|
+
rucaptcha_key: User API key
|
|
24
|
+
save_format: The format in which the file will be saved, or as a temporary file - 'temp',
|
|
25
|
+
or as a regular file to a folder created by the library - 'const'.
|
|
26
|
+
img_clearing: True - delete file after solution, False - don't delete file after solution
|
|
27
|
+
img_path: Folder to save captcha audio
|
|
28
|
+
lang: Captcha audio lang: `en`, `fr`, `de`, `el`, `pt`, `ru`
|
|
29
|
+
|
|
30
|
+
Examples:
|
|
31
|
+
>>> AudioCaptcha(rucaptcha_key="aa9011f31111181111168611f1151122",
|
|
32
|
+
... lang='en'
|
|
33
|
+
... ).captcha_handler(captcha_file='examples/mediacaptcha_audio/recaptcha_55914.mp3')
|
|
34
|
+
{
|
|
35
|
+
'captchaSolve': 'five five nine one four',
|
|
36
|
+
'taskId': 73243152973,
|
|
37
|
+
'error': False,
|
|
38
|
+
'errorBody': None
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
>>> await AudioCaptcha(rucaptcha_key="aa9011f31111181111168611f1151122",
|
|
42
|
+
... lang='en'
|
|
43
|
+
... ).aio_captcha_handler(captcha_file='examples/mediacaptcha_audio/recaptcha_55914.mp3')
|
|
44
|
+
{
|
|
45
|
+
'captchaSolve': 'five five nine one four',
|
|
46
|
+
'taskId': 73243152973,
|
|
47
|
+
'error': False,
|
|
48
|
+
'errorBody': None
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
Returns:
|
|
52
|
+
Dict with full server response
|
|
53
|
+
|
|
54
|
+
Notes:
|
|
55
|
+
https://rucaptcha.com/api-rucaptcha#audio
|
|
56
|
+
"""
|
|
57
|
+
|
|
58
|
+
super().__init__(method=AudioCaptchaEnm.AUDIO.value, *args, **kwargs)
|
|
59
|
+
self.save_format = save_format
|
|
60
|
+
self.img_clearing = img_clearing
|
|
61
|
+
self.img_path = img_path
|
|
62
|
+
|
|
63
|
+
self.post_payload.update({"lang": lang})
|
|
64
|
+
|
|
65
|
+
def captcha_handler(
|
|
66
|
+
self,
|
|
67
|
+
captcha_link: Optional[str] = None,
|
|
68
|
+
captcha_file: Optional[str] = None,
|
|
69
|
+
captcha_base64: Optional[bytes] = None,
|
|
70
|
+
**kwargs,
|
|
71
|
+
) -> dict:
|
|
72
|
+
"""
|
|
73
|
+
Synchronous method for captcha solving
|
|
74
|
+
|
|
75
|
+
Args:
|
|
76
|
+
captcha_link: Captcha file URL
|
|
77
|
+
captcha_file: Captcha file path
|
|
78
|
+
captcha_base64: Captcha file BASE64 info
|
|
79
|
+
kwargs: additional params for `requests` library
|
|
80
|
+
|
|
81
|
+
Examples:
|
|
82
|
+
>>> AudioCaptcha(rucaptcha_key="aa9011f31111181111168611f1151122",
|
|
83
|
+
... lang='en'
|
|
84
|
+
... ).captcha_handler(captcha_file='examples/mediacaptcha_audio/recaptcha_55914.mp3')
|
|
85
|
+
{
|
|
86
|
+
'captchaSolve': 'five five nine one four',
|
|
87
|
+
'taskId': 73243152973,
|
|
88
|
+
'error': False,
|
|
89
|
+
'errorBody': None
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
>>> AudioCaptcha(rucaptcha_key="aa9011f31111181111168611f1151122",
|
|
93
|
+
... lang='en'
|
|
94
|
+
... ).captcha_handler(captcha_link='http://some/link/address/recaptcha_55914.mp3')
|
|
95
|
+
{
|
|
96
|
+
'captchaSolve': 'five five nine one four',
|
|
97
|
+
'taskId': 73243152973,
|
|
98
|
+
'error': False,
|
|
99
|
+
'errorBody': None
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
Returns:
|
|
103
|
+
Dict with full server response
|
|
104
|
+
|
|
105
|
+
Notes:
|
|
106
|
+
Check class docstirng for more info
|
|
107
|
+
"""
|
|
108
|
+
# if a local file link is passed
|
|
109
|
+
if captcha_file:
|
|
110
|
+
self.post_payload.update({"body": base64.b64encode(self._local_file_captcha(captcha_file)).decode("utf-8")})
|
|
111
|
+
# if the file is transferred in base64 encoding
|
|
112
|
+
elif captcha_base64:
|
|
113
|
+
self.post_payload.update({"body": base64.b64encode(captcha_base64).decode("utf-8")})
|
|
114
|
+
# if a URL is passed
|
|
115
|
+
elif captcha_link:
|
|
116
|
+
try:
|
|
117
|
+
content = self.url_open(url=captcha_link, **kwargs).content
|
|
118
|
+
except Exception as error:
|
|
119
|
+
self.result.error = True
|
|
120
|
+
self.result.errorBody = str(error)
|
|
121
|
+
return self.result.dict()
|
|
122
|
+
|
|
123
|
+
# according to the value of the passed parameter, select the function to save the file
|
|
124
|
+
if self.save_format == SaveFormatsEnm.CONST.value:
|
|
125
|
+
self._file_const_saver(content, self.img_path, file_extension="mp3")
|
|
126
|
+
self.post_payload.update({"body": base64.b64encode(content).decode("utf-8")})
|
|
127
|
+
|
|
128
|
+
else:
|
|
129
|
+
# if none of the parameters are passed
|
|
130
|
+
self.result.error = True
|
|
131
|
+
self.result.errorBody = self.NO_CAPTCHA_ERR
|
|
132
|
+
return self.result.dict()
|
|
133
|
+
|
|
134
|
+
return self._processing_response(**kwargs)
|
|
135
|
+
|
|
136
|
+
async def aio_captcha_handler(
|
|
137
|
+
self,
|
|
138
|
+
captcha_link: Optional[str] = None,
|
|
139
|
+
captcha_file: Optional[str] = None,
|
|
140
|
+
captcha_base64: Optional[bytes] = None,
|
|
141
|
+
**kwargs,
|
|
142
|
+
) -> dict:
|
|
143
|
+
"""
|
|
144
|
+
Asynchronous method for captcha solving
|
|
145
|
+
|
|
146
|
+
Args:
|
|
147
|
+
captcha_link: Captcha file URL
|
|
148
|
+
captcha_file: Captcha file path
|
|
149
|
+
captcha_base64: Captcha file BASE64
|
|
150
|
+
kwargs: additional params for `aiohttp` library
|
|
151
|
+
|
|
152
|
+
Examples:
|
|
153
|
+
>>> await AudioCaptcha(rucaptcha_key="aa9011f31111181111168611f1151122",
|
|
154
|
+
... lang='en'
|
|
155
|
+
... ).aio_captcha_handler(captcha_file='examples/mediacaptcha_audio/recaptcha_55914.mp3')
|
|
156
|
+
{
|
|
157
|
+
'captchaSolve': 'five five nine one four',
|
|
158
|
+
'taskId': 73243152973,
|
|
159
|
+
'error': False,
|
|
160
|
+
'errorBody': None
|
|
161
|
+
}
|
|
162
|
+
>>> await AudioCaptcha(rucaptcha_key="aa9011f31111181111168611f1151122",
|
|
163
|
+
... lang='en'
|
|
164
|
+
... ).aio_captcha_handler(captcha_link='http://some/link/address/recaptcha_55914.mp3')
|
|
165
|
+
{
|
|
166
|
+
'captchaSolve': 'five five nine one four',
|
|
167
|
+
'taskId': 73243152973,
|
|
168
|
+
'error': False,
|
|
169
|
+
'errorBody': None
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
Returns:
|
|
173
|
+
Dict with full server response
|
|
174
|
+
|
|
175
|
+
Notes:
|
|
176
|
+
Check class docstirng for more info
|
|
177
|
+
"""
|
|
178
|
+
# if a local file link is passed
|
|
179
|
+
if captcha_file:
|
|
180
|
+
self.post_payload.update({"body": base64.b64encode(self._local_file_captcha(captcha_file)).decode("utf-8")})
|
|
181
|
+
# if the file is transferred in base64 encoding
|
|
182
|
+
elif captcha_base64:
|
|
183
|
+
self.post_payload.update({"body": base64.b64encode(captcha_base64).decode("utf-8")})
|
|
184
|
+
# if a URL is passed
|
|
185
|
+
elif captcha_link:
|
|
186
|
+
try:
|
|
187
|
+
content = await self.aio_url_read(url=captcha_link, **kwargs)
|
|
188
|
+
except Exception as error:
|
|
189
|
+
self.result.error = True
|
|
190
|
+
self.result.errorBody = str(error)
|
|
191
|
+
return self.result.dict()
|
|
192
|
+
|
|
193
|
+
# according to the value of the passed parameter, select the function to save the file
|
|
194
|
+
if self.save_format == SaveFormatsEnm.CONST.value:
|
|
195
|
+
self._file_const_saver(content, self.img_path)
|
|
196
|
+
self.post_payload.update({"body": base64.b64encode(content).decode("utf-8")})
|
|
197
|
+
|
|
198
|
+
else:
|
|
199
|
+
# if none of the parameters are passed
|
|
200
|
+
self.result.error = True
|
|
201
|
+
self.result.errorBody = self.NO_CAPTCHA_ERR
|
|
202
|
+
return self.result.dict()
|
|
203
|
+
|
|
204
|
+
return await self._aio_processing_response()
|
|
205
|
+
|
|
206
|
+
def __del__(self):
|
|
207
|
+
if self.save_format == SaveFormatsEnm.CONST.value and self.img_clearing:
|
|
208
|
+
shutil.rmtree(self.img_path)
|
python_rucaptcha/control.py
CHANGED
|
@@ -37,6 +37,31 @@ class Control(BaseCaptcha):
|
|
|
37
37
|
'errorBody': None
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
+
Death By Captcha example:
|
|
41
|
+
|
|
42
|
+
>>> Control(rucaptcha_key="service_username:service_password",
|
|
43
|
+
... service_type="other-captcha-services",
|
|
44
|
+
... action=ControlEnm.GETBALANCE.value).additional_methods()
|
|
45
|
+
{
|
|
46
|
+
'captchaSolve': '0.00',
|
|
47
|
+
'taskId': None,
|
|
48
|
+
'error': False,
|
|
49
|
+
'errorBody': None
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
Death By Captcha example:
|
|
53
|
+
|
|
54
|
+
>>> from python_rucaptcha.core.enums import ControlEnm, ServiceEnm
|
|
55
|
+
>>> Control(rucaptcha_key="service_username:service_password",
|
|
56
|
+
... service_type=ServiceEnm.DEATHBYCAPTCHA,
|
|
57
|
+
... action=ControlEnm.GETBALANCE.value).additional_methods()
|
|
58
|
+
{
|
|
59
|
+
'captchaSolve': '0.00',
|
|
60
|
+
'taskId': None,
|
|
61
|
+
'error': False,
|
|
62
|
+
'errorBody': None
|
|
63
|
+
}
|
|
64
|
+
|
|
40
65
|
Returns:
|
|
41
66
|
Dict with full server response
|
|
42
67
|
|
|
@@ -46,7 +71,7 @@ class Control(BaseCaptcha):
|
|
|
46
71
|
https://rucaptcha.com/api-rucaptcha#additional
|
|
47
72
|
"""
|
|
48
73
|
|
|
49
|
-
super().__init__(action=action, *args, **kwargs)
|
|
74
|
+
super().__init__(method=ControlEnm.CONTROL.value, action=action, *args, **kwargs)
|
|
50
75
|
|
|
51
76
|
# check user params
|
|
52
77
|
if action not in ControlEnm.list_values():
|
python_rucaptcha/core/base.py
CHANGED
|
@@ -20,10 +20,10 @@ class BaseCaptcha:
|
|
|
20
20
|
def __init__(
|
|
21
21
|
self,
|
|
22
22
|
rucaptcha_key: str,
|
|
23
|
-
method: str
|
|
23
|
+
method: str,
|
|
24
24
|
action: str = "get",
|
|
25
25
|
sleep_time: int = 15,
|
|
26
|
-
service_type: str = enums.
|
|
26
|
+
service_type: str = enums.ServiceEnm.TWOCAPTCHA.value,
|
|
27
27
|
**kwargs,
|
|
28
28
|
):
|
|
29
29
|
"""
|
|
@@ -36,7 +36,7 @@ class BaseCaptcha:
|
|
|
36
36
|
:param kwargs: Designed to pass OPTIONAL parameters to the payload for a request to RuCaptcha
|
|
37
37
|
"""
|
|
38
38
|
# assign args to validator
|
|
39
|
-
self.params = CaptchaOptionsSer(**locals())
|
|
39
|
+
self.params = CaptchaOptionsSer(**locals(), **kwargs)
|
|
40
40
|
|
|
41
41
|
# prepare POST payload
|
|
42
42
|
self.post_payload = PostRequestSer(key=self.params.rucaptcha_key, method=method).dict(by_alias=True)
|
|
@@ -154,24 +154,24 @@ class BaseCaptcha:
|
|
|
154
154
|
# Working with images methods
|
|
155
155
|
|
|
156
156
|
@staticmethod
|
|
157
|
-
def
|
|
157
|
+
def _local_file_captcha(captcha_file: str):
|
|
158
158
|
"""
|
|
159
|
-
Method get local
|
|
159
|
+
Method get local file, read it and prepare for sending to Captcha solving service
|
|
160
160
|
"""
|
|
161
161
|
with open(captcha_file, "rb") as file:
|
|
162
162
|
return file.read()
|
|
163
163
|
|
|
164
|
-
def
|
|
164
|
+
def _file_const_saver(self, content: bytes, file_path: str, file_extension: str = "png"):
|
|
165
165
|
"""
|
|
166
166
|
Method create and save file in folder
|
|
167
167
|
"""
|
|
168
|
-
Path(
|
|
168
|
+
Path(file_path).mkdir(parents=True, exist_ok=True)
|
|
169
169
|
|
|
170
170
|
# generate image name
|
|
171
|
-
self.
|
|
171
|
+
self._file_name = f"file-{uuid.uuid4()}.{file_extension}"
|
|
172
172
|
|
|
173
173
|
# save image to folder
|
|
174
|
-
with open(os.path.join(
|
|
174
|
+
with open(os.path.join(file_path, self._file_name), "wb") as out_image:
|
|
175
175
|
out_image.write(content)
|
|
176
176
|
|
|
177
177
|
def __enter__(self):
|
python_rucaptcha/core/enums.py
CHANGED
|
@@ -20,9 +20,10 @@ class MyEnum(Enum):
|
|
|
20
20
|
return list(map(lambda c: c.name, cls))
|
|
21
21
|
|
|
22
22
|
|
|
23
|
-
class
|
|
23
|
+
class ServiceEnm(str, MyEnum):
|
|
24
24
|
TWOCAPTCHA = "2captcha"
|
|
25
25
|
RUCAPTCHA = "rucaptcha"
|
|
26
|
+
DEATHBYCAPTCHA = "other-captcha-services"
|
|
26
27
|
|
|
27
28
|
|
|
28
29
|
class SaveFormatsEnm(str, MyEnum):
|
|
@@ -72,6 +73,9 @@ class TikTokCaptchaEnm(str, MyEnum):
|
|
|
72
73
|
|
|
73
74
|
|
|
74
75
|
class ControlEnm(str, MyEnum):
|
|
76
|
+
# control method
|
|
77
|
+
CONTROL = "control"
|
|
78
|
+
|
|
75
79
|
# default
|
|
76
80
|
GET = "get"
|
|
77
81
|
# https://rucaptcha.com/api-rucaptcha#manage_pingback
|
|
@@ -98,3 +102,11 @@ class TurnstileCaptchaEnm(str, MyEnum):
|
|
|
98
102
|
|
|
99
103
|
class AmazonWAFCaptchaEnm(str, MyEnum):
|
|
100
104
|
AMAZON_WAF = "amazon_waf"
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
class TextCaptchaEnm(str, MyEnum):
|
|
108
|
+
TEXT = "text"
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
class AudioCaptchaEnm(str, MyEnum):
|
|
112
|
+
AUDIO = "audio"
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import logging
|
|
1
2
|
from uuid import uuid4
|
|
2
3
|
from typing import Union, Optional
|
|
3
4
|
|
|
@@ -94,34 +95,53 @@ class GetRequestSer(BaseModel):
|
|
|
94
95
|
|
|
95
96
|
|
|
96
97
|
class CaptchaOptionsSer(BaseModel):
|
|
97
|
-
rucaptcha_key: constr(min_length=32, max_length=32)
|
|
98
98
|
method: str
|
|
99
99
|
action: str
|
|
100
100
|
sleep_time: conint(gt=5) = 10
|
|
101
|
-
service_type: str = enums.
|
|
101
|
+
service_type: str = enums.ServiceEnm.TWOCAPTCHA.value
|
|
102
|
+
rucaptcha_key: constr(min_length=1)
|
|
102
103
|
|
|
103
|
-
#
|
|
104
|
-
|
|
105
|
-
# img_clearing: bool = True
|
|
106
|
-
# img_path: str = "PythonRuCaptchaImages"
|
|
104
|
+
url_request: Optional[str] = None # /in.php
|
|
105
|
+
url_response: Optional[str] = None # /res.php
|
|
107
106
|
|
|
108
|
-
|
|
109
|
-
|
|
107
|
+
@validator("rucaptcha_key")
|
|
108
|
+
def rucaptcha_key_check(cls, value, values, **kwargs):
|
|
109
|
+
service_type = values.get("service_type")
|
|
110
|
+
if service_type in (enums.ServiceEnm.RUCAPTCHA, enums.ServiceEnm.TWOCAPTCHA):
|
|
111
|
+
if len(value) != 32:
|
|
112
|
+
raise ValueError(f"Invalid `rucaptcha_key` len, it must be - 32, u send - {len(value)}")
|
|
113
|
+
return value
|
|
110
114
|
|
|
111
115
|
@validator("service_type")
|
|
112
116
|
def service_type_check(cls, value):
|
|
113
|
-
if value not in enums.
|
|
114
|
-
|
|
115
|
-
f"
|
|
117
|
+
if value not in enums.ServiceEnm.list_values():
|
|
118
|
+
logging.warning(
|
|
119
|
+
f"We support only this list of services - '{', '.join(enums.ServiceEnm.list_values())}', u send - '{value}'. "
|
|
120
|
+
f"All other services you use at your own risk"
|
|
116
121
|
)
|
|
117
122
|
return value
|
|
118
123
|
|
|
119
124
|
@root_validator
|
|
120
125
|
def urls_set(cls, values):
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
)
|
|
126
|
+
"""
|
|
127
|
+
Set request \ response URLs if they not set previously
|
|
128
|
+
"""
|
|
129
|
+
if not values.get("url_request") and not values.get("url_response"):
|
|
130
|
+
service_type = values.get("service_type")
|
|
131
|
+
if service_type == enums.ServiceEnm.DEATHBYCAPTCHA:
|
|
132
|
+
values.update(
|
|
133
|
+
{
|
|
134
|
+
"url_request": f"http://api.{service_type}.com/2captcha/in.php",
|
|
135
|
+
"url_response": f"http://api.{service_type}.com/2captcha/res.php",
|
|
136
|
+
}
|
|
137
|
+
)
|
|
138
|
+
else:
|
|
139
|
+
values.update(
|
|
140
|
+
{
|
|
141
|
+
"url_request": f"http://{service_type}.com/in.php",
|
|
142
|
+
"url_response": f"http://{service_type}.com/res.php",
|
|
143
|
+
}
|
|
144
|
+
)
|
|
125
145
|
return values
|
|
126
146
|
|
|
127
147
|
|
|
@@ -112,13 +112,11 @@ class ImageCaptcha(BaseCaptcha):
|
|
|
112
112
|
Dict with full server response
|
|
113
113
|
|
|
114
114
|
Notes:
|
|
115
|
-
|
|
115
|
+
Check class docstirng for more info
|
|
116
116
|
"""
|
|
117
117
|
# if a local file link is passed
|
|
118
118
|
if captcha_file:
|
|
119
|
-
self.post_payload.update(
|
|
120
|
-
{"body": base64.b64encode(self._local_image_captcha(captcha_file)).decode("utf-8")}
|
|
121
|
-
)
|
|
119
|
+
self.post_payload.update({"body": base64.b64encode(self._local_file_captcha(captcha_file)).decode("utf-8")})
|
|
122
120
|
# if the file is transferred in base64 encoding
|
|
123
121
|
elif captcha_base64:
|
|
124
122
|
self.post_payload.update({"body": base64.b64encode(captcha_base64).decode("utf-8")})
|
|
@@ -133,7 +131,7 @@ class ImageCaptcha(BaseCaptcha):
|
|
|
133
131
|
|
|
134
132
|
# according to the value of the passed parameter, select the function to save the image
|
|
135
133
|
if self.save_format == SaveFormatsEnm.CONST.value:
|
|
136
|
-
self.
|
|
134
|
+
self._file_const_saver(content, self.img_path)
|
|
137
135
|
self.post_payload.update({"body": base64.b64encode(content).decode("utf-8")})
|
|
138
136
|
|
|
139
137
|
else:
|
|
@@ -183,13 +181,11 @@ class ImageCaptcha(BaseCaptcha):
|
|
|
183
181
|
Dict with full server response
|
|
184
182
|
|
|
185
183
|
Notes:
|
|
186
|
-
|
|
184
|
+
Check class docstirng for more info
|
|
187
185
|
"""
|
|
188
186
|
# if a local file link is passed
|
|
189
187
|
if captcha_file:
|
|
190
|
-
self.post_payload.update(
|
|
191
|
-
{"body": base64.b64encode(self._local_image_captcha(captcha_file)).decode("utf-8")}
|
|
192
|
-
)
|
|
188
|
+
self.post_payload.update({"body": base64.b64encode(self._local_file_captcha(captcha_file)).decode("utf-8")})
|
|
193
189
|
# if the file is transferred in base64 encoding
|
|
194
190
|
elif captcha_base64:
|
|
195
191
|
self.post_payload.update({"body": base64.b64encode(captcha_base64).decode("utf-8")})
|
|
@@ -204,7 +200,7 @@ class ImageCaptcha(BaseCaptcha):
|
|
|
204
200
|
|
|
205
201
|
# according to the value of the passed parameter, select the function to save the image
|
|
206
202
|
if self.save_format == SaveFormatsEnm.CONST.value:
|
|
207
|
-
self.
|
|
203
|
+
self._file_const_saver(content, self.img_path)
|
|
208
204
|
self.post_payload.update({"body": base64.b64encode(content).decode("utf-8")})
|
|
209
205
|
|
|
210
206
|
else:
|
python_rucaptcha/text_captcha.py
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
from .core.base import BaseCaptcha
|
|
2
|
+
from .core.enums import TextCaptchaEnm
|
|
2
3
|
|
|
3
4
|
|
|
4
5
|
class TextCaptcha(BaseCaptcha):
|
|
5
6
|
def __init__(
|
|
6
7
|
self,
|
|
7
|
-
rucaptcha_key: str,
|
|
8
8
|
language: int = 0,
|
|
9
9
|
*args,
|
|
10
10
|
**kwargs,
|
|
@@ -45,7 +45,7 @@ class TextCaptcha(BaseCaptcha):
|
|
|
45
45
|
https://rucaptcha.com/api-rucaptcha#solving_text_captcha
|
|
46
46
|
"""
|
|
47
47
|
|
|
48
|
-
super().__init__(
|
|
48
|
+
super().__init__(method=TextCaptchaEnm.TEXT.value, *args, **kwargs)
|
|
49
49
|
|
|
50
50
|
self.post_payload.update({"language": language})
|
|
51
51
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: python-rucaptcha
|
|
3
|
-
Version: 5.
|
|
3
|
+
Version: 5.2
|
|
4
4
|
Summary: Python 3.7+ RuCaptcha library with AIO module.
|
|
5
5
|
Home-page: https://andreidrang.github.io/python-rucaptcha/
|
|
6
6
|
Author: AndreiDrang, redV0ID
|
|
@@ -13,6 +13,7 @@ Project-URL: Issue tracker, https://github.com/AndreiDrang/python-rucaptcha/issu
|
|
|
13
13
|
Keywords: captcha
|
|
14
14
|
rucaptcha
|
|
15
15
|
2captcha
|
|
16
|
+
deathbycaptcha
|
|
16
17
|
recaptcha
|
|
17
18
|
geetest
|
|
18
19
|
hcaptcha
|
|
@@ -114,6 +115,8 @@ Is described in the [documentation-website](https://andreidrang.github.io/python
|
|
|
114
115
|
|
|
115
116
|
### Changelog
|
|
116
117
|
|
|
118
|
+
- v.5.3 - Added support for [Death By Captcha](https://deathbycaptcha.com/) and other services by changing `service_type` and `url_request` \ `url_response` parameters.
|
|
119
|
+
- v.5.2 - Added Audio captcha method.
|
|
117
120
|
- v.5.1 - Check [releases page](https://github.com/AndreiDrang/python-rucaptcha/releases).
|
|
118
121
|
- v.5.0 - Added AmazonWAF captcha method.
|
|
119
122
|
- v.4.2 - Added [Yandex Smart Captcha](https://rucaptcha.com/api-rucaptcha#yandex).
|
|
@@ -1,28 +1,29 @@
|
|
|
1
1
|
python_rucaptcha/SocketAPI.py,sha256=W_ZmEaNTMx--lvaYiLJyckWGt3P-gxoZf0qdxK-onb0,4291
|
|
2
2
|
python_rucaptcha/TikTokCaptcha.py,sha256=PF1ZeV3tb1e2ig3w6kfqqHQzAMOhmGxKjiAyizBRzks,2122
|
|
3
3
|
python_rucaptcha/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
4
|
-
python_rucaptcha/__version__.py,sha256=
|
|
5
|
-
python_rucaptcha/amazon_waf.py,sha256=
|
|
4
|
+
python_rucaptcha/__version__.py,sha256=w-7iTykPeImrjtpuwfo7ztWT6laCATvHs7mwCtvIvZs,20
|
|
5
|
+
python_rucaptcha/amazon_waf.py,sha256=On5PdMYuyWp0DLdmnCs04CuYALEx-aKo0P-USsk-dgk,4385
|
|
6
|
+
python_rucaptcha/audio_captcha.py,sha256=HFAzvEMwgqmjx3mu8_6az4T4YCqqcIzEB5pRc4V0Ojo,7879
|
|
6
7
|
python_rucaptcha/capy_puzzle.py,sha256=wgofttv2qp-7_xHClKE8E6jlV1ca0H4m9fw0ZVnq7RU,7077
|
|
7
|
-
python_rucaptcha/control.py,sha256=
|
|
8
|
+
python_rucaptcha/control.py,sha256=xOLHFrXh2OCb-UFYI9Kxcxkj_B4CX2FsLqMHCWjoMHI,13476
|
|
8
9
|
python_rucaptcha/fun_captcha.py,sha256=0IdsCe_4HxSgtdhBb3B6w_LaSel89IUEQYL7_m2D2i4,3859
|
|
9
10
|
python_rucaptcha/gee_test.py,sha256=-mHV8w717UhsmjQUknZgl1elNEXRz-h5GC6S3QtEM6U,10436
|
|
10
11
|
python_rucaptcha/hcaptcha.py,sha256=lvBpIqlZnELEu6aXcAn0hGWybtYvXn0Gmzq4KXO9hPg,3844
|
|
11
|
-
python_rucaptcha/image_captcha.py,sha256=
|
|
12
|
+
python_rucaptcha/image_captcha.py,sha256=hSLEHV6w-ekthZfdIsIzIM5Wm4QYd3XsDiewb6FRoAM,9281
|
|
12
13
|
python_rucaptcha/key_captcha.py,sha256=qdWlHdLg2RzBGtkBDdGwyfpsLu821Iy2Pk2tIe1p7WI,5022
|
|
13
14
|
python_rucaptcha/lemin_cropped_captcha.py,sha256=m51lbpFk_QHAXUIlaBS7YEkTetZmyKDz0tzHeufz-mU,5209
|
|
14
15
|
python_rucaptcha/re_captcha.py,sha256=9k9_ErZkSge-IrjMAYMbrmkScDD9XAMnny0ko3gNx5I,5437
|
|
15
16
|
python_rucaptcha/rotate_captcha.py,sha256=P5eNM-fLGnW1TVoF2OxlF-Kou-jVPY7yjAvTw5V_Gfc,6187
|
|
16
|
-
python_rucaptcha/text_captcha.py,sha256=
|
|
17
|
+
python_rucaptcha/text_captcha.py,sha256=Qj32p71KNj02laARIbpAzSszBeuUGTLrSyRoesvubf0,3118
|
|
17
18
|
python_rucaptcha/turnstile.py,sha256=O2Q10oei6pSt47Wdq3lJjCagH_1x2U_h-LcPu0gXaDM,3790
|
|
18
19
|
python_rucaptcha/yandex_smart_captcha.py,sha256=YGBhflfTxWJ603o3COvYAYHSFvbXBb5KrsduBI25YKQ,4695
|
|
19
20
|
python_rucaptcha/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
20
|
-
python_rucaptcha/core/base.py,sha256=
|
|
21
|
+
python_rucaptcha/core/base.py,sha256=UzbJYseQX4nGjGKcjWgAAmXqo9defTd4CURTV1xyrn4,6666
|
|
21
22
|
python_rucaptcha/core/config.py,sha256=SRbH3ENNpVLwqCkXU_cqVILkSqtorUlkYBs-_XMXYzQ,552
|
|
22
|
-
python_rucaptcha/core/enums.py,sha256=
|
|
23
|
+
python_rucaptcha/core/enums.py,sha256=QYdnxgALuplSD5dWkW16OP5dMcRCT3BHXPWBKIBFHag,2109
|
|
23
24
|
python_rucaptcha/core/result_handler.py,sha256=OPCpfaItugyUMLJsrNaUZhZAHjb3wzHUOGO02av5KoE,3390
|
|
24
|
-
python_rucaptcha/core/serializer.py,sha256=
|
|
25
|
-
python_rucaptcha-5.
|
|
26
|
-
python_rucaptcha-5.
|
|
27
|
-
python_rucaptcha-5.
|
|
28
|
-
python_rucaptcha-5.
|
|
25
|
+
python_rucaptcha/core/serializer.py,sha256=2C-qTZIDNtH-ENqGORpguOQBnkSbkC1Ka1Ig5aT8Hd8,4617
|
|
26
|
+
python_rucaptcha-5.2.dist-info/METADATA,sha256=Cl_toq1iSuzrVQWU3UIDBR48wQvTR1n7bUm3ug0qddM,5658
|
|
27
|
+
python_rucaptcha-5.2.dist-info/WHEEL,sha256=G16H4A3IeoQmnOrYV4ueZGKSjhipXx8zc8nu9FGlvMA,92
|
|
28
|
+
python_rucaptcha-5.2.dist-info/top_level.txt,sha256=Eu_atEB79Y7jCsfXPcXF5N8OLt6kKVbvhuRsI1BmSWM,17
|
|
29
|
+
python_rucaptcha-5.2.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|