Skip to content

Commit 6304282

Browse files
docstrings and bugfixes
1 parent d3a9408 commit 6304282

38 files changed

Lines changed: 801 additions & 209 deletions

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,5 @@ build/
44
env/
55
venv/
66
capmonstercloudclient.egg-info/
7-
.mcp.json
7+
.mcp.json
8+
.claude/

capmonstercloud_client/requests/AlibabaCustomTaskRequest.py

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,19 @@
99
}
1010

1111
class AlibabaCustomTaskRequest(CustomTaskRequestBase):
12-
captchaClass: str = Field(default='alibaba')
13-
metadata: Dict[str, Union[str, bool]]
12+
"""
13+
Represents a payload structure for solving Alibaba custom captcha challenges.
14+
15+
Attributes:
16+
captchaClass: The constant string value identifying the captcha
17+
class as "alibaba".
18+
metadata: A dictionary of Alibaba-specific parameters. Requires sceneId
19+
and prefix; userId, userUserId, verifyType, region, UserCertifyId,
20+
apiGetLib, and cookieRequired are optional, needed only for sites
21+
that use them.
22+
"""
23+
captchaClass: str = Field(default='alibaba', description='The constant string value identifying the captcha class as "alibaba".')
24+
metadata: Dict[str, Union[str, bool]] = Field(..., description='A dictionary of Alibaba-specific parameters. Requires sceneId and prefix; userId, userUserId, verifyType, region, UserCertifyId, apiGetLib, and cookieRequired are optional, needed only for sites that use them.')
1425

1526
@field_validator('metadata')
1627
@classmethod

capmonstercloud_client/requests/AltchaCustomTaskRequest.py

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,23 @@
44
from .CustomTaskRequestBase import CustomTaskRequestBase
55

66
class AltchaCustomTaskRequest(CustomTaskRequestBase):
7-
captchaClass: str = Field(default='altcha')
8-
websiteKey: str = Field()
9-
metadata : Dict[str, str]
7+
"""
8+
Represents a payload structure for solving Altcha proof-of-work
9+
captcha challenges via a custom module.
10+
11+
Attributes:
12+
captchaClass: The class (subtype) identifier of the custom
13+
module, constant "altcha" for this task.
14+
websiteKey: The site key associated with the Altcha challenge
15+
on the webpage. An empty string is allowed for this task.
16+
metadata: A dictionary containing the Altcha challenge parameters
17+
(challenge, iterations, salt, signature) extracted from the
18+
webpage.
19+
"""
20+
21+
captchaClass: str = Field(default='altcha', description='Class (subtype) identifier of the custom module, constant "altcha".')
22+
websiteKey: str = Field(description='Site key associated with the Altcha challenge on the webpage. An empty string is allowed for this task.')
23+
metadata: Dict[str, str] = Field(description='Altcha challenge parameters: challenge, iterations, salt, and signature.')
1024

1125
@field_validator('metadata')
1226
@classmethod
Lines changed: 79 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,98 @@
11
from typing import Dict, Union, Optional
2-
from pydantic import Field
2+
from pydantic import Field, model_validator
33

44
from .baseRequestWithProxy import BaseRequestWithProxy
55

66
class AmazonWafRequest(BaseRequestWithProxy):
7-
type: str = 'AmazonTask'
8-
websiteUrl: str
9-
challengeScript: str
10-
captchaScript: str
11-
websiteKey: str
12-
context: str
13-
iv: str
14-
cookieSolution: Optional[bool] = Field(default=None)
7+
"""
8+
Represents a payload structure for solving Amazon AWS WAF captcha challenges.
9+
10+
The live API accepts three mutually exclusive parameter sets:
11+
Option 1 (visible captcha): websiteUrl, websiteKey, captchaScript
12+
required; challengeScript/context/iv must not be set.
13+
Option 2 (challenge + captcha): websiteUrl, challengeScript, websiteKey,
14+
context, iv required; captchaScript optional.
15+
Option 3 (invisible/challenge-only): websiteUrl, challengeScript
16+
required; context and iv must be empty strings; websiteKey and
17+
captchaScript must not be set.
18+
19+
Attributes:
20+
type: The constant string value identifying the task type as "AmazonTask".
21+
websiteUrl: The URL of the webpage where the Amazon AWS WAF challenge
22+
is presented.
23+
challengeScript: Link to challenge.js served by AWS WAF on the target
24+
page. Required for Options 2 and 3; must not be set for Option 1.
25+
captchaScript: Link to captcha.js / jsapi.js served by AWS WAF on the
26+
target page. Required for Option 1, optional for Option 2, must
27+
not be set for Option 3.
28+
websiteKey: The site key associated with the AWS WAF challenge.
29+
Required for Options 1 and 2; must not be set for Option 3.
30+
context: The context token provided by AWS WAF, used to correlate
31+
the challenge with a specific session. Required for Option 2;
32+
must be an empty string for Option 3; must not be set for Option 1.
33+
iv: The initialization vector value provided by AWS WAF as part
34+
of the challenge payload. Required for Option 2; must be an
35+
empty string for Option 3; must not be set for Option 1.
36+
cookieSolution: When set to True, requests the solution to be
37+
returned as a ready-to-use cookie instead of a token.
38+
userAgent: Browser User-Agent to emulate. Only used for Option 1.
39+
Pass only a current Windows OS UA.
40+
"""
41+
type: str = Field(default='AmazonTask', description='The constant string value identifying the task type as "AmazonTask".')
42+
websiteUrl: str = Field(..., description='The URL of the webpage where the Amazon AWS WAF challenge is presented.')
43+
challengeScript: Optional[str] = Field(default=None, description='Link to challenge.js served by AWS WAF on the target page. Required for Options 2 and 3; must not be set for Option 1.')
44+
captchaScript: Optional[str] = Field(default=None, description='Link to captcha.js / jsapi.js served by AWS WAF on the target page. Required for Option 1, optional for Option 2, must not be set for Option 3.')
45+
websiteKey: Optional[str] = Field(default=None, description='The site key associated with the AWS WAF challenge. Required for Options 1 and 2; must not be set for Option 3.')
46+
context: Optional[str] = Field(default=None, description='The context token provided by AWS WAF, used to correlate the challenge with a specific session. Required for Option 2; must be an empty string for Option 3; must not be set for Option 1.')
47+
iv: Optional[str] = Field(default=None, description='The initialization vector value provided by AWS WAF as part of the challenge payload. Required for Option 2; must be an empty string for Option 3; must not be set for Option 1.')
48+
cookieSolution: Optional[bool] = Field(default=None, description='When set to True, requests the solution to be returned as a ready-to-use cookie instead of a token.')
49+
userAgent: Optional[str] = Field(default=None, description='Browser User-Agent to emulate. Only used for Option 1. Pass only a current Windows OS UA.')
50+
51+
@model_validator(mode='after')
52+
def validate_amazon_waf_variant(self):
53+
if self.challengeScript is None:
54+
# Option 1: visible captcha, no challenge.js involved.
55+
if self.websiteKey is None or self.captchaScript is None:
56+
raise ValueError('Expect that "websiteKey" and "captchaScript" will be filled '
57+
'when "challengeScript" is not provided (Option 1).')
58+
if self.context is not None or self.iv is not None:
59+
raise ValueError('"context" and "iv" are not used when "challengeScript" is not provided (Option 1).')
60+
elif self.websiteKey is None and self.captchaScript is None:
61+
# Option 3: invisible/challenge-only captcha.
62+
if self.context != '' or self.iv != '':
63+
raise ValueError('Expect that "context" and "iv" will be empty strings '
64+
'when only "challengeScript" is provided (Option 3).')
65+
else:
66+
# Option 2: challenge + captcha.
67+
if self.websiteKey is None or self.context is None or self.iv is None:
68+
raise ValueError('Expect that "websiteKey", "context" and "iv" will be filled '
69+
'when "challengeScript" is provided together with "websiteKey" (Option 2).')
70+
return self
1571

1672
def getTaskDict(self) -> Dict[str, Union[str, int, bool]]:
1773
task = {}
1874
task['type'] = self.type
1975
task['websiteURL'] = self.websiteUrl
20-
task['challengeScript'] = self.challengeScript
21-
task['captchaScript'] = self.captchaScript
22-
task['websiteKey'] = self.websiteKey
23-
task['context'] = self.context
24-
task['iv'] = self.iv
25-
76+
if self.challengeScript is not None:
77+
task['challengeScript'] = self.challengeScript
78+
if self.captchaScript is not None:
79+
task['captchaScript'] = self.captchaScript
80+
if self.websiteKey is not None:
81+
task['websiteKey'] = self.websiteKey
82+
if self.context is not None:
83+
task['context'] = self.context
84+
if self.iv is not None:
85+
task['iv'] = self.iv
86+
2687
if self.proxy:
2788
task['proxyType'] = self.proxy.proxyType
2889
task['proxyAddress'] = self.proxy.proxyAddress
2990
task['proxyPort'] = self.proxy.proxyPort
3091
task['proxyLogin'] = self.proxy.proxyLogin
3192
task['proxyPassword'] = self.proxy.proxyPassword
32-
93+
3394
if self.cookieSolution is not None:
3495
task['cookieSolution'] = self.cookieSolution
96+
if self.userAgent is not None:
97+
task['userAgent'] = self.userAgent
3598
return task

capmonstercloud_client/requests/BasiliskCustomTaskRequest.py

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,19 @@
44
from .CustomTaskRequestBase import CustomTaskRequestBase
55

66
class BasiliskCustomTaskRequest(CustomTaskRequestBase):
7-
captchaClass: str = Field(default='Basilisk')
8-
websiteKey: str = Field()
7+
"""
8+
Represents a payload structure for solving Basilisk custom captcha
9+
challenges.
10+
11+
Attributes:
12+
captchaClass: The class (subtype) identifier of the custom module,
13+
fixed to "Basilisk" for this task type.
14+
websiteKey: The site key associated with the Basilisk captcha on
15+
the webpage.
16+
"""
17+
18+
captchaClass: str = Field(default='Basilisk', description='Class (subtype) identifier of the custom module, fixed to "Basilisk".')
19+
websiteKey: str = Field(..., description='Site key associated with the Basilisk captcha on the webpage.')
920

1021
def getTaskDict(self) -> Dict[str, Union[str, int, bool]]:
1122
task = {}

capmonstercloud_client/requests/BinanceTaskRequest.py

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,23 @@
44
from .baseRequestWithProxy import BaseRequestWithProxy
55

66
class BinanceTaskRequest(BaseRequestWithProxy):
7-
type: str = Field(default='BinanceTask')
8-
websiteKey: str = Field()
9-
websiteUrl: str = Field()
10-
validateId: str = Field()
11-
userAgent: Optional[str] = None
7+
"""
8+
Represents a payload structure for solving Binance's custom captcha challenge.
9+
10+
Attributes:
11+
type: The constant string value identifying the task type as "BinanceTask".
12+
websiteKey: The site key associated with the Binance captcha challenge.
13+
websiteUrl: The URL of the webpage containing the Binance captcha challenge.
14+
validateId: A unique identifier for the specific captcha validation
15+
attempt, issued by Binance for each challenge instance.
16+
userAgent: Browser User-Agent to emulate. Pass only a current
17+
Windows OS UA.
18+
"""
19+
type: str = Field(default='BinanceTask', description='The constant string value identifying the task type as "BinanceTask".')
20+
websiteKey: str = Field(description="The site key associated with the Binance captcha challenge.")
21+
websiteUrl: str = Field(description="The URL of the webpage containing the Binance captcha challenge.")
22+
validateId: str = Field(description="A unique identifier for the specific captcha validation attempt, issued by Binance for each challenge instance.")
23+
userAgent: Optional[str] = Field(default=None, description="Browser User-Agent to emulate. Pass only a current Windows OS UA.")
1224

1325
def getTaskDict(self) -> Dict[str, Union[str, int, bool]]:
1426
task = {}

capmonstercloud_client/requests/CastleCustomTaskRequest.py

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,21 @@
44
from .CustomTaskRequestBase import CustomTaskRequestBase
55

66
class CastleCustomTaskRequest(CustomTaskRequestBase):
7-
captchaClass: str = Field(default='Castle')
8-
websiteKey: str = Field()
9-
metadata: Dict[str, Union[str, int]]
7+
"""
8+
Represents a payload structure for solving Castle challenges via a custom task.
9+
10+
Attributes:
11+
captchaClass: The constant string value identifying the captcha
12+
class as "Castle".
13+
websiteKey: The site key associated with the Castle challenge on the
14+
webpage.
15+
metadata: A dictionary of additional parameters required to solve the
16+
challenge, including the worker script URL (wUrl), service worker
17+
URL (swUrl), and an optional request count (count).
18+
"""
19+
captchaClass: str = Field(default='Castle', description='The constant string value identifying the captcha class as "Castle".')
20+
websiteKey: str = Field(description='The site key associated with the Castle challenge on the webpage.')
21+
metadata: Dict[str, Union[str, int]] = Field(description='A dictionary of additional parameters required to solve the challenge, including the worker script URL (wUrl), service worker URL (swUrl), and an optional request count (count).')
1022

1123
@field_validator('metadata')
1224
@classmethod
Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,25 @@
11
from typing import Optional, List
22

3+
from pydantic import Field
4+
35
from .baseRequest import BaseRequest
46

57
class ComplexImageTaskRequestBase(BaseRequest):
6-
captchaClass: str # Class(subtype) of ComplexImageTask
7-
taskType: str = "ComplexImageTask" # Recognition task type
8-
websiteUrl: Optional[str] = None # Address of a webpage with captcha
9-
imagesUrls: Optional[List[str]] = None # Collection with image urls. Must be populated if <see cref="ImagesBase64"/> not.
10-
imagesBase64: Optional[List[str]] = None # Collection with base64 encoded images. Must be populated if <see cref="ImageUrls"/> not.
11-
userAgent: Optional[str] = None # It is required that you use a signature of a modern browser
8+
"""
9+
Represents a payload structure for solving complex image-based recognition tasks.
10+
11+
Attributes:
12+
captchaClass: The class (subtype) of the ComplexImageTask, identifying
13+
the specific image recognition scenario to be solved.
14+
taskType: The constant string value identifying the task type as
15+
"ComplexImageTask".
16+
websiteUrl: The URL of the webpage containing the captcha, if applicable.
17+
imagesBase64: A collection of base64-encoded images to be recognized.
18+
userAgent: Browser User-Agent to emulate. Pass only a current
19+
Windows OS UA.
20+
"""
21+
captchaClass: str = Field(..., description='Class(subtype) of ComplexImageTask.') # Class(subtype) of ComplexImageTask
22+
taskType: str = Field(default="ComplexImageTask", description='Recognition task type.') # Recognition task type
23+
websiteUrl: Optional[str] = Field(default=None, description='Address of a webpage with captcha.') # Address of a webpage with captcha
24+
imagesBase64: Optional[List[str]] = Field(default=None, description='Collection with base64 encoded images.') # Collection with base64 encoded images.
25+
userAgent: Optional[str] = Field(default=None, description='Browser User-Agent to emulate. Pass only a current Windows OS UA.')
Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,27 @@
11
from typing import Optional, List
22

3+
from pydantic import Field
4+
35
from .baseRequestWithProxy import BaseRequestWithProxy
46

57
class CustomTaskRequestBase(BaseRequestWithProxy):
6-
captchaClass: str # Class(subtype) of ComplexImageTask
7-
type: str = "CustomTask" # Recognition task type
8-
websiteUrl: str # Address of a webpage with captcha
9-
userAgent: Optional[str] = None
10-
domains: Optional[List[str]] = None
8+
"""
9+
Base payload structure for CustomTask-family anti-bot/WAF challenges
10+
(e.g. DataDome, Imperva, Basilisk, TenDI, Altcha, TSPD, HUNT, Alibaba,
11+
Friendly Captcha), each selected via a fixed "class" discriminator value.
12+
13+
Attributes:
14+
captchaClass: The built-in class (subtype) discriminator identifying
15+
which CustomTask variant to solve (e.g. "DataDome", "Imperva", "HUNT").
16+
type: The constant string value identifying the task type as "CustomTask".
17+
websiteUrl: The URL of the webpage containing the captcha.
18+
userAgent: Browser User-Agent to emulate. Pass only a current
19+
Windows OS UA.
20+
domains: A list of domains the returned cookies/solution should apply to.
21+
"""
22+
23+
captchaClass: str = Field(..., description='The built-in class (subtype) discriminator identifying which CustomTask variant to solve (e.g. "DataDome", "Imperva", "HUNT").')
24+
type: str = Field(default="CustomTask", description='The constant string value identifying the task type as "CustomTask".')
25+
websiteUrl: str = Field(..., description='Address of a webpage with captcha.')
26+
userAgent: Optional[str] = Field(default=None, description='Browser User-Agent to emulate. Pass only a current Windows OS UA.')
27+
domains: Optional[List[str]] = Field(default=None, description='A list of domains the returned cookies/solution should apply to.')

capmonstercloud_client/requests/DataDomeCustomTaskRequest.py

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,20 @@
33
from .CustomTaskRequestBase import CustomTaskRequestBase
44

55
class DataDomeCustomTaskRequest(CustomTaskRequestBase):
6-
captchaClass: str = Field(default='DataDome')
7-
metadata : Dict[str, str]
6+
"""
7+
Represents a payload structure for solving DataDome custom challenges.
8+
9+
Attributes:
10+
captchaClass: The constant string value identifying the captcha
11+
class as "DataDome".
12+
metadata: A dictionary carrying DataDome-specific challenge data:
13+
the required captchaUrl and datadomeCookie, plus the optional
14+
datadomeVersion.
15+
proxy: Proxy settings to route the request through. Required for
16+
this task type — DataDome will not solve without your own proxy.
17+
"""
18+
captchaClass: str = Field(default='DataDome', description='The constant string value identifying the captcha class as "DataDome".')
19+
metadata : Dict[str, str] = Field(..., description='A dictionary carrying DataDome-specific challenge data: the required captchaUrl and datadomeCookie, plus the optional datadomeVersion.')
820

921
@field_validator('metadata')
1022
@classmethod
@@ -13,14 +25,9 @@ def validate_metadata(cls, value):
1325
raise TypeError(f'Expect that datadomeCookie will be defined.')
1426
if value.get('datadomeVersion') is not None and not isinstance(value.get('datadomeVersion'), str):
1527
raise TypeError(f'Expected datadomeVersion to be str')
16-
if value.get('captchaUrl') and value.get('htmlPageBase64'):
17-
raise TypeError(f'Expected only one of [captchaUrl, htmlPageBase64]')
18-
elif value.get('captchaUrl'):
19-
return {i: value[i] for i in value if i != 'htmlPageBase64'}
20-
elif value.get('htmlPageBase64'):
21-
return {i: value[i] for i in value if i != 'captchaUrl'}
22-
else:
23-
raise TypeError(f'Expected one of [captchaUrl, htmlPageBase64]')
28+
if value.get('captchaUrl') is None:
29+
raise TypeError(f'Expect that captchaUrl will be defined.')
30+
return value
2431

2532
@model_validator(mode='before')
2633
def validate_datadome_proxy(cls, values):

0 commit comments

Comments
 (0)