Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 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