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
python3_capsolver/core/enum.py
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
from enum import Enum
|
|
2
|
-
from types import DynamicClassAttribute
|
|
3
2
|
from typing import List
|
|
4
3
|
|
|
4
|
+
__all__ = ("EndpointPostfixEnm", "CaptchaTypeEnm", "ResponseStatusEnm", "SaveFormatsEnm")
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
|
|
7
|
+
class MyEnum(str, Enum):
|
|
7
8
|
@classmethod
|
|
8
9
|
def list(cls) -> List[Enum]:
|
|
9
10
|
return list(map(lambda c: c, cls))
|
|
@@ -16,22 +17,8 @@ class MyEnum(Enum):
|
|
|
16
17
|
def list_names(cls) -> List[str]:
|
|
17
18
|
return list(map(lambda c: c.name, cls))
|
|
18
19
|
|
|
19
|
-
@DynamicClassAttribute
|
|
20
|
-
def name(self) -> str:
|
|
21
|
-
"""
|
|
22
|
-
The name of the Enum member
|
|
23
|
-
"""
|
|
24
|
-
return self._name_
|
|
25
|
-
|
|
26
|
-
@DynamicClassAttribute
|
|
27
|
-
def value(self) -> str:
|
|
28
|
-
"""
|
|
29
|
-
The name of the Enum member
|
|
30
|
-
"""
|
|
31
|
-
return self._value_
|
|
32
20
|
|
|
33
|
-
|
|
34
|
-
class EndpointPostfixEnm(str, MyEnum):
|
|
21
|
+
class EndpointPostfixEnm(MyEnum):
|
|
35
22
|
"""
|
|
36
23
|
Enum stored URL postfixes for API endpoints
|
|
37
24
|
"""
|
|
@@ -39,93 +26,46 @@ class EndpointPostfixEnm(str, MyEnum):
|
|
|
39
26
|
GET_BALANCE = "getBalance"
|
|
40
27
|
CREATE_TASK = "createTask"
|
|
41
28
|
GET_TASK_RESULT = "getTaskResult"
|
|
42
|
-
AKAMAI_BMP_INVOKE = "akamaibmp/invoke"
|
|
43
|
-
AKAMAI_WEB_INVOKE = "akamaiweb/invoke"
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
class ImageToTextTaskTypeEnm(str, MyEnum):
|
|
47
|
-
ImageToTextTask = "ImageToTextTask"
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
class HCaptchaTypeEnm(str, MyEnum):
|
|
51
|
-
HCaptchaTask = "HCaptchaTask"
|
|
52
|
-
HCaptchaTaskProxyless = "HCaptchaTaskProxyless"
|
|
53
|
-
HCaptchaEnterpriseTask = "HCaptchaEnterpriseTask"
|
|
54
|
-
HCaptchaEnterpriseTaskProxyLess = "HCaptchaEnterpriseTaskProxyLess"
|
|
55
|
-
HCaptchaTurboTask = "HCaptchaTurboTask"
|
|
56
|
-
HCaptchaClassification = "HCaptchaClassification"
|
|
57
29
|
|
|
58
30
|
|
|
59
|
-
class
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
class FunCaptchaTypeEnm(str, MyEnum):
|
|
64
|
-
FunCaptchaTask = "FunCaptchaTask"
|
|
65
|
-
FunCaptchaTaskProxyLess = "FunCaptchaTaskProxyLess"
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
class FunCaptchaClassificationTypeEnm(str, MyEnum):
|
|
69
|
-
FunCaptchaClassification = "FunCaptchaClassification"
|
|
31
|
+
class CaptchaTypeEnm(MyEnum):
|
|
32
|
+
Control = "Control"
|
|
70
33
|
|
|
34
|
+
ImageToTextTask = "ImageToTextTask"
|
|
35
|
+
VisionEngine = "VisionEngine"
|
|
71
36
|
|
|
72
|
-
class GeeTestCaptchaTypeEnm(str, MyEnum):
|
|
73
|
-
GeeTestTask = "GeeTestTask"
|
|
74
37
|
GeeTestTaskProxyLess = "GeeTestTaskProxyLess"
|
|
75
38
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
# V2
|
|
39
|
+
# re-captcha
|
|
40
|
+
ReCaptchaV2Classification = "ReCaptchaV2Classification"
|
|
79
41
|
ReCaptchaV2Task = "ReCaptchaV2Task"
|
|
80
42
|
ReCaptchaV2EnterpriseTask = "ReCaptchaV2EnterpriseTask"
|
|
81
43
|
ReCaptchaV2TaskProxyLess = "ReCaptchaV2TaskProxyLess"
|
|
82
44
|
ReCaptchaV2EnterpriseTaskProxyLess = "ReCaptchaV2EnterpriseTaskProxyLess"
|
|
83
45
|
|
|
84
|
-
|
|
85
|
-
class ReCaptchaV3TypeEnm(str, MyEnum):
|
|
86
46
|
ReCaptchaV3Task = "ReCaptchaV3Task"
|
|
87
47
|
ReCaptchaV3EnterpriseTask = "ReCaptchaV3EnterpriseTask"
|
|
88
48
|
ReCaptchaV3TaskProxyLess = "ReCaptchaV3TaskProxyLess"
|
|
89
49
|
ReCaptchaV3EnterpriseTaskProxyLess = "ReCaptchaV3EnterpriseTaskProxyLess"
|
|
90
50
|
|
|
91
|
-
|
|
92
|
-
class MtCaptchaTypeEnm(str, MyEnum):
|
|
93
51
|
MtCaptchaTask = "MtCaptchaTask"
|
|
94
52
|
MtCaptchaTaskProxyLess = "MtCaptchaTaskProxyLess"
|
|
95
53
|
|
|
96
|
-
|
|
97
|
-
class DatadomeSliderTypeEnm(str, MyEnum):
|
|
98
54
|
DatadomeSliderTask = "DatadomeSliderTask"
|
|
99
55
|
|
|
100
|
-
|
|
101
|
-
class CloudflareTypeEnm(str, MyEnum):
|
|
56
|
+
AntiTurnstileTaskProxyLess = "AntiTurnstileTaskProxyLess"
|
|
102
57
|
AntiCloudflareTask = "AntiCloudflareTask"
|
|
103
58
|
|
|
59
|
+
FriendlyCaptchaTaskProxyless = "FriendlyCaptchaTaskProxyless"
|
|
60
|
+
|
|
61
|
+
YandexCaptchaTaskProxyLess = "YandexCaptchaTaskProxyLess"
|
|
104
62
|
|
|
105
|
-
class AntiAwsWafTaskTypeEnm(str, MyEnum):
|
|
106
63
|
AntiAwsWafTask = "AntiAwsWafTask"
|
|
107
64
|
AntiAwsWafTaskProxyLess = "AntiAwsWafTaskProxyLess"
|
|
65
|
+
AwsWafClassification = "AwsWafClassification"
|
|
108
66
|
|
|
109
67
|
|
|
110
|
-
class
|
|
111
|
-
AntiCyberSiAraTask = "AntiCyberSiAraTask"
|
|
112
|
-
AntiCyberSiAraTaskProxyLess = "AntiCyberSiAraTaskProxyLess"
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
class AntiAkamaiTaskEnm(str, MyEnum):
|
|
116
|
-
AntiAkamaiBMPTask = "AntiAkamaiBMPTask"
|
|
117
|
-
AntiAkamaiWebTask = "AntiAkamaiWebTask"
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
class AntiImpervaTaskEnm(str, MyEnum):
|
|
121
|
-
AntiImpervaTask = "AntiImpervaTask"
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
class BinanceCaptchaTaskEnm(str, MyEnum):
|
|
125
|
-
BinanceCaptchaTask = "BinanceCaptchaTask"
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
class ResponseStatusEnm(str, MyEnum):
|
|
68
|
+
class ResponseStatusEnm(MyEnum):
|
|
129
69
|
"""
|
|
130
70
|
Enum store results `status` field variants
|
|
131
71
|
|
|
@@ -137,3 +77,8 @@ class ResponseStatusEnm(str, MyEnum):
|
|
|
137
77
|
Processing = "processing" # Task is not ready yet
|
|
138
78
|
Ready = "ready" # Task completed, solution object can be found in solution property
|
|
139
79
|
Failed = "failed" # Task failed, check the errorDescription to know why failed.
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
class SaveFormatsEnm(MyEnum):
|
|
83
|
+
TEMP = "temp"
|
|
84
|
+
CONST = "const"
|
|
@@ -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, Any]:
|
|
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,124 +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
|
-
populate_by_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
|
-
class CyberSiAraSer(WebsiteDataOptionsSer):
|
|
127
|
-
SlideMasterUrlId: str = Field(
|
|
128
|
-
..., description="You can get MasterUrlId param form `api/CyberSiara/GetCyberSiara` endpoint request"
|
|
129
|
-
)
|
|
130
|
-
UserAgent: str = Field(..., description="Browser userAgent, you need submit your userAgent")
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
class AntiAkamaiBMPTaskSer(TaskSer):
|
|
134
|
-
packageName: str = Field("de.zalando.iphone", description="Package name of AkamaiBMP mobile APP")
|
|
135
|
-
version: str = Field("3.2.6", description="AKAMAI BMP Version number")
|
|
136
|
-
country: str = Field("US", description="AKAMAI BMP country")
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
class AntiAkamaiWebTaskSer(TaskSer):
|
|
140
|
-
url: str = Field(..., description="Browser url address")
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
class AntiImpervaTaskSer(TaskSer):
|
|
144
|
-
websiteUrl: str = Field(..., description="The website url")
|
|
145
|
-
userAgent: str = Field(..., description="Browser userAgent")
|
|
146
|
-
utmvc: bool = Field(
|
|
147
|
-
True, description="If cookie contains `incap_see_xxx`, `nlbi_xxx`, `visid_inap_xxx`, mean is true"
|
|
148
|
-
)
|
|
149
|
-
reese84: bool = Field(True, description="if cookie conains `reese84`, set it true")
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
class BinanceCaptchaTaskSer(TaskSer):
|
|
153
|
-
websiteURL: str = Field(..., description="Address of a webpage with Binance captcha")
|
|
154
|
-
websiteKey: str = Field("login", description="`bizId` always be `login`")
|
|
155
|
-
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,75 @@
|
|
|
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
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
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
|
+
}
|
|
41
|
+
|
|
42
|
+
>>> import asyncio
|
|
43
|
+
>>> from python3_capsolver.datadome_slider import DatadomeSlider
|
|
44
|
+
>>> from python3_capsolver.core.enum import CaptchaTypeEnm
|
|
45
|
+
>>> asyncio.run(DatadomeSlider(api_key="CAI-12345....",
|
|
46
|
+
... captcha_type=CaptchaTypeEnm.DatadomeSliderTask)
|
|
47
|
+
... .aio_captcha_handler(task_payload={
|
|
48
|
+
... "captchaUrl": "https://geo.captchaxxxxxx",
|
|
49
|
+
... "userAgent": "Mozilla/5.0 xxxx",
|
|
50
|
+
... "proxy": "0.0.0.0:334:user:pass"
|
|
51
|
+
... }))
|
|
52
|
+
{
|
|
53
|
+
"errorId":0,
|
|
54
|
+
"errorCode":"None",
|
|
55
|
+
"errorDescription":"None",
|
|
56
|
+
"taskId":"db0a3153-621d-4f5e-8554-a1c032597ee7",
|
|
57
|
+
"status":"ready",
|
|
58
|
+
"solution":{
|
|
59
|
+
"userAgent": "Mozilla/5.0 xxxx",
|
|
60
|
+
"cookie": "datadome=yzj_BK..xxxx"
|
|
61
|
+
}
|
|
62
|
+
}
|
|
52
63
|
|
|
53
64
|
Notes:
|
|
54
|
-
https://docs.capsolver.com/guide/
|
|
65
|
+
https://docs.capsolver.com/en/guide/captcha/datadome/
|
|
55
66
|
"""
|
|
56
67
|
|
|
57
68
|
def __init__(
|
|
58
69
|
self,
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
userAgent: str,
|
|
62
|
-
captcha_type: Union[DatadomeSliderTypeEnm, str] = DatadomeSliderTypeEnm.DatadomeSliderTask,
|
|
63
|
-
*args,
|
|
70
|
+
api_key: str,
|
|
71
|
+
captcha_type: Union[CaptchaTypeEnm, str] = CaptchaTypeEnm.DatadomeSliderTask,
|
|
64
72
|
**kwargs,
|
|
65
73
|
):
|
|
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
74
|
|
|
100
|
-
|
|
101
|
-
Check class docstring for more info
|
|
102
|
-
"""
|
|
103
|
-
return await self._aio_processing_captcha(create_params=self.task_params)
|
|
75
|
+
super().__init__(api_key=api_key, captcha_type=captcha_type, **kwargs)
|