Skip to content
Open
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
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,6 @@ dist/
build/
env/
venv/
capmonstercloudclient.egg-info/
capmonstercloudclient.egg-info/
.mcp.json
.claude/
134 changes: 91 additions & 43 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,58 +1,106 @@
# Zennolab.CapMonsterCloud.Client

> [!IMPORTANT]
> This repository has been moved and is no longer maintained.
>
> New repository: [https://github.com/CapMonsterCloud/client-python](https://github.com/CapMonsterCloud/client-python)
>
> Please update your references and use the new repository for all future development.
Official Python client library for [capmonster.cloud](https://capmonster.cloud/) — an AI-powered CAPTCHA solving and anti-bot bypass API.

## Installation

Official python client library for [capmonster.cloud](https://capmonster.cloud/) captcha recognition service
```bash
python3 -m pip install capmonstercloudclient
```

## Installation
## 🚀 Quick Start

python3 -m pip install capmonstercloudclient
1. Get your API key in the [CapMonster Cloud Dashboard](https://dash.capmonster.cloud/).
2. Install the package (see above).
3. Copy a snippet below, replace `YOUR_API_KEY`, and run it.

## Usage
### Bypass reCAPTCHA v2

***
import asyncio
```python
import asyncio

from capmonstercloudclient import CapMonsterClient, ClientOptions
from capmonstercloudclient.requests import RecaptchaV2ProxylessRequest
from capmonstercloudclient import CapMonsterClient, ClientOptions
from capmonstercloudclient.requests import RecaptchaV2Request

client_options = ClientOptions(api_key=<YOUR_API_KEY>)

async def main():
client_options = ClientOptions(api_key="YOUR_API_KEY")
cap_monster_client = CapMonsterClient(options=client_options)

async def solve_captcha():
return await cap_monster_client.solve_captcha(recaptcha2request)

recaptcha2request = RecaptchaV2ProxylessRequest(websiteUrl="https://lessons.zennolab.com/captchas/recaptcha/v2_simple.php?level=high",
websiteKey="6Lcg7CMUAAAAANphynKgn9YAgA4tQ2KI_iqRyTwd")

responses = asyncio.run(solve_captcha())
print(responses)
***

Supported captcha recognition requests:

- [GeeTestProxylessRequest](https://zenno.link/doc-geetest-en)
- [GeeTestRequest](https://zenno.link/doc-geetest-proxy-en)
- [ImageToTextRequest](https://zenno.link/doc-ImageToTextTask-en)
- [RecaptchaV2ProxylessRequest](https://zenno.link/doc-recaptcha2-en)
- [RecaptchaV2Request](https://zenno.link/doc-recaptcha2-proxy-en)
- [RecaptchaV3ProxylessRequest](https://zenno.link/doc-recaptcha3-en)
- [RecaptchaV2EnterpriseProxylessRequest](https://zenno.link/doc-recaptcha2e-en)
- [RecaptchaV2EnterpriseRequest](https://zenno.link/doc-recaptcha2e-proxy-en)
- [TurnstileProxylessRequest](https://zenno.link/doc-turnstile-en)
- [TurnstileRequest](https://zenno.link/doc-turnstile-proxy-en)
- [RecaptchaComplexImageTaskRequest](https://zenno.link/doc-complextask-rc-en)
- [DataDomeCustomTaskRequest](https://docs.capmonster.cloud/docs/captchas/datadome)
- [TenDiCustomTaskRequest](https://docs.capmonster.cloud/docs/captchas/tendi)
- [BasiliskCustomTaskRequest](https://docs.capmonster.cloud/docs/captchas/Basilisk-task)
recaptcha2_request = RecaptchaV2Request(
websiteUrl="https://lessons.zennolab.com/captchas/recaptcha/v2_simple.php?level=high",
websiteKey="6Lcg7CMUAAAAANphynKgn9YAgA4tQ2KI_iqRyTwd",
)

solution = await cap_monster_client.solve_captcha(recaptcha2_request)
print(solution) # {'gRecaptchaResponse': '...'}


asyncio.run(main())
```

### Bypass Cloudflare Turnstile

```python
import asyncio

from capmonstercloudclient import CapMonsterClient, ClientOptions
from capmonstercloudclient.requests import TurnstileRequest


async def main():
client_options = ClientOptions(api_key="YOUR_API_KEY")
cap_monster_client = CapMonsterClient(options=client_options)

turnstile_request = TurnstileRequest(
websiteURL="https://tsinvisble.zlsupport.com",
websiteKey="0x4AAAAAAABUY0VLtOUMAHxE",
)

solution = await cap_monster_client.solve_captcha(turnstile_request)
print(solution) # {'token': '...'}


asyncio.run(main())
```

More end-to-end examples (proxies, image-based captchas, custom anti-bot tasks) are available in the [`examples/`](examples/) directory.

## ⚡ Supported CAPTCHA Recognition Requests

### Classic captcha tasks

- [ImageToTextRequest](https://docs.capmonster.cloud/docs/captchas/image-to-text)
- [RecaptchaV2Request](https://docs.capmonster.cloud/docs/captchas/no-captcha-task)
- [RecaptchaV2EnterpriseRequest](https://docs.capmonster.cloud/docs/captchas/recaptcha-v2-enterprise-task)
- [RecaptchaV3ProxylessRequest](https://docs.capmonster.cloud/docs/captchas/recaptcha-v3-task)
- [FuncaptchaRequest](https://docs.capmonster.cloud/docs/captchas/funcaptcha-task)
- [GeetestRequest](https://docs.capmonster.cloud/docs/captchas/geetest-task)
- [TurnstileRequest — Cloudflare Turnstile](https://docs.capmonster.cloud/docs/captchas/turnstile-task)
- [TurnstileRequest — Cloudflare Challenge](https://docs.capmonster.cloud/docs/captchas/turnstile-challenge-task)
- [TurnstileRequest — Cloudflare Waiting Room](https://docs.capmonster.cloud/docs/captchas/turnstile-waitroom-task)
- [AmazonWafRequest](https://docs.capmonster.cloud/docs/captchas/amazon-task)
- [BinanceTaskRequest](https://docs.capmonster.cloud/docs/captchas/binance)
- [BinanceTaskProxylessRequest](https://docs.capmonster.cloud/docs/captchas/binance)
- [MTCaptchaRequest](https://docs.capmonster.cloud/docs/captchas/mtcaptcha-task)
- [ProsopoTaskRequest](https://docs.capmonster.cloud/docs/captchas/prosopo-task)
- [YidunRequest](https://docs.capmonster.cloud/docs/captchas/yidun-task)

### Custom tasks (anti-bot / WAF / custom challenge systems)

- [AlibabaCustomTaskRequest](https://docs.capmonster.cloud/docs/captchas/alibaba-task)
- [AltchaCustomTaskRequest](https://docs.capmonster.cloud/docs/captchas/altcha-task)
- [BasiliskCustomTaskRequest](https://docs.capmonster.cloud/docs/captchas/Basilisk-task)
- [DataDomeCustomTaskRequest](https://docs.capmonster.cloud/docs/captchas/datadome)
- [FriendlyCustomTaskRequest](https://docs.capmonster.cloud/docs/captchas/friendly-task)
- [HuntCustomTaskRequest](https://docs.capmonster.cloud/docs/captchas/hunt-task)
- [ImpervaCustomTaskRequest](https://docs.capmonster.cloud/docs/captchas/incapsula)
- [ImpervaCustomTaskProxylessRequest](https://docs.capmonster.cloud/docs/captchas/incapsula)
- [TenDiCustomTaskRequest](https://docs.capmonster.cloud/docs/captchas/tendi)
- [TspdCustomTaskRequest](https://docs.capmonster.cloud/docs/captchas/tspd-task)

### Complex image tasks (grid / dynamic image selection tasks)

- [RecaptchaComplexImageTaskRequest](https://docs.capmonster.cloud/docs/captchas/recaptcha-click)
- [RecognitionComplexImageTaskRequest](https://docs.capmonster.cloud/docs/captchas/compleximage/rotation/baidu)

---
**[Official Documentation](https://docs.capmonster.cloud/docs/getting-start/)** | **[Register Account](https://dash.capmonster.cloud/)**
15 changes: 12 additions & 3 deletions capmonstercloud_client/CapMonsterCloudClient.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,16 @@
((BinanceTaskRequest,), getBinanceTimeouts),
((ImpervaCustomTaskRequest,), getImpervaTimeouts),
((RecognitionComplexImageTaskRequest,), getCITTimeouts),
((MTCaptchaRequest,), getImage2TextTimeouts),
((MTCaptchaRequest,), getMTCaptchaTimeouts),
((YidunRequest,), getYidunTimeouts),
((TemuCustomTaskRequest,), getTemuTimeouts),
((ProsopoTaskRequest,), getProsopoTimeouts),
((AltchaCustomTaskRequest,), getAltchaTimeouts),
((CastleCustomTaskRequest,), getCastleTimeouts),
((TspdCustomTaskRequest,), getTspdTimeouts),
((HuntCustomTaskRequest,), getHuntTimeouts),
((AlibabaCustomTaskRequest,), getAlibabaTimeouts),
((FriendlyCustomTaskRequest,), getFriendlyTimeouts),
)


Expand Down Expand Up @@ -106,7 +108,9 @@ async def solve_captcha(self, request: Union[
AltchaCustomTaskRequest,
CastleCustomTaskRequest,
TspdCustomTaskRequest,
HuntCustomTaskRequest],
HuntCustomTaskRequest,
AlibabaCustomTaskRequest,
FriendlyCustomTaskRequest],
) -> Dict[str, str]:
'''
Non-blocking method for captcha solving.
Expand Down Expand Up @@ -145,7 +149,12 @@ async def _solve(self, request: Union[
YidunRequest,
TemuCustomTaskRequest,
ProsopoTaskRequest,
AltchaCustomTaskRequest],
AltchaCustomTaskRequest,
CastleCustomTaskRequest,
TspdCustomTaskRequest,
HuntCustomTaskRequest,
AlibabaCustomTaskRequest,
FriendlyCustomTaskRequest],
timeouts: GetResultTimeouts,
) -> Dict[str, str]:

Expand Down
15 changes: 12 additions & 3 deletions capmonstercloud_client/GetResultTimeouts.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ def getTurnstileTimeouts() -> GetResultTimeouts:
return GetResultTimeouts(1, 0, 1, 80)

def getDatadomeTimeouts() -> GetResultTimeouts:
return GetResultTimeouts(1, 0, 1, 80)
return GetResultTimeouts(1, 0, 3, 180)

def getTenDiTimeouts() -> GetResultTimeouts:
return GetResultTimeouts(1, 10, 3, 180)
Expand All @@ -51,7 +51,7 @@ def getBinanceTimeouts() -> GetResultTimeouts:
return GetResultTimeouts(1, 0, 1, 20)

def getImpervaTimeouts() -> GetResultTimeouts:
return GetResultTimeouts(1, 0, 1, 20)
return GetResultTimeouts(1, 0, 1, 15)

def getAltchaTimeouts() -> GetResultTimeouts:
return GetResultTimeouts(1, 0, 1, 50)
Expand All @@ -63,11 +63,20 @@ def getTspdTimeouts() -> GetResultTimeouts:
return GetResultTimeouts(1, 0, 1, 60)

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

def getAlibabaTimeouts() -> GetResultTimeouts:
return GetResultTimeouts(1, 0, 3, 120)

def getFriendlyTimeouts() -> GetResultTimeouts:
return GetResultTimeouts(1, 0, 3, 180)

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

def getMTCaptchaTimeouts() -> GetResultTimeouts:
return GetResultTimeouts(1, 10, 3, 180)

def getYidunTimeouts() -> GetResultTimeouts:
return GetResultTimeouts(1, 10, 3, 180)

Expand Down
11 changes: 7 additions & 4 deletions capmonstercloud_client/clientOptions.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from pydantic import BaseModel, validator, Field
from pydantic import BaseModel, field_validator, Field
from .requests import ClientProxyInfo
from typing import Optional

Expand All @@ -10,19 +10,22 @@ class ClientOptions(BaseModel):
client_timeout: float = Field(default=20.0)


@validator('api_key')
@field_validator('api_key')
@classmethod
def validate_api_key(cls, value):
if not isinstance(value, str):
raise TypeError(f'Api Key must be <str> type, got {type(value)}')
return value

@validator('service_url')
@field_validator('service_url')
@classmethod
def validate_service_url(cls, value):
if not isinstance(value, str):
raise TypeError(f'Service url must be <str> type, got {type(value)}')
return value

@validator('default_soft_id')
@field_validator('default_soft_id')
@classmethod
def validate_soft_id(cls, value):
if not isinstance(value, int):
raise TypeError(f'Soft id must be <int> type, got {type(value)}')
Expand Down
59 changes: 59 additions & 0 deletions capmonstercloud_client/requests/AlibabaCustomTaskRequest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
from typing import Dict, Optional, Union
from pydantic import Field, field_validator

from .CustomTaskRequestBase import CustomTaskRequestBase

ALLOWED_METADATA_KEYS = {
'sceneId', 'prefix', 'userId', 'userUserId', 'verifyType',
'region', 'UserCertifyId', 'apiGetLib', 'cookieRequired',
}

class AlibabaCustomTaskRequest(CustomTaskRequestBase):
"""
Represents a payload structure for solving Alibaba custom captcha challenges.

Attributes:
captchaClass: The constant string value identifying the captcha
class as "alibaba".
metadata: 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.
"""
captchaClass: str = Field(default='alibaba', description='The constant string value identifying the captcha class as "alibaba".')
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.')

@field_validator('metadata')
@classmethod
def validate_metadata(cls, value):
if not set(value.keys()).issubset(ALLOWED_METADATA_KEYS):
raise TypeError(f'Allowed keys for metadata are {sorted(ALLOWED_METADATA_KEYS)}')
if value.get('sceneId') is None:
raise TypeError(f'Expect that sceneId will be defined.')
else:
if not isinstance(value.get('sceneId'), str):
raise TypeError(f'Expect that sceneId will be str.')
if value.get('prefix') is None:
raise TypeError(f'Expect that prefix will be defined.')
else:
if not isinstance(value.get('prefix'), str):
raise TypeError(f'Expect that prefix will be str.')
if value.get('cookieRequired') is not None and not isinstance(value.get('cookieRequired'), bool):
raise TypeError(f'Expect that cookieRequired will be bool.')
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['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
25 changes: 20 additions & 5 deletions capmonstercloud_client/requests/AltchaCustomTaskRequest.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,29 @@
from typing import Dict, Union
from pydantic import Field, validator
from pydantic import Field, field_validator

from .CustomTaskRequestBase import CustomTaskRequestBase

class AltchaCustomTaskRequest(CustomTaskRequestBase):
captchaClass: str = Field(default='altcha')
websiteKey: str = Field()
metadata : Dict[str, str]
"""
Represents a payload structure for solving Altcha proof-of-work
captcha challenges via a custom module.

Attributes:
captchaClass: The class (subtype) identifier of the custom
module, constant "altcha" for this task.
websiteKey: The site key associated with the Altcha challenge
on the webpage. An empty string is allowed for this task.
metadata: A dictionary containing the Altcha challenge parameters
(challenge, iterations, salt, signature) extracted from the
webpage.
"""

captchaClass: str = Field(default='altcha', description='Class (subtype) identifier of the custom module, constant "altcha".')
websiteKey: str = Field(description='Site key associated with the Altcha challenge on the webpage. An empty string is allowed for this task.')
metadata: Dict[str, str] = Field(description='Altcha challenge parameters: challenge, iterations, salt, and signature.')

@validator('metadata')
@field_validator('metadata')
@classmethod
def validate_metadata(cls, value):
for key in ['challenge', 'iterations', 'salt', 'signature']:
if value.get(key) is None:
Expand Down
Loading
Loading