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
7 changes: 4 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,6 @@ Supported captcha recognition requests:

- [GeeTestProxylessRequest](https://zenno.link/doc-geetest-en)
- [GeeTestRequest](https://zenno.link/doc-geetest-proxy-en)
- [HCaptchaProxylessRequest](https://zenno.link/doc-hcaptcha-en)
- [HCaptchaRequest](https://zenno.link/doc-hcaptcha-proxy-en)
- [ImageToTextRequest](https://zenno.link/doc-ImageToTextTask-en)
- [RecaptchaV2ProxylessRequest](https://zenno.link/doc-recaptcha2-en)
- [RecaptchaV2Request](https://zenno.link/doc-recaptcha2-proxy-en)
Expand All @@ -42,8 +40,11 @@ Supported captcha recognition requests:
- [TurnstileProxylessRequest](https://zenno.link/doc-turnstile-en)
- [TurnstileRequest](https://zenno.link/doc-turnstile-proxy-en)
- [RecaptchaComplexImageTaskRequest](https://zenno.link/doc-complextask-rc-en)
- [HcaptchaComplexImageTaskRequest](https://zenno.link/doc-complextask-hc-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)
- [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)
- [ImpervaCustomTaskRequest](https://docs.capmonster.cloud/docs/captchas/incapsula)
- [ImpervaCustomTaskProxylessRequest](https://docs.capmonster.cloud/docs/captchas/incapsula)
15 changes: 12 additions & 3 deletions capmonstercloud_client/CapMonsterCloudClient.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@
((TenDiCustomTaskRequest, TenDiCustomTaskProxylessRequest), getTenDiTimeouts),
((BasiliskCustomTaskRequest, BasiliskCustomTaskProxylessRequest), getBasiliskTimeouts),
((AmazonWafRequest, AmazonWafProxylessRequest), getAmazonWafTimeouts),

((BinanceTaskRequest, BinanceTaskProxylessRequest), getBinanceTimeouts),
((ImpervaCustomTaskRequest, ImpervaCustomTaskProxylessRequest), getImpervaTimeouts)
)


Expand Down Expand Up @@ -77,7 +78,11 @@ async def solve_captcha(self, request: Union[RecaptchaV2EnterpriseProxylessReque
RecaptchaComplexImageTaskRequest,
FunCaptchaComplexImageTaskRequest,
DataDomeCustomTaskProxylessRequest,
DataDomeCustomTaskRequest],
DataDomeCustomTaskRequest,
BinanceTaskRequest,
BinanceTaskProxylessRequest,
ImpervaCustomTaskRequest,
ImpervaCustomTaskProxylessRequest],
) -> Dict[str, str]:
'''
Non-blocking method for captcha solving.
Expand Down Expand Up @@ -108,7 +113,11 @@ async def _solve(self, request: Union[RecaptchaV2EnterpriseProxylessRequest,
TurnstileRequest,
HcaptchaComplexImageTaskRequest,
RecaptchaComplexImageTaskRequest,
FunCaptchaComplexImageTaskRequest],
FunCaptchaComplexImageTaskRequest,
BinanceTaskRequest,
BinanceTaskProxylessRequest,
ImpervaCustomTaskRequest,
ImpervaCustomTaskProxylessRequest],
timeouts: GetResultTimeouts,
) -> Dict[str, str]:

Expand Down
6 changes: 6 additions & 0 deletions capmonstercloud_client/GetResultTimeouts.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,9 @@ def getBasiliskTimeouts() -> GetResultTimeouts:

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

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

def getImpervaTimeouts() -> GetResultTimeouts:
return GetResultTimeouts(1, 0, 1, 20)
17 changes: 17 additions & 0 deletions capmonstercloud_client/requests/BinanceTaskProxylessRequest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
from typing import Dict, Union

from .BinanceTaskRequestBase import BinanceTaskRequestBase


class BinanceTaskProxylessRequest(BinanceTaskRequestBase):
type: str = 'BinanceTaskProxyless'

def getTaskDict(self) -> Dict[str, Union[str, int, bool]]:
task = {}
task['type'] = self.type
task['validateId'] = self.validateId
task['websiteURL'] = self.websiteUrl
task['websiteKey'] = self.websiteKey
if self.userAgent is not None:
task['userAgent'] = self.userAgent
return task
22 changes: 22 additions & 0 deletions capmonstercloud_client/requests/BinanceTaskRequest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
from typing import Dict, Union
from pydantic import Field, validator

from .proxy_info import ProxyInfo
from .BinanceTaskRequestBase import BinanceTaskRequestBase

class BinanceTaskRequest(BinanceTaskRequestBase, ProxyInfo):

def getTaskDict(self) -> Dict[str, Union[str, int, bool]]:
task = {}
task['type'] = self.type
task['validateId'] = self.validateId
task['websiteURL'] = self.websiteUrl
task['websiteKey'] = self.websiteKey
task['proxyType'] = self.proxyType
task['proxyAddress'] = self.proxyAddress
task['proxyPort'] = self.proxyPort
task['proxyLogin'] = self.proxyLogin
task['proxyPassword'] = self.proxyPassword
if self.userAgent is not None:
task['userAgent'] = self.userAgent
return task
11 changes: 11 additions & 0 deletions capmonstercloud_client/requests/BinanceTaskRequestBase.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
from .baseRequest import BaseRequest, Field
from typing import Optional


class BinanceTaskRequestBase(BaseRequest):

type: str = Field(default='BinanceTask')
websiteKey: str = Field()
websiteUrl: str = Field()
validateId: str = Field()
userAgent: Optional[str] = None
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
from typing import Dict, Union
from pydantic import Field, validator

from .ImpervaCustomTaskRequestBase import ImpervaCustomTaskRequestBase

class ImpervaCustomTaskProxylessRequest(ImpervaCustomTaskRequestBase):
metadata : Dict[str, str]

@validator('metadata')
def validate_metadata(cls, value):
if value.get('incapsulaScriptBase64') is None:
raise TypeError(f'Expect that incapsulaScriptBase64 will be defined.')
else:
if not isinstance(value.get('incapsulaScriptBase64'), str):
raise TypeError(f'Expect that incapsulaScriptBase64 will be str.')
if value.get('incapsulaSessionCookie') is None:
raise TypeError(f'Expect that incapsulaSessionCookie will be defined.')
else:
if not isinstance(value.get('incapsulaSessionCookie'), str):
raise TypeError(f'Expect that incapsulaSessionCookie will be str.')
if value.get('reese84UrlEndpoint') is not None and not isinstance(value.get('incapsulaSessionCookie'), str):
raise TypeError(f'Expect that reese84UrlEndpoint will be str.')
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.userAgent is not None:
task['userAgent'] = self.userAgent
return task
39 changes: 39 additions & 0 deletions capmonstercloud_client/requests/ImpervaCustomTaskRequest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
from typing import Dict, Union
from pydantic import Field, validator

from .proxy_info import ProxyInfo
from .ImpervaCustomTaskRequestBase import ImpervaCustomTaskRequestBase

class ImpervaCustomTaskRequest(ImpervaCustomTaskRequestBase, ProxyInfo):
metadata : Dict[str, str]

@validator('metadata')
def validate_metadata(cls, value):
if value.get('incapsulaScriptBase64') is None:
raise TypeError(f'Expect that incapsulaScriptBase64 will be defined.')
else:
if not isinstance(value.get('incapsulaScriptBase64'), str):
raise TypeError(f'Expect that incapsulaScriptBase64 will be str.')
if value.get('incapsulaSessionCookie') is None:
raise TypeError(f'Expect that incapsulaSessionCookie will be defined.')
else:
if not isinstance(value.get('incapsulaSessionCookie'), str):
raise TypeError(f'Expect that incapsulaSessionCookie will be str.')
if value.get('reese84UrlEndpoint') is not None and not isinstance(value.get('incapsulaSessionCookie'), str):
raise TypeError(f'Expect that reese84UrlEndpoint will be str.')
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
task['proxyType'] = self.proxyType
task['proxyAddress'] = self.proxyAddress
task['proxyPort'] = self.proxyPort
task['proxyLogin'] = self.proxyLogin
task['proxyPassword'] = self.proxyPassword
if self.userAgent is not None:
task['userAgent'] = self.userAgent
return task
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
from typing import Dict, Union
from pydantic import Field

from .CustomTaskRequestBase import CustomTaskRequestBase

class ImpervaCustomTaskRequestBase(CustomTaskRequestBase):
type: str = Field(default='CustomTask')
captchaClass: str = Field(default='Imperva')
1 change: 1 addition & 0 deletions capmonstercloud_client/requests/TurnstileRequestBase.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ class TurnstileRequestBase(BaseRequest):
userAgent: Optional[str] = Field(default=None)
cloudflareTaskType: Optional[str] = Field(default=None)
htmlPageBase64: Optional[str] = Field(default=None)
apiJsUrl: Optional[str] = Field(default=None)

@validator('cloudflareTaskType')
def validate_cloudflare_task(cls, value):
Expand Down
9 changes: 8 additions & 1 deletion capmonstercloud_client/requests/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,18 @@
from .BasiliskCustomTaskProxylessRequest import BasiliskCustomTaskProxylessRequest
from .AmazonWafRequest import AmazonWafRequest
from .AmazonWafProxylessRequest import AmazonWafProxylessRequest
from .BinanceTaskRequest import BinanceTaskRequest
from .BinanceTaskProxylessRequest import BinanceTaskProxylessRequest
from .ImpervaCustomTaskRequest import ImpervaCustomTaskRequest
from .ImpervaCustomTaskProxylessRequest import ImpervaCustomTaskProxylessRequest


REQUESTS = ['RecaptchaV2EnterpiseRequest', 'RecaptchaV2EnterpriseProxylessRequest',
'RecaptchaV2ProxylessRequest', 'RecaptchaV2Request', 'RecaptchaV3ProxylessRequest',
'ImageToTextRequest', 'FuncaptchaProxylessRequest', 'FuncaptchaRequest',
'GeetestRequest', 'GeetestProxylessRequest', 'HcaptchaProxylessRequest',
'HcaptchaRequest', 'DataDomeCustomTaskRequest', 'DataDomeCustomTaskProxylessRequest',
'TenDiCustomTaskRequest', 'TenDiCustomTaskProxylessRequest', 'BasiliskCustomTaskRequest',
'BasiliskCustomTaskProxylessRequest', 'AmazonWafRequest', 'AmazonWafProxylessRequest']
'BasiliskCustomTaskProxylessRequest', 'AmazonWafRequest', 'AmazonWafProxylessRequest',
'BinanceTaskRequest', 'BinanceTaskProxylessRequest', 'ImpervaCustomTaskProxylessRequest',
'ImpervaCustomTaskRequest']
2 changes: 1 addition & 1 deletion capmonstercloud_client/version.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1.5.2
1.6.0
37 changes: 37 additions & 0 deletions examples/binance.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import os
import time
import asyncio

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

async def solve_captcha_sync(num_requests):
return [await cap_monster_client.solve_captcha(datadome_request) for _ in range(num_requests)]

async def solve_captcha_async(num_requests):
tasks = [asyncio.create_task(cap_monster_client.solve_captcha(datadome_request))
for _ in range(num_requests)]
return await asyncio.gather(*tasks, return_exceptions=True)

if __name__ == '__main__':
key = os.getenv('API_KEY')
client_options = ClientOptions(api_key=key)
cap_monster_client = CapMonsterClient(options=client_options)
datadome_request = BinanceTaskProxylessRequest(
websiteUrl='https://accounts.binance.com/ru/login?loginChannel=&return_to=',
websiteKey='login',
validateId="2b8137c0b9b44189800368819354e114"
)
nums = 3

# Sync test
sync_start = time.time()
sync_responses = asyncio.run(solve_captcha_sync(nums))
print(f'average execution time sync {1/((time.time()-sync_start)/nums):0.2f} ' \
f'resp/sec\nsolution: {sync_responses[0]}')

# Async test
async_start = time.time()
async_responses = asyncio.run(solve_captcha_async(nums))
print(f'average execution time async {1/((time.time()-async_start)/nums):0.2f} ' \
f'resp/sec\nsolution: {async_responses[0]}')
40 changes: 40 additions & 0 deletions examples/imperva.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import os
import time
import asyncio

from capmonstercloudclient.requests import ImpervaCustomTaskProxylessRequest
from capmonstercloudclient import ClientOptions, CapMonsterClient
import json

async def solve_captcha_sync(num_requests):
return [await cap_monster_client.solve_captcha(datadome_request) for _ in range(num_requests)]

async def solve_captcha_async(num_requests):
tasks = [asyncio.create_task(cap_monster_client.solve_captcha(datadome_request))
for _ in range(num_requests)]
return await asyncio.gather(*tasks, return_exceptions=True)

if __name__ == '__main__':
key = os.getenv('API_KEY')
client_options = ClientOptions(api_key=key)
cap_monster_client = CapMonsterClient(options=client_options)
metadata = {"incapsulaScriptBase64": "",
"incapsulaSessionCookie": "SAyLRzdYgUntD6v0r7nFBmxTYGcAAAAArkznhRMmVs/cBynTg3r6YA==",
"reese84UrlEndpoint": "Alarums-Exeunter-Hath-Brese-Banq-Wheth-frangerd-"}
datadome_request = ImpervaCustomTaskProxylessRequest(
websiteUrl='https://example.com/login',
metadata=metadata
)
nums = 3

# Sync test
sync_start = time.time()
sync_responses = asyncio.run(solve_captcha_sync(nums))
print(f'average execution time sync {1/((time.time()-sync_start)/nums):0.2f} ' \
f'resp/sec\nsolution: {sync_responses[0]}')

# Async test
async_start = time.time()
async_responses = asyncio.run(solve_captcha_async(nums))
print(f'average execution time async {1/((time.time()-async_start)/nums):0.2f} ' \
f'resp/sec\nsolution: {async_responses[0]}')
45 changes: 45 additions & 0 deletions test/binance_request_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import unittest
from copy import deepcopy

from pydantic import ValidationError
from capmonstercloudclient.requests import BinanceTaskProxylessRequest


class BinanceRequestTest(unittest.TestCase):

websiteUrlExample = 'https://binance.com/login'
websiteKeyExample = 'login'
userAgentExample = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36'

def test_binance(self,
):
required_fields = ['type',
'websiteURL',
'websiteKey',
'validateId']
request = BinanceTaskProxylessRequest(websiteKey=self.websiteKeyExample,
websiteUrl=self.websiteUrlExample,
validateId='asdgf')
task_dictionary = request.getTaskDict()
for f in required_fields:
self.assertTrue(f in list(task_dictionary.keys()),
msg=f'Required captcha input key "{f}" does not include to request.')

def test_binance_missing(self,):
required_fields = ['type',
'websiteURL',
'websiteKey',
'validateId']
base_kwargs = {}
self.assertRaises(ValidationError, BinanceTaskProxylessRequest, **base_kwargs)
base_kwargs.update({'websiteUrl': self.websiteUrlExample})
self.assertRaises(ValidationError, BinanceTaskProxylessRequest, **base_kwargs)
base_kwargs.update({'websiteKey': self.websiteKeyExample})
self.assertRaises(ValidationError, BinanceTaskProxylessRequest, **base_kwargs)
base_kwargs.update({'validateId': 'asdgf'})
BinanceTaskProxylessRequest(**base_kwargs)
base_kwargs.update({'userAgent': self.userAgentExample})
BinanceTaskProxylessRequest(**base_kwargs)

if __name__ == '__main__':
unittest.main()
Loading
Loading