Skip to content

Commit e7a1493

Browse files
authored
Merge pull request #43 from ZennoLab/grk717/CML-3353
Major changes
2 parents e36b408 + a4e447e commit e7a1493

28 files changed

Lines changed: 826 additions & 53 deletions

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,5 @@ __pycache__/
22
dist/
33
build/
44
env/
5+
venv/
56
capmonstercloudclient.egg-info/

capmonstercloud_client/CapMonsterCloudClient.py

Lines changed: 21 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,9 @@
1616
_instance_config = (
1717
((RecaptchaV2Request,), getRecaptchaV2Timeouts),
1818
((RecaptchaV2EnterpriseRequest,), getRecaptchaV2EnterpriseTimeouts),
19-
((RecaptchaV3ProxylessRequest), getRecaptchaV3Timeouts),
20-
((RecaptchaV3EnterpriseRequest), getRecaptchaV3Timeouts),
21-
((ImageToTextRequest), getImage2TextTimeouts),
19+
((RecaptchaV3ProxylessRequest,), getRecaptchaV3Timeouts),
20+
((RecaptchaV3EnterpriseRequest,), getRecaptchaV3Timeouts),
21+
((ImageToTextRequest,), getImage2TextTimeouts),
2222
((FuncaptchaRequest,), getFuncaptchaTimeouts),
2323
((HcaptchaRequest,), getHcaptchaTimeouts),
2424
((GeetestRequest,), getGeetestTimeouts),
@@ -31,12 +31,15 @@
3131
((AmazonWafRequest,), getAmazonWafTimeouts),
3232
((BinanceTaskRequest,), getBinanceTimeouts),
3333
((ImpervaCustomTaskRequest,), getImpervaTimeouts),
34-
((RecognitionComplexImageTaskRequest), getCITTimeouts),
35-
((MTCaptchaRequest), getImage2TextTimeouts),
36-
((YidunRequest), getYidunTimeouts),
37-
((TemuCustomTaskRequest), getTemuTimeouts),
38-
((ProsopoTaskRequest), getProsopoTimeouts),
39-
((AltchaCustomTaskRequest), getAltchaTimeouts),
34+
((RecognitionComplexImageTaskRequest,), getCITTimeouts),
35+
((MTCaptchaRequest,), getImage2TextTimeouts),
36+
((YidunRequest,), getYidunTimeouts),
37+
((TemuCustomTaskRequest,), getTemuTimeouts),
38+
((ProsopoTaskRequest,), getProsopoTimeouts),
39+
((AltchaCustomTaskRequest,), getAltchaTimeouts),
40+
((CastleCustomTaskRequest,), getCastleTimeouts),
41+
((TspdCustomTaskRequest,), getTspdTimeouts),
42+
((HuntCustomTaskRequest,), getHuntTimeouts),
4043
)
4144

4245

@@ -100,7 +103,10 @@ async def solve_captcha(self, request: Union[
100103
YidunRequest,
101104
TemuCustomTaskRequest,
102105
ProsopoTaskRequest,
103-
AltchaCustomTaskRequest],
106+
AltchaCustomTaskRequest,
107+
CastleCustomTaskRequest,
108+
TspdCustomTaskRequest,
109+
HuntCustomTaskRequest],
104110
) -> Dict[str, str]:
105111
'''
106112
Non-blocking method for captcha solving.
@@ -148,6 +154,7 @@ async def _solve(self, request: Union[
148154
raise GetTaskError(f'[{getTaskResponse.get("errorCode")}] ' \
149155
f'{getTaskResponse.get("errorDescription")}.')
150156
timer = RequestController(timeout=timeouts.timeout)
157+
timer.run()
151158
await asyncio.sleep(timeouts.firstRequestDelay)
152159
result = CaptchaResult()
153160
while not timer.cancel:
@@ -165,13 +172,10 @@ async def _solve(self, request: Union[
165172
elif getResultResponse.get('status') == 'ready':
166173
timer.stop()
167174
result.solution = getResultResponse.get('solution')
168-
break
169-
170-
if result != None:
171-
return result.solution
172-
else:
173-
raise TimeoutError('Failed to get a solution within the maximum ' \
174-
f'response waiting interval: {timeouts.timeout:0.1f} sec.')
175+
return result.solution
176+
177+
raise TimeoutError('Failed to get a solution within the maximum ' \
178+
f'response waiting interval: {timeouts.timeout:0.1f} sec.')
175179

176180

177181
async def _getTaskResult(self, task_id: str) -> Dict[str, Union[int, str, None]]:

capmonstercloud_client/GetResultTimeouts.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,15 @@ def getImpervaTimeouts() -> GetResultTimeouts:
5656
def getAltchaTimeouts() -> GetResultTimeouts:
5757
return GetResultTimeouts(1, 0, 1, 50)
5858

59+
def getCastleTimeouts() -> GetResultTimeouts:
60+
return GetResultTimeouts(1, 0, 1, 60)
61+
62+
def getTspdTimeouts() -> GetResultTimeouts:
63+
return GetResultTimeouts(1, 0, 1, 60)
64+
65+
def getHuntTimeouts() -> GetResultTimeouts:
66+
return GetResultTimeouts(1, 0, 1, 60)
67+
5968
def getCITTimeouts() -> GetResultTimeouts:
6069
return GetResultTimeouts(0.35, 0, 0.2, 10)
6170

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
from typing import Dict, Union
2+
from pydantic import Field, validator
3+
4+
from .CustomTaskRequestBase import CustomTaskRequestBase
5+
6+
class CastleCustomTaskRequest(CustomTaskRequestBase):
7+
captchaClass: str = Field(default='Castle')
8+
websiteKey: str = Field()
9+
metadata: Dict[str, Union[str, int]]
10+
11+
@validator('metadata')
12+
def validate_metadata(cls, value):
13+
if value.get('wUrl') is None:
14+
raise TypeError(f'Expected that wUrl is defined.')
15+
else:
16+
if not isinstance(value.get('wUrl'), str):
17+
raise TypeError(f'Expected that wUrl is str.')
18+
if value.get('swUrl') is None:
19+
raise TypeError(f'Expected that swUrl is defined.')
20+
else:
21+
if not isinstance(value.get('swUrl'), str):
22+
raise TypeError(f'Expected that swUrl is str.')
23+
if value.get('count') is not None and not isinstance(value.get('count'), int):
24+
raise TypeError(f'Expected that count is int.')
25+
return value
26+
27+
def getTaskDict(self) -> Dict[str, Union[str, int, bool]]:
28+
task = {}
29+
task['type'] = self.type
30+
task['class'] = self.captchaClass
31+
task['websiteURL'] = self.websiteUrl
32+
task['websiteKey'] = self.websiteKey
33+
task['metadata'] = self.metadata
34+
if self.proxy:
35+
task['proxyType'] = self.proxy.proxyType
36+
task['proxyAddress'] = self.proxy.proxyAddress
37+
task['proxyPort'] = self.proxy.proxyPort
38+
task['proxyLogin'] = self.proxy.proxyLogin
39+
task['proxyPassword'] = self.proxy.proxyPassword
40+
if self.userAgent is not None:
41+
task['userAgent'] = self.userAgent
42+
return task

capmonstercloud_client/requests/DataDomeCustomTaskRequest.py

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,17 @@
11
from typing import Dict, Union
2-
from pydantic import Field, validator
2+
from pydantic import Field, validator, model_validator
33
from .CustomTaskRequestBase import CustomTaskRequestBase
44

55
class DataDomeCustomTaskRequest(CustomTaskRequestBase):
66
captchaClass: str = Field(default='DataDome')
77
metadata : Dict[str, str]
8-
8+
99
@validator('metadata')
1010
def validate_metadata(cls, value):
1111
if value.get('datadomeCookie') is None:
1212
raise TypeError(f'Expect that datadomeCookie will be defined.')
13+
if value.get('datadomeVersion') is not None and not isinstance(value.get('datadomeVersion'), str):
14+
raise TypeError(f'Expected datadomeVersion to be str')
1315
if value.get('captchaUrl') and value.get('htmlPageBase64'):
1416
raise TypeError(f'Expected only one of [captchaUrl, htmlPageBase64]')
1517
elif value.get('captchaUrl'):
@@ -18,22 +20,24 @@ def validate_metadata(cls, value):
1820
return {i: value[i] for i in value if i != 'captchaUrl'}
1921
else:
2022
raise TypeError(f'Expected one of [captchaUrl, htmlPageBase64]')
21-
if value.get('datadomeVersion') and not isinstance(value.get('datadomeVersion'), str):
22-
raise TypeError(f'Expected datadomeVersion to be str')
2323

24-
24+
@model_validator(mode='before')
25+
def validate_datadome_proxy(cls, values):
26+
proxy = values.get('proxy')
27+
if proxy is None:
28+
raise RuntimeError(f'You are required to use your own proxies.')
29+
return values
30+
2531
def getTaskDict(self) -> Dict[str, Union[str, int, bool]]:
2632
task = {}
2733
task['type'] = self.type
2834
task['class'] = self.captchaClass
2935
task['websiteURL'] = self.websiteUrl
30-
if self.proxy:
31-
task['proxyType'] = self.proxy.proxyType
32-
task['proxyAddress'] = self.proxy.proxyAddress
33-
task['proxyPort'] = self.proxy.proxyPort
34-
task['proxyLogin'] = self.proxy.proxyLogin
35-
task['proxyPassword'] = self.proxy.proxyPassword
36-
task['domains'] = self.domains
36+
task['proxyType'] = self.proxy.proxyType
37+
task['proxyAddress'] = self.proxy.proxyAddress
38+
task['proxyPort'] = self.proxy.proxyPort
39+
task['proxyLogin'] = self.proxy.proxyLogin
40+
task['proxyPassword'] = self.proxy.proxyPassword
3741
task['metadata'] = self.metadata
3842
if self.userAgent is not None:
3943
task['userAgent'] = self.userAgent
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
from typing import Dict, Union
2+
from pydantic import Field, validator, model_validator
3+
4+
from .CustomTaskRequestBase import CustomTaskRequestBase
5+
6+
class HuntCustomTaskRequest(CustomTaskRequestBase):
7+
captchaClass: str = Field(default='HUNT')
8+
metadata: Dict[str, str]
9+
10+
@validator('metadata')
11+
def validate_metadata(cls, value):
12+
if value.get('apiGetLib') is None:
13+
raise TypeError(f'Expect that apiGetLib will be defined.')
14+
else:
15+
if not isinstance(value.get('apiGetLib'), str):
16+
raise TypeError(f'Expect that apiGetLib will be str.')
17+
if value.get('data') is not None and not isinstance(value.get('data'), str):
18+
raise TypeError(f'Expect that data will be str.')
19+
return value
20+
21+
@model_validator(mode='before')
22+
def validate_hunt_proxy(cls, values):
23+
proxy = values.get('proxy')
24+
if proxy is None:
25+
raise RuntimeError(f'You are required to use your own proxies.')
26+
return values
27+
28+
def getTaskDict(self) -> Dict[str, Union[str, int, bool]]:
29+
task = {}
30+
task['type'] = self.type
31+
task['class'] = self.captchaClass
32+
task['websiteURL'] = self.websiteUrl
33+
task['metadata'] = self.metadata
34+
task['proxyType'] = self.proxy.proxyType
35+
task['proxyAddress'] = self.proxy.proxyAddress
36+
task['proxyPort'] = self.proxy.proxyPort
37+
task['proxyLogin'] = self.proxy.proxyLogin
38+
task['proxyPassword'] = self.proxy.proxyPassword
39+
if self.userAgent is not None:
40+
task['userAgent'] = self.userAgent
41+
return task

capmonstercloud_client/requests/RecaptchaV2EnterpiseRequest.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@ class RecaptchaV2EnterpriseRequest(BaseRequestWithProxy):
1010
enterprisePayload: Optional[str] = Field(default=None)
1111
apiDomain: Optional[str] = Field(default=None)
1212
pageAction: Optional[str] = Field(default=None)
13-
13+
userAgent: Optional[str] = Field(default=None)
14+
cookies: Optional[str] = Field(default=None)
15+
1416
def getTaskDict(self) -> Dict[str, Union[str, int]]:
1517
task = {}
1618
task['type'] = self.type
@@ -28,4 +30,8 @@ def getTaskDict(self) -> Dict[str, Union[str, int]]:
2830
task['apiDomain'] = self.apiDomain
2931
if self.pageAction is not None:
3032
task['pageAction'] = self.pageAction
33+
if self.userAgent is not None:
34+
task['userAgent'] = self.userAgent
35+
if self.cookies is not None:
36+
task['cookies'] = self.cookies
3137
return task

capmonstercloud_client/requests/RecaptchaV2Request.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,9 @@ class RecaptchaV2Request(BaseRequestWithProxy):
1111
dataSValue: Optional[str] = Field(default=None)
1212
userAgent: Optional[str] = Field(default=None)
1313
cookies: Optional[str] = Field(default=None)
14+
isInvisible: Optional[bool] = Field(default=None)
1415

15-
def getTaskDict(self) -> Dict[str, Union[str, int]]:
16+
def getTaskDict(self) -> Dict[str, Union[str, int, bool]]:
1617
task = {}
1718
task['type'] = self.type
1819
task['websiteURL'] = self.websiteUrl
@@ -26,12 +27,15 @@ def getTaskDict(self) -> Dict[str, Union[str, int]]:
2627

2728
if self.dataSValue is not None:
2829
task['recaptchaDataSValue'] = self.dataSValue
29-
30+
3031
if self.userAgent is not None:
3132
task['userAgent'] = self.userAgent
3233

3334
if self.cookies is not None:
3435
task['cookies'] = self.cookies
3536

37+
if self.isInvisible is not None:
38+
task['isInvisible'] = self.isInvisible
39+
3640
return task
3741

capmonstercloud_client/requests/RecaptchaV3ProxylessRequest.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,10 @@ class RecaptchaV3ProxylessRequest(BaseRequest):
77
websiteUrl: str
88
websiteKey: str
99
type: str = Field(default='RecaptchaV3TaskProxyless')
10-
min_score: Optional[float] = Field(default=None)
10+
minScore: Optional[float] = Field(default=None)
1111
pageAction: Optional[str] = Field(default=None)
1212

13-
@validator('min_score')
13+
@validator('minScore')
1414
def validate_min_score(cls, value):
1515
if value is not None:
1616
if not 0.1 <= value <= 0.9:
@@ -23,8 +23,8 @@ def getTaskDict(self) -> Dict[str, Union[str, float]]:
2323
task['type'] = self.type
2424
task['websiteURL'] = self.websiteUrl
2525
task['websiteKey'] = self.websiteKey
26-
if self.min_score is not None:
27-
task['minScore'] = self.min_score
26+
if self.minScore is not None:
27+
task['minScore'] = self.minScore
2828
if self.pageAction is not None:
2929
task['pageAction'] = self.pageAction
3030
return task

capmonstercloud_client/requests/TenDiCustomTaskRequest.py

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,21 @@
1-
from typing import Dict, Union
2-
from pydantic import Field
1+
from typing import Dict, Optional, Union
2+
from pydantic import Field, validator
33

44
from .CustomTaskRequestBase import CustomTaskRequestBase
55

66
class TenDiCustomTaskRequest(CustomTaskRequestBase):
77
captchaClass: str = Field(default='TenDI')
88
websiteKey: str = Field()
9+
metadata: Optional[Dict[str, str]] = Field(default=None)
10+
11+
@validator('metadata')
12+
def validate_metadata(cls, value):
13+
if value is not None:
14+
if not set(value.keys()).issubset(set(["captchaUrl"])):
15+
raise TypeError(f'Allowed keys for metadata are "captchaUrl"')
16+
if value.get('captchaUrl') is not None and not isinstance(value.get('captchaUrl'), str):
17+
raise TypeError(f'Expect that captchaUrl will be str.')
18+
return value
919

1020
def getTaskDict(self) -> Dict[str, Union[str, int, bool]]:
1121
task = {}
@@ -21,4 +31,6 @@ def getTaskDict(self) -> Dict[str, Union[str, int, bool]]:
2131
task['proxyPassword'] = self.proxy.proxyPassword
2232
if self.userAgent is not None:
2333
task['userAgent'] = self.userAgent
34+
if self.metadata is not None:
35+
task['metadata'] = self.metadata
2436
return task

0 commit comments

Comments
 (0)