python3-capsolver 0.9.2__py3-none-any.whl → 1.0.0a0__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/__init__.py +1 -0
- python3_capsolver/__version__.py +1 -1
- python3_capsolver/aws_waf.py +122 -95
- python3_capsolver/cloudflare.py +77 -96
- python3_capsolver/control.py +31 -29
- python3_capsolver/core/aio_captcha_instrument.py +109 -0
- python3_capsolver/core/base.py +52 -198
- 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 -129
- python3_capsolver/core/sio_captcha_instrument.py +116 -0
- python3_capsolver/core/{config.py → utils.py} +1 -10
- python3_capsolver/datadome_slider.py +34 -84
- python3_capsolver/friendly_captcha.py +69 -0
- python3_capsolver/gee_test.py +58 -90
- python3_capsolver/image_to_text.py +86 -116
- python3_capsolver/mt_captcha.py +32 -108
- python3_capsolver/recaptcha.py +65 -129
- python3_capsolver/vision_engine.py +102 -0
- python3_capsolver/yandex.py +53 -0
- python3_capsolver-1.0.0a0.dist-info/LICENSE +21 -0
- {python3_capsolver-0.9.2.dist-info → python3_capsolver-1.0.0a0.dist-info}/METADATA +25 -55
- python3_capsolver-1.0.0a0.dist-info/RECORD +28 -0
- {python3_capsolver-0.9.2.dist-info → python3_capsolver-1.0.0a0.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.2.dist-info/RECORD +0 -25
- {python3_capsolver-0.9.2.dist-info → python3_capsolver-1.0.0a0.dist-info}/top_level.txt +0 -0
|
@@ -1,30 +1,47 @@
|
|
|
1
|
-
from
|
|
1
|
+
from enum import Enum
|
|
2
|
+
from typing import Any, Dict, Literal, Optional
|
|
2
3
|
|
|
3
|
-
from
|
|
4
|
+
from msgspec import Struct
|
|
5
|
+
|
|
6
|
+
from .enum import ResponseStatusEnm
|
|
7
|
+
from .const import APP_ID
|
|
8
|
+
|
|
9
|
+
__all__ = ("PostRequestSer", "TaskSer", "RequestCreateTaskSer", "CaptchaResponseSer", "RequestGetTaskResultSer")
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class MyBaseModel(Struct):
|
|
13
|
+
def to_dict(self) -> Dict[str, str]:
|
|
14
|
+
result = {}
|
|
15
|
+
for f in self.__struct_fields__:
|
|
16
|
+
if isinstance(getattr(self, f), Enum):
|
|
17
|
+
result.update({f: getattr(self, f).value})
|
|
18
|
+
else:
|
|
19
|
+
result.update({f: getattr(self, f)})
|
|
20
|
+
return result
|
|
4
21
|
|
|
5
|
-
from python3_capsolver.core.enum import ResponseStatusEnm
|
|
6
|
-
from python3_capsolver.core.config import APP_ID
|
|
7
22
|
|
|
8
23
|
"""
|
|
9
24
|
HTTP API Request ser
|
|
10
25
|
"""
|
|
11
26
|
|
|
12
27
|
|
|
13
|
-
class PostRequestSer(
|
|
14
|
-
clientKey: str
|
|
15
|
-
task:
|
|
28
|
+
class PostRequestSer(MyBaseModel):
|
|
29
|
+
clientKey: str
|
|
30
|
+
task: Dict = {}
|
|
31
|
+
callbackUrl: Optional[str] = None
|
|
16
32
|
|
|
17
33
|
|
|
18
|
-
class TaskSer(
|
|
19
|
-
type: str
|
|
34
|
+
class TaskSer(MyBaseModel):
|
|
35
|
+
type: str
|
|
20
36
|
|
|
21
37
|
|
|
22
38
|
class RequestCreateTaskSer(PostRequestSer):
|
|
23
39
|
appId: Literal[APP_ID] = APP_ID
|
|
24
40
|
|
|
25
41
|
|
|
26
|
-
class RequestGetTaskResultSer(
|
|
27
|
-
|
|
42
|
+
class RequestGetTaskResultSer(MyBaseModel):
|
|
43
|
+
clientKey: str
|
|
44
|
+
taskId: Optional[str] = None
|
|
28
45
|
|
|
29
46
|
|
|
30
47
|
"""
|
|
@@ -32,125 +49,14 @@ HTTP API Response ser
|
|
|
32
49
|
"""
|
|
33
50
|
|
|
34
51
|
|
|
35
|
-
class ResponseSer(
|
|
36
|
-
errorId: int =
|
|
52
|
+
class ResponseSer(MyBaseModel):
|
|
53
|
+
errorId: int = 0
|
|
37
54
|
# error info
|
|
38
|
-
errorCode: Optional[str] =
|
|
39
|
-
errorDescription: Optional[str] =
|
|
55
|
+
errorCode: Optional[str] = None
|
|
56
|
+
errorDescription: Optional[str] = None
|
|
40
57
|
|
|
41
58
|
|
|
42
59
|
class CaptchaResponseSer(ResponseSer):
|
|
43
|
-
taskId: Optional[str] =
|
|
44
|
-
status: ResponseStatusEnm =
|
|
45
|
-
solution: Dict[str, Any] =
|
|
46
|
-
|
|
47
|
-
class Config:
|
|
48
|
-
allow_population_by_field_name = True
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
class ControlResponseSer(ResponseSer):
|
|
52
|
-
balance: Optional[float] = Field(0, description="Account balance value in USD")
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
"""
|
|
56
|
-
Other ser
|
|
57
|
-
"""
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
class CaptchaOptionsSer(BaseModel):
|
|
61
|
-
api_key: str
|
|
62
|
-
sleep_time: conint(ge=5) = 5
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
"""
|
|
66
|
-
Captcha tasks ser
|
|
67
|
-
"""
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
class WebsiteDataOptionsSer(TaskSer):
|
|
71
|
-
websiteURL: str = Field(..., description="Address of a webpage with Captcha")
|
|
72
|
-
websiteKey: Optional[str] = Field(None, description="Website key")
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
class ReCaptchaV3Ser(WebsiteDataOptionsSer):
|
|
76
|
-
pageAction: str = Field(
|
|
77
|
-
"verify",
|
|
78
|
-
description="Widget action value."
|
|
79
|
-
"Website owner defines what user is doing on the page through this parameter",
|
|
80
|
-
)
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
class HCaptchaClassificationOptionsSer(TaskSer):
|
|
84
|
-
queries: List[str] = Field(..., description="Base64-encoded images, do not include 'data:image/***;base64,'")
|
|
85
|
-
question: str = Field(
|
|
86
|
-
..., description="Question ID. Support English and Chinese, other languages please convert yourself"
|
|
87
|
-
)
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
class FunCaptchaClassificationOptionsSer(TaskSer):
|
|
91
|
-
images: List[str] = Field(..., description="Base64-encoded images, do not include 'data:image/***;base64,'")
|
|
92
|
-
question: str = Field(
|
|
93
|
-
...,
|
|
94
|
-
description="Question name. this param value from API response game_variant field. Exmaple: maze,maze2,flockCompass,3d_rollball_animals",
|
|
95
|
-
)
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
class GeeTestSer(TaskSer):
|
|
99
|
-
websiteURL: str = Field(..., description="Address of a webpage with Geetest")
|
|
100
|
-
gt: str = Field(..., description="The domain public key, rarely updated")
|
|
101
|
-
challenge: Optional[str] = Field(
|
|
102
|
-
"",
|
|
103
|
-
description="If you need to solve Geetest V3 you must use this parameter, don't need if you need to solve GeetestV4",
|
|
104
|
-
)
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
class FunCaptchaSer(TaskSer):
|
|
108
|
-
websiteURL: str = Field(..., description="Address of a webpage with Funcaptcha")
|
|
109
|
-
websitePublicKey: str = Field(..., description="Funcaptcha website key.")
|
|
110
|
-
funcaptchaApiJSSubdomain: Optional[str] = Field(
|
|
111
|
-
None,
|
|
112
|
-
description="A special subdomain of funcaptcha.com, from which the JS captcha widget should be loaded."
|
|
113
|
-
"Most FunCaptcha installations work from shared domains.",
|
|
114
|
-
)
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
class DatadomeSliderSer(TaskSer):
|
|
118
|
-
websiteURL: str = Field(..., description="Address of a webpage with DatadomeSlider")
|
|
119
|
-
captchaUrl: str = Field(..., description="Captcha Url where is the captcha")
|
|
120
|
-
userAgent: str = Field(..., description="Browser's User-Agent which is used in emulation")
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
class CloudflareTurnstileSer(WebsiteDataOptionsSer):
|
|
124
|
-
...
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
class CyberSiAraSer(WebsiteDataOptionsSer):
|
|
128
|
-
SlideMasterUrlId: str = Field(
|
|
129
|
-
..., description="You can get MasterUrlId param form `api/CyberSiara/GetCyberSiara` endpoint request"
|
|
130
|
-
)
|
|
131
|
-
UserAgent: str = Field(..., description="Browser userAgent, you need submit your userAgent")
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
class AntiAkamaiBMPTaskSer(TaskSer):
|
|
135
|
-
packageName: str = Field("de.zalando.iphone", description="Package name of AkamaiBMP mobile APP")
|
|
136
|
-
version: str = Field("3.2.6", description="AKAMAI BMP Version number")
|
|
137
|
-
country: str = Field("US", description="AKAMAI BMP country")
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
class AntiAkamaiWebTaskSer(TaskSer):
|
|
141
|
-
url: str = Field(..., description="Browser url address")
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
class AntiImpervaTaskSer(TaskSer):
|
|
145
|
-
websiteUrl: str = Field(..., description="The website url")
|
|
146
|
-
userAgent: str = Field(..., description="Browser userAgent")
|
|
147
|
-
utmvc: bool = Field(
|
|
148
|
-
True, description="If cookie contains `incap_see_xxx`, `nlbi_xxx`, `visid_inap_xxx`, mean is true"
|
|
149
|
-
)
|
|
150
|
-
reese84: bool = Field(True, description="if cookie conains `reese84`, set it true")
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
class BinanceCaptchaTaskSer(TaskSer):
|
|
154
|
-
websiteURL: str = Field(..., description="Address of a webpage with Binance captcha")
|
|
155
|
-
websiteKey: str = Field("login", description="`bizId` always be `login`")
|
|
156
|
-
validateId: str = Field(..., description="`validateId` bncaptcha validateId field")
|
|
60
|
+
taskId: Optional[str] = None
|
|
61
|
+
status: ResponseStatusEnm = ResponseStatusEnm.Processing
|
|
62
|
+
solution: Optional[Dict[str, Any]] = None
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import time
|
|
2
|
+
import logging
|
|
3
|
+
from typing import Optional
|
|
4
|
+
from urllib import parse
|
|
5
|
+
|
|
6
|
+
import requests
|
|
7
|
+
from requests.adapters import HTTPAdapter
|
|
8
|
+
|
|
9
|
+
from .enum import ResponseStatusEnm, EndpointPostfixEnm
|
|
10
|
+
from .const import RETRIES, REQUEST_URL, VALID_STATUS_CODES, GET_BALANCE_POSTFIX
|
|
11
|
+
from .utils import attempts_generator
|
|
12
|
+
from .serializer import CaptchaResponseSer
|
|
13
|
+
from .captcha_instrument import CaptchaInstrument
|
|
14
|
+
|
|
15
|
+
__all__ = ("SIOCaptchaInstrument",)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class SIOCaptchaInstrument(CaptchaInstrument):
|
|
19
|
+
"""
|
|
20
|
+
Instrument for working with sync captcha
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
def __init__(self, captcha_params: "CaptchaParams"):
|
|
24
|
+
super().__init__()
|
|
25
|
+
self.captcha_params = captcha_params
|
|
26
|
+
self.created_task_data = CaptchaResponseSer
|
|
27
|
+
# prepare session
|
|
28
|
+
self.session = requests.Session()
|
|
29
|
+
self.session.mount("http://", HTTPAdapter(max_retries=RETRIES))
|
|
30
|
+
self.session.mount("https://", HTTPAdapter(max_retries=RETRIES))
|
|
31
|
+
self.session.verify = False
|
|
32
|
+
|
|
33
|
+
def processing_captcha(self) -> dict:
|
|
34
|
+
self.captcha_params.create_task_payload.task = self.captcha_params.task_params
|
|
35
|
+
|
|
36
|
+
self.created_task_data = CaptchaResponseSer(**self.__create_task())
|
|
37
|
+
|
|
38
|
+
# if task created and ready - return result
|
|
39
|
+
if self.created_task_data.errorId == 0 and self.created_task_data.status == ResponseStatusEnm.Processing:
|
|
40
|
+
return self.__get_result().to_dict()
|
|
41
|
+
elif self.created_task_data.errorId != 0:
|
|
42
|
+
self.created_task_data.status = ResponseStatusEnm.Failed
|
|
43
|
+
|
|
44
|
+
return self.created_task_data.to_dict()
|
|
45
|
+
|
|
46
|
+
def __create_task(self, url_postfix: str = EndpointPostfixEnm.CREATE_TASK.value) -> dict:
|
|
47
|
+
"""
|
|
48
|
+
Function send SYNC request to service and wait for result
|
|
49
|
+
"""
|
|
50
|
+
try:
|
|
51
|
+
resp = self.session.post(
|
|
52
|
+
parse.urljoin(self.captcha_params.request_url, url_postfix),
|
|
53
|
+
json=self.captcha_params.create_task_payload.to_dict(),
|
|
54
|
+
)
|
|
55
|
+
if resp.status_code in VALID_STATUS_CODES:
|
|
56
|
+
return resp.json()
|
|
57
|
+
else:
|
|
58
|
+
raise ValueError(resp.raise_for_status())
|
|
59
|
+
except Exception as error:
|
|
60
|
+
logging.exception(error)
|
|
61
|
+
raise
|
|
62
|
+
|
|
63
|
+
def __get_result(self, url_postfix: str = EndpointPostfixEnm.GET_TASK_RESULT.value) -> CaptchaResponseSer:
|
|
64
|
+
"""
|
|
65
|
+
Method send SYNC request to service and wait for result
|
|
66
|
+
"""
|
|
67
|
+
# initial waiting
|
|
68
|
+
time.sleep(self.captcha_params.sleep_time)
|
|
69
|
+
|
|
70
|
+
self.captcha_params.get_result_params.taskId = self.created_task_data.taskId
|
|
71
|
+
|
|
72
|
+
attempts = attempts_generator()
|
|
73
|
+
for _ in attempts:
|
|
74
|
+
try:
|
|
75
|
+
resp = self.session.post(
|
|
76
|
+
parse.urljoin(self.captcha_params.request_url, url_postfix),
|
|
77
|
+
json=self.captcha_params.get_result_params.to_dict(),
|
|
78
|
+
)
|
|
79
|
+
if resp.status_code in VALID_STATUS_CODES:
|
|
80
|
+
result_data = CaptchaResponseSer(**resp.json())
|
|
81
|
+
if result_data.status in (ResponseStatusEnm.Ready, ResponseStatusEnm.Failed):
|
|
82
|
+
# if captcha ready\failed or have unknown status - return exist data
|
|
83
|
+
return result_data
|
|
84
|
+
else:
|
|
85
|
+
raise ValueError(resp.raise_for_status())
|
|
86
|
+
except Exception as error:
|
|
87
|
+
logging.exception(error)
|
|
88
|
+
raise
|
|
89
|
+
|
|
90
|
+
# if captcha just created or in processing now - wait
|
|
91
|
+
time.sleep(self.captcha_params.sleep_time)
|
|
92
|
+
# default response if server is silent
|
|
93
|
+
self.result.errorId = 1
|
|
94
|
+
self.result.errorCode = self.CAPTCHA_UNSOLVABLE
|
|
95
|
+
self.result.errorDescription = "Captcha not recognized"
|
|
96
|
+
self.result.taskId = self.created_task_data.taskId
|
|
97
|
+
self.result.status = ResponseStatusEnm.Failed
|
|
98
|
+
|
|
99
|
+
@staticmethod
|
|
100
|
+
def send_post_request(
|
|
101
|
+
payload: Optional[dict] = None,
|
|
102
|
+
session: requests.Session = requests.Session(),
|
|
103
|
+
url_postfix: str = GET_BALANCE_POSTFIX,
|
|
104
|
+
) -> dict:
|
|
105
|
+
"""
|
|
106
|
+
Function send SYNC request to service and wait for result
|
|
107
|
+
"""
|
|
108
|
+
try:
|
|
109
|
+
resp = session.post(parse.urljoin(REQUEST_URL, url_postfix), json=payload)
|
|
110
|
+
if resp.status_code == 200:
|
|
111
|
+
return resp.json()
|
|
112
|
+
else:
|
|
113
|
+
raise ValueError(resp.status_code)
|
|
114
|
+
except Exception as error:
|
|
115
|
+
logging.exception(error)
|
|
116
|
+
raise
|
|
@@ -1,15 +1,6 @@
|
|
|
1
1
|
from typing import Generator
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
from requests.adapters import Retry
|
|
5
|
-
|
|
6
|
-
RETRIES = Retry(total=5, backoff_factor=0.9, status_forcelist=[500, 502, 503, 504])
|
|
7
|
-
ASYNC_RETRIES = AsyncRetrying(wait=wait_fixed(5), stop=stop_after_attempt(5), reraise=True)
|
|
8
|
-
|
|
9
|
-
REQUEST_URL = "https://api.capsolver.com"
|
|
10
|
-
VALID_STATUS_CODES = (200, 202, 400, 401, 405)
|
|
11
|
-
|
|
12
|
-
APP_ID = "3E36E3CD-7EB5-4CAF-AA15-91011E652321"
|
|
3
|
+
__all__ = ("attempts_generator",)
|
|
13
4
|
|
|
14
5
|
|
|
15
6
|
# Connection retry generator
|
|
@@ -1,103 +1,53 @@
|
|
|
1
1
|
from typing import Union
|
|
2
2
|
|
|
3
|
-
from
|
|
4
|
-
from
|
|
5
|
-
from python3_capsolver.core.serializer import DatadomeSliderSer, CaptchaResponseSer
|
|
3
|
+
from .core.base import CaptchaParams
|
|
4
|
+
from .core.enum import CaptchaTypeEnm
|
|
6
5
|
|
|
7
6
|
|
|
8
|
-
class DatadomeSlider(
|
|
7
|
+
class DatadomeSlider(CaptchaParams):
|
|
9
8
|
"""
|
|
10
|
-
The class is used to work with Capsolver
|
|
9
|
+
The class is used to work with Capsolver DatadomeSliderTask method.
|
|
11
10
|
|
|
12
11
|
Args:
|
|
13
12
|
api_key: Capsolver API key
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
13
|
+
captcha_type: Captcha type name, like ``DatadomeSliderTask`` and etc.
|
|
14
|
+
kwargs: additional params for client, like captcha waiting time
|
|
15
|
+
available keys:
|
|
16
|
+
- sleep_time: int - captcha solution waintig time in sec
|
|
17
|
+
- request_url: str - API address for sending requests,
|
|
18
|
+
else official will be used
|
|
18
19
|
|
|
19
20
|
Examples:
|
|
20
|
-
>>> DatadomeSlider
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
...
|
|
24
|
-
...
|
|
25
|
-
...
|
|
26
|
-
...
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
... userAgent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36",
|
|
41
|
-
... ).aio_captcha_handler()
|
|
42
|
-
CaptchaResponseSer(errorId=0,
|
|
43
|
-
errorCode=None,
|
|
44
|
-
errorDescription=None,
|
|
45
|
-
taskId='73bdcd28-6c77-4414-8....',
|
|
46
|
-
status=<ResponseStatusEnm.Ready: 'ready'>,
|
|
47
|
-
solution={'gRecaptchaResponse': '44795sds...'}
|
|
48
|
-
)
|
|
49
|
-
|
|
50
|
-
Returns:
|
|
51
|
-
CaptchaResponseSer model with full server response
|
|
21
|
+
>>> from python3_capsolver.datadome_slider import DatadomeSlider
|
|
22
|
+
>>> from python3_capsolver.core.enum import CaptchaTypeEnm
|
|
23
|
+
>>> DatadomeSlider(api_key="CAI-12345....",
|
|
24
|
+
... captcha_type=CaptchaTypeEnm.DatadomeSliderTask)
|
|
25
|
+
... .captcha_handler(task_payload={
|
|
26
|
+
... "captchaUrl": "https://geo.captchaxxxxxx",
|
|
27
|
+
... "userAgent": "Mozilla/5.0 xxxx",
|
|
28
|
+
... "proxy": "0.0.0.0:334:user:pass"
|
|
29
|
+
... })
|
|
30
|
+
{
|
|
31
|
+
"errorId":0,
|
|
32
|
+
"errorCode":"None",
|
|
33
|
+
"errorDescription":"None",
|
|
34
|
+
"taskId":"db0a3153-621d-4f5e-8554-a1c032597ee7",
|
|
35
|
+
"status":"ready",
|
|
36
|
+
"solution":{
|
|
37
|
+
"userAgent": "Mozilla/5.0 xxxx",
|
|
38
|
+
"cookie": "datadome=yzj_BK..xxxx"
|
|
39
|
+
}
|
|
40
|
+
}
|
|
52
41
|
|
|
53
42
|
Notes:
|
|
54
|
-
https://docs.capsolver.com/guide/
|
|
43
|
+
https://docs.capsolver.com/en/guide/captcha/datadome/
|
|
55
44
|
"""
|
|
56
45
|
|
|
57
46
|
def __init__(
|
|
58
47
|
self,
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
userAgent: str,
|
|
62
|
-
captcha_type: Union[DatadomeSliderTypeEnm, str] = DatadomeSliderTypeEnm.DatadomeSliderTask,
|
|
63
|
-
*args,
|
|
48
|
+
api_key: str,
|
|
49
|
+
captcha_type: Union[CaptchaTypeEnm, str] = CaptchaTypeEnm.DatadomeSliderTask,
|
|
64
50
|
**kwargs,
|
|
65
51
|
):
|
|
66
|
-
super().__init__(*args, **kwargs)
|
|
67
|
-
|
|
68
|
-
if captcha_type in DatadomeSliderTypeEnm.list():
|
|
69
|
-
self.task_params = DatadomeSliderSer(**locals()).dict()
|
|
70
|
-
else:
|
|
71
|
-
raise ValueError(
|
|
72
|
-
f"""Invalid `captcha_type` parameter set for `{self.__class__.__name__}`,
|
|
73
|
-
available - {DatadomeSliderTypeEnm.list()}"""
|
|
74
|
-
)
|
|
75
|
-
for key in kwargs:
|
|
76
|
-
self.task_params.update({key: kwargs[key]})
|
|
77
|
-
|
|
78
|
-
def captcha_handler(self) -> CaptchaResponseSer:
|
|
79
|
-
"""
|
|
80
|
-
Sync method for captcha solving
|
|
81
|
-
|
|
82
|
-
Returns:
|
|
83
|
-
CaptchaResponseSer model with full service response
|
|
84
|
-
|
|
85
|
-
Notes:
|
|
86
|
-
Check class docstring for more info
|
|
87
|
-
"""
|
|
88
|
-
return self._processing_captcha(create_params=self.task_params)
|
|
89
|
-
|
|
90
|
-
async def aio_captcha_handler(
|
|
91
|
-
self,
|
|
92
|
-
**additional_params,
|
|
93
|
-
) -> CaptchaResponseSer:
|
|
94
|
-
"""
|
|
95
|
-
Async method for captcha solving
|
|
96
|
-
|
|
97
|
-
Returns:
|
|
98
|
-
CaptchaResponseSer model with full service response
|
|
99
52
|
|
|
100
|
-
|
|
101
|
-
Check class docstring for more info
|
|
102
|
-
"""
|
|
103
|
-
return await self._aio_processing_captcha(create_params=self.task_params)
|
|
53
|
+
super().__init__(api_key=api_key, captcha_type=captcha_type, **kwargs)
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
from typing import Union
|
|
2
|
+
|
|
3
|
+
from .core.base import CaptchaParams
|
|
4
|
+
from .core.enum import CaptchaTypeEnm
|
|
5
|
+
|
|
6
|
+
__all__ = ("FriendlyCaptcha",)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class FriendlyCaptcha(CaptchaParams):
|
|
10
|
+
"""
|
|
11
|
+
The class is used to work with Capsolver FriendlyCaptchaTaskProxyless methods.
|
|
12
|
+
|
|
13
|
+
Args:
|
|
14
|
+
api_key: Capsolver API key
|
|
15
|
+
captcha_type: Captcha type name, like ``FriendlyCaptchaTaskProxyless`` and etc.
|
|
16
|
+
kwargs: additional params for client, like captcha waiting time
|
|
17
|
+
available keys:
|
|
18
|
+
- sleep_time: int - captcha solution waintig time in sec
|
|
19
|
+
- request_url: str - API address for sending requests,
|
|
20
|
+
else official will be used
|
|
21
|
+
|
|
22
|
+
Examples:
|
|
23
|
+
>>> from python3_capsolver.core.enum import CaptchaTypeEnm
|
|
24
|
+
>>> from python3_capsolver.friendly_captcha import FriendlyCaptcha
|
|
25
|
+
>>> FriendlyCaptcha(api_key="CAP-XXXXX",
|
|
26
|
+
... captcha_type=CaptchaTypeEnm.FriendlyCaptchaTaskProxyless,
|
|
27
|
+
... ).captcha_handler(task_payload={
|
|
28
|
+
... "websiteURL": "https://www.yourwebsite.com",
|
|
29
|
+
... "proxy": "ip:port:user:pass"
|
|
30
|
+
... })
|
|
31
|
+
{
|
|
32
|
+
"errorId":0,
|
|
33
|
+
"errorCode":"None",
|
|
34
|
+
"errorDescription":"None",
|
|
35
|
+
"taskId":"db0a3153-621d-4f5e-8554-a1c032597ee7",
|
|
36
|
+
"status":"ready",
|
|
37
|
+
"solution":{
|
|
38
|
+
"cookies": "cf_clearance=_VPxxxx",
|
|
39
|
+
"headers": {
|
|
40
|
+
"sec-ch-ua": "\"Chromium\";v=\"130\", \"Google Chrome\";v=\"130\", \"Not?A_Brand\";v=\"99\"",
|
|
41
|
+
"sec-ch-ua-platform": "\"Windows\"",
|
|
42
|
+
"accept": "text/html,axxxx",
|
|
43
|
+
"User-Agent": "Mozilla/5.0xxxx",
|
|
44
|
+
"sec-ch-ua-mobile": "?0",
|
|
45
|
+
"sec-fetch-user": "?1",
|
|
46
|
+
"referer": "https://www.yourwebsite.com",
|
|
47
|
+
"Sec-Fetch-Dest": "document",
|
|
48
|
+
"Sec-Fetch-Mode": "navigate",
|
|
49
|
+
"Sec-Fetch-Site": "same-origin",
|
|
50
|
+
"accept-language": "en",
|
|
51
|
+
},
|
|
52
|
+
"page_url": "https://www.yourwebsite.com",
|
|
53
|
+
"proxy": "your proxyxxxx",
|
|
54
|
+
"token": "_VPCTZXP5bhinxxxx"
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
Notes:
|
|
59
|
+
https://docs.capsolver.com/en/guide/captcha/FriendlyCaptcha/
|
|
60
|
+
"""
|
|
61
|
+
|
|
62
|
+
def __init__(
|
|
63
|
+
self,
|
|
64
|
+
api_key: str,
|
|
65
|
+
captcha_type: Union[CaptchaTypeEnm, str] = CaptchaTypeEnm.FriendlyCaptchaTaskProxyless,
|
|
66
|
+
**kwargs,
|
|
67
|
+
):
|
|
68
|
+
|
|
69
|
+
super().__init__(api_key=api_key, captcha_type=captcha_type, **kwargs)
|