Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@ __pycache__/
dist/
build/
env/
venv/
capmonstercloudclient.egg-info/
38 changes: 21 additions & 17 deletions capmonstercloud_client/CapMonsterCloudClient.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@
_instance_config = (
((RecaptchaV2Request,), getRecaptchaV2Timeouts),
((RecaptchaV2EnterpriseRequest,), getRecaptchaV2EnterpriseTimeouts),
((RecaptchaV3ProxylessRequest), getRecaptchaV3Timeouts),
((RecaptchaV3EnterpriseRequest), getRecaptchaV3Timeouts),
((ImageToTextRequest), getImage2TextTimeouts),
((RecaptchaV3ProxylessRequest,), getRecaptchaV3Timeouts),
((RecaptchaV3EnterpriseRequest,), getRecaptchaV3Timeouts),
((ImageToTextRequest,), getImage2TextTimeouts),
((FuncaptchaRequest,), getFuncaptchaTimeouts),
((HcaptchaRequest,), getHcaptchaTimeouts),
((GeetestRequest,), getGeetestTimeouts),
Expand All @@ -31,12 +31,15 @@
((AmazonWafRequest,), getAmazonWafTimeouts),
((BinanceTaskRequest,), getBinanceTimeouts),
((ImpervaCustomTaskRequest,), getImpervaTimeouts),
((RecognitionComplexImageTaskRequest), getCITTimeouts),
((MTCaptchaRequest), getImage2TextTimeouts),
((YidunRequest), getYidunTimeouts),
((TemuCustomTaskRequest), getTemuTimeouts),
((ProsopoTaskRequest), getProsopoTimeouts),
((AltchaCustomTaskRequest), getAltchaTimeouts),
((RecognitionComplexImageTaskRequest,), getCITTimeouts),
((MTCaptchaRequest,), getImage2TextTimeouts),
((YidunRequest,), getYidunTimeouts),
((TemuCustomTaskRequest,), getTemuTimeouts),
((ProsopoTaskRequest,), getProsopoTimeouts),
((AltchaCustomTaskRequest,), getAltchaTimeouts),
((CastleCustomTaskRequest,), getCastleTimeouts),
((TspdCustomTaskRequest,), getTspdTimeouts),
((HuntCustomTaskRequest,), getHuntTimeouts),
)


Expand Down Expand Up @@ -100,7 +103,10 @@ async def solve_captcha(self, request: Union[
YidunRequest,
TemuCustomTaskRequest,
ProsopoTaskRequest,
AltchaCustomTaskRequest],
AltchaCustomTaskRequest,
CastleCustomTaskRequest,
TspdCustomTaskRequest,
HuntCustomTaskRequest],
) -> Dict[str, str]:
'''
Non-blocking method for captcha solving.
Expand Down Expand Up @@ -148,6 +154,7 @@ async def _solve(self, request: Union[
raise GetTaskError(f'[{getTaskResponse.get("errorCode")}] ' \
f'{getTaskResponse.get("errorDescription")}.')
timer = RequestController(timeout=timeouts.timeout)
timer.run()
await asyncio.sleep(timeouts.firstRequestDelay)
result = CaptchaResult()
while not timer.cancel:
Expand All @@ -165,13 +172,10 @@ async def _solve(self, request: Union[
elif getResultResponse.get('status') == 'ready':
timer.stop()
result.solution = getResultResponse.get('solution')
break

if result != None:
return result.solution
else:
raise TimeoutError('Failed to get a solution within the maximum ' \
f'response waiting interval: {timeouts.timeout:0.1f} sec.')
return result.solution

raise TimeoutError('Failed to get a solution within the maximum ' \
f'response waiting interval: {timeouts.timeout:0.1f} sec.')


async def _getTaskResult(self, task_id: str) -> Dict[str, Union[int, str, None]]:
Expand Down
9 changes: 9 additions & 0 deletions capmonstercloud_client/GetResultTimeouts.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,15 @@ def getImpervaTimeouts() -> GetResultTimeouts:
def getAltchaTimeouts() -> GetResultTimeouts:
return GetResultTimeouts(1, 0, 1, 50)

def getCastleTimeouts() -> GetResultTimeouts:
return GetResultTimeouts(1, 0, 1, 60)

def getTspdTimeouts() -> GetResultTimeouts:
return GetResultTimeouts(1, 0, 1, 60)

def getHuntTimeouts() -> GetResultTimeouts:
return GetResultTimeouts(1, 0, 1, 60)

def getCITTimeouts() -> GetResultTimeouts:
return GetResultTimeouts(0.35, 0, 0.2, 10)

Expand Down
42 changes: 42 additions & 0 deletions capmonstercloud_client/requests/CastleCustomTaskRequest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
from typing import Dict, Union
from pydantic import Field, validator

from .CustomTaskRequestBase import CustomTaskRequestBase

class CastleCustomTaskRequest(CustomTaskRequestBase):
captchaClass: str = Field(default='Castle')
websiteKey: str = Field()
metadata: Dict[str, Union[str, int]]

@validator('metadata')
def validate_metadata(cls, value):
if value.get('wUrl') is None:
raise TypeError(f'Expected that wUrl is defined.')
else:
if not isinstance(value.get('wUrl'), str):
raise TypeError(f'Expected that wUrl is str.')
if value.get('swUrl') is None:
raise TypeError(f'Expected that swUrl is defined.')
else:
if not isinstance(value.get('swUrl'), str):
raise TypeError(f'Expected that swUrl is str.')
if value.get('count') is not None and not isinstance(value.get('count'), int):
raise TypeError(f'Expected that count is int.')
return value

def getTaskDict(self) -> Dict[str, Union[str, int, bool]]:
task = {}
task['type'] = self.type
task['class'] = self.captchaClass
task['websiteURL'] = self.websiteUrl
task['websiteKey'] = self.websiteKey
task['metadata'] = self.metadata
if self.proxy:
task['proxyType'] = self.proxy.proxyType
task['proxyAddress'] = self.proxy.proxyAddress
task['proxyPort'] = self.proxy.proxyPort
task['proxyLogin'] = self.proxy.proxyLogin
task['proxyPassword'] = self.proxy.proxyPassword
if self.userAgent is not None:
task['userAgent'] = self.userAgent
return task
28 changes: 16 additions & 12 deletions capmonstercloud_client/requests/DataDomeCustomTaskRequest.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
from typing import Dict, Union
from pydantic import Field, validator
from pydantic import Field, validator, model_validator
from .CustomTaskRequestBase import CustomTaskRequestBase

class DataDomeCustomTaskRequest(CustomTaskRequestBase):
captchaClass: str = Field(default='DataDome')
metadata : Dict[str, str]

@validator('metadata')
def validate_metadata(cls, value):
if value.get('datadomeCookie') is None:
raise TypeError(f'Expect that datadomeCookie will be defined.')
if value.get('datadomeVersion') is not None and not isinstance(value.get('datadomeVersion'), str):
raise TypeError(f'Expected datadomeVersion to be str')
if value.get('captchaUrl') and value.get('htmlPageBase64'):
raise TypeError(f'Expected only one of [captchaUrl, htmlPageBase64]')
elif value.get('captchaUrl'):
Expand All @@ -18,22 +20,24 @@ def validate_metadata(cls, value):
return {i: value[i] for i in value if i != 'captchaUrl'}
else:
raise TypeError(f'Expected one of [captchaUrl, htmlPageBase64]')
if value.get('datadomeVersion') and not isinstance(value.get('datadomeVersion'), str):
raise TypeError(f'Expected datadomeVersion to be str')


@model_validator(mode='before')
def validate_datadome_proxy(cls, values):
proxy = values.get('proxy')
if proxy is None:
raise RuntimeError(f'You are required to use your own proxies.')
return values

def getTaskDict(self) -> Dict[str, Union[str, int, bool]]:
task = {}
task['type'] = self.type
task['class'] = self.captchaClass
task['websiteURL'] = self.websiteUrl
if self.proxy:
task['proxyType'] = self.proxy.proxyType
task['proxyAddress'] = self.proxy.proxyAddress
task['proxyPort'] = self.proxy.proxyPort
task['proxyLogin'] = self.proxy.proxyLogin
task['proxyPassword'] = self.proxy.proxyPassword
task['domains'] = self.domains
task['proxyType'] = self.proxy.proxyType
task['proxyAddress'] = self.proxy.proxyAddress
task['proxyPort'] = self.proxy.proxyPort
task['proxyLogin'] = self.proxy.proxyLogin
task['proxyPassword'] = self.proxy.proxyPassword
task['metadata'] = self.metadata
if self.userAgent is not None:
task['userAgent'] = self.userAgent
Expand Down
41 changes: 41 additions & 0 deletions capmonstercloud_client/requests/HuntCustomTaskRequest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
from typing import Dict, Union
from pydantic import Field, validator, model_validator

from .CustomTaskRequestBase import CustomTaskRequestBase

class HuntCustomTaskRequest(CustomTaskRequestBase):
captchaClass: str = Field(default='HUNT')
metadata: Dict[str, str]

@validator('metadata')
def validate_metadata(cls, value):
if value.get('apiGetLib') is None:
raise TypeError(f'Expect that apiGetLib will be defined.')
else:
if not isinstance(value.get('apiGetLib'), str):
raise TypeError(f'Expect that apiGetLib will be str.')
if value.get('data') is not None and not isinstance(value.get('data'), str):
raise TypeError(f'Expect that data will be str.')
return value

@model_validator(mode='before')
def validate_hunt_proxy(cls, values):
proxy = values.get('proxy')
if proxy is None:
raise RuntimeError(f'You are required to use your own proxies.')
return values

def getTaskDict(self) -> Dict[str, Union[str, int, bool]]:
task = {}
task['type'] = self.type
task['class'] = self.captchaClass
task['websiteURL'] = self.websiteUrl
task['metadata'] = self.metadata
task['proxyType'] = self.proxy.proxyType
task['proxyAddress'] = self.proxy.proxyAddress
task['proxyPort'] = self.proxy.proxyPort
task['proxyLogin'] = self.proxy.proxyLogin
task['proxyPassword'] = self.proxy.proxyPassword
if self.userAgent is not None:
task['userAgent'] = self.userAgent
return task
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@ class RecaptchaV2EnterpriseRequest(BaseRequestWithProxy):
enterprisePayload: Optional[str] = Field(default=None)
apiDomain: Optional[str] = Field(default=None)
pageAction: Optional[str] = Field(default=None)

userAgent: Optional[str] = Field(default=None)
cookies: Optional[str] = Field(default=None)

def getTaskDict(self) -> Dict[str, Union[str, int]]:
task = {}
task['type'] = self.type
Expand All @@ -28,4 +30,8 @@ def getTaskDict(self) -> Dict[str, Union[str, int]]:
task['apiDomain'] = self.apiDomain
if self.pageAction is not None:
task['pageAction'] = self.pageAction
if self.userAgent is not None:
task['userAgent'] = self.userAgent
if self.cookies is not None:
task['cookies'] = self.cookies
return task
8 changes: 6 additions & 2 deletions capmonstercloud_client/requests/RecaptchaV2Request.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,9 @@ class RecaptchaV2Request(BaseRequestWithProxy):
dataSValue: Optional[str] = Field(default=None)
userAgent: Optional[str] = Field(default=None)
cookies: Optional[str] = Field(default=None)
isInvisible: Optional[bool] = Field(default=None)

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

if self.dataSValue is not None:
task['recaptchaDataSValue'] = self.dataSValue

if self.userAgent is not None:
task['userAgent'] = self.userAgent

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

if self.isInvisible is not None:
task['isInvisible'] = self.isInvisible

return task

Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ class RecaptchaV3ProxylessRequest(BaseRequest):
websiteUrl: str
websiteKey: str
type: str = Field(default='RecaptchaV3TaskProxyless')
min_score: Optional[float] = Field(default=None)
minScore: Optional[float] = Field(default=None)
pageAction: Optional[str] = Field(default=None)

@validator('min_score')
@validator('minScore')
def validate_min_score(cls, value):
if value is not None:
if not 0.1 <= value <= 0.9:
Expand All @@ -23,8 +23,8 @@ def getTaskDict(self) -> Dict[str, Union[str, float]]:
task['type'] = self.type
task['websiteURL'] = self.websiteUrl
task['websiteKey'] = self.websiteKey
if self.min_score is not None:
task['minScore'] = self.min_score
if self.minScore is not None:
task['minScore'] = self.minScore
if self.pageAction is not None:
task['pageAction'] = self.pageAction
return task
16 changes: 14 additions & 2 deletions capmonstercloud_client/requests/TenDiCustomTaskRequest.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,21 @@
from typing import Dict, Union
from pydantic import Field
from typing import Dict, Optional, Union
from pydantic import Field, validator

from .CustomTaskRequestBase import CustomTaskRequestBase

class TenDiCustomTaskRequest(CustomTaskRequestBase):
captchaClass: str = Field(default='TenDI')
websiteKey: str = Field()
metadata: Optional[Dict[str, str]] = Field(default=None)

@validator('metadata')
def validate_metadata(cls, value):
if value is not None:
if not set(value.keys()).issubset(set(["captchaUrl"])):
raise TypeError(f'Allowed keys for metadata are "captchaUrl"')
if value.get('captchaUrl') is not None and not isinstance(value.get('captchaUrl'), str):
raise TypeError(f'Expect that captchaUrl will be str.')
return value

def getTaskDict(self) -> Dict[str, Union[str, int, bool]]:
task = {}
Expand All @@ -21,4 +31,6 @@ def getTaskDict(self) -> Dict[str, Union[str, int, bool]]:
task['proxyPassword'] = self.proxy.proxyPassword
if self.userAgent is not None:
task['userAgent'] = self.userAgent
if self.metadata is not None:
task['metadata'] = self.metadata
return task
44 changes: 44 additions & 0 deletions capmonstercloud_client/requests/TspdCustomTaskRequest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
from typing import Dict, Union
from pydantic import Field, validator, model_validator

from .CustomTaskRequestBase import CustomTaskRequestBase

class TspdCustomTaskRequest(CustomTaskRequestBase):
captchaClass: str = Field(default='tspd')
userAgent: str = Field()
metadata: Dict[str, str]

@validator('metadata')
def validate_metadata(cls, value):
if value.get('tspdCookie') is None:
raise TypeError(f'Expect that tspdCookie will be defined.')
else:
if not isinstance(value.get('tspdCookie'), str):
raise TypeError(f'Expect that tspdCookie will be str.')
if value.get('htmlPageBase64') is None:
raise TypeError(f'Expect that htmlPageBase64 will be defined.')
else:
if not isinstance(value.get('htmlPageBase64'), str):
raise TypeError(f'Expect that htmlPageBase64 will be str.')
return value

@model_validator(mode='before')
def validate_tspd_proxy(cls, values):
proxy = values.get('proxy')
if proxy is None:
raise RuntimeError(f'You are required to use your own proxies.')
return values

def getTaskDict(self) -> Dict[str, Union[str, int, bool]]:
task = {}
task['type'] = self.type
task['class'] = self.captchaClass
task['websiteURL'] = self.websiteUrl
task['metadata'] = self.metadata
task['userAgent'] = self.userAgent
task['proxyType'] = self.proxy.proxyType
task['proxyAddress'] = self.proxy.proxyAddress
task['proxyPort'] = self.proxy.proxyPort
task['proxyLogin'] = self.proxy.proxyLogin
task['proxyPassword'] = self.proxy.proxyPassword
return task
Loading
Loading