Skip to content

Commit

Permalink
Merge pull request #39 from AndreiDrang/main
Browse files Browse the repository at this point in the history
0.8
  • Loading branch information
AndreiDrang committed Sep 12, 2023
2 parents 0698bbc + 21a787e commit 78f46a1
Show file tree
Hide file tree
Showing 16 changed files with 272 additions and 10 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ jobs:
strategy:
fail-fast: false
matrix:
python-version: ["3.8", "3.9", "3.10", "3.11"]
python-version: ["3.8", "3.11"]

steps:
- uses: actions/checkout@v3
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ At the lowest price on the market, you may receive a variety of solutions, inclu

[![PyPI version](https://badge.fury.io/py/python3-capsolver.svg)](https://badge.fury.io/py/python3-capsolver)
[![Python versions](https://img.shields.io/pypi/pyversions/python3-capsolver.svg?logo=python&logoColor=FBE072)](https://badge.fury.io/py/python3-capsolver)
[![Downloads](https://pepy.tech/badge/python3-capsolver/month)](https://pepy.tech/project/python3-capsolver)
[![Downloads](https://static.pepy.tech/badge/python3-capsolver/month)](https://pepy.tech/project/python3-capsolver)

[![Maintainability](https://api.codeclimate.com/v1/badges/3c30167b5fb37a0775ea/maintainability)](https://codeclimate.com/github/AndreiDrang/python3-capsolver/maintainability)
[![Codacy Badge](https://app.codacy.com/project/badge/Grade/323d4eda0fe1477bbea8fe8902b9e97e)](https://www.codacy.com/gh/AndreiDrang/python3-capsolver/dashboard?utm_source=github.com&utm_medium=referral&utm_content=AndreiDrang/python3-capsolver&utm_campaign=Badge_Grade)
Expand Down
1 change: 1 addition & 0 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

from python3_capsolver import (
core,
akamai,
gee_test,
hcaptcha,
recaptcha,
Expand Down
1 change: 1 addition & 0 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ The library is intended for software developers and is used to work with the `Ca
modules/cloudflare/example.rst
modules/aws-waf/example.rst
modules/cyber-si-ara/example.rst
modules/akamai/example.rst

.. toctree::
:maxdepth: 2
Expand Down
12 changes: 12 additions & 0 deletions docs/modules/akamai/example.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
Akamai
======

To import this module:

.. code-block:: python
from python3_capsolver.akamai import Akamai
.. autoclass:: python3_capsolver.akamai.Akamai
:members:
14 changes: 14 additions & 0 deletions docs/modules/serializer/info.rst
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,17 @@ To import this module:
.. autopydantic_model:: python3_capsolver.core.serializer.WebsiteDataOptionsSer
:members:
:undoc-members:


.. autopydantic_model:: python3_capsolver.core.serializer.CyberSiAraSer
:members:
:undoc-members:


.. autopydantic_model:: python3_capsolver.core.serializer.AntiAkamaiBMPTaskSer
:members:
:undoc-members:

.. autopydantic_model:: python3_capsolver.core.serializer.AntiAkamaiWebTaskSer
:members:
:undoc-members:
2 changes: 1 addition & 1 deletion docs/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
pallets_sphinx_themes==2.*
myst-parser==2.0.*
autodoc_pydantic==1.9.*
autodoc_pydantic==1.9.0
2 changes: 1 addition & 1 deletion requirements.style.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# codestyle
isort==5.*
black==23.7.0
black==23.9.1
autoflake==2.*
2 changes: 1 addition & 1 deletion src/python3_capsolver/__version__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = "0.7.1"
__version__ = "0.8"
192 changes: 192 additions & 0 deletions src/python3_capsolver/akamai.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,192 @@
from typing import Union

from python3_capsolver.core.base import BaseCaptcha
from python3_capsolver.core.enum import AntiAkamaiTaskEnm, EndpointPostfixEnm
from python3_capsolver.core.serializer import (
PostRequestSer,
CaptchaResponseSer,
AntiAkamaiBMPTaskSer,
AntiAkamaiWebTaskSer,
)


class Akamai(BaseCaptcha):
"""
The class is used to work with Capsolver AntiAkamai methods.
Args:
api_key: Capsolver API key
captcha_type: Captcha type name, like ``AntiAkamaiBMPTask`` and etc.
packageName: Package name of AkamaiBMP mobile APP
version: AKAMAI BMP Version number, default is: 3.2.6 , max support 3.3.1
Examples:
>>> Akamai(api_key="CAI-BA9XXXXXXXXXXXXX2702E010",
... captcha_type="AntiAkamaiBMPTask",
... packageName="de.zalando.iphone",
... country="US",
... deviceId="90F9EAF5-D6E5-4E30-BC8B-B7780AD02600",
... deviceName="iPhone14,2/16.0.2",
... count=10,
... ).captcha_handler()
CaptchaResponseSer(errorId=0,
errorCode=None,
errorDescription=None,
taskId='73bdcd28-6c77-4414-8....',
status=<ResponseStatusEnm.Ready: 'ready'>,
solution={'deviceId': '90F9EAF...'}
)
>>> Akamai(api_key="CAI-BA9XXXXXXXXXXXXX2702E010",
... captcha_type="AntiAkamaiWebTask",
... url="https://www.xxxx.com/nMRH2/aYJ/PQ4b/32/0peDlm/b9f5NJcXf7tiYE/OE9CMGI1/Nzsn/bCVKCnA",
... abck="14164862507BD4......",
... bmsz="4E3C....33",
... userAgent="Mozilla/5.0 (Wi....",
... ).captcha_handler()
CaptchaResponseSer(errorId=0,
errorCode=None,
errorDescription=None,
taskId='73bdcd28-6c77-4414-8....',
status=<ResponseStatusEnm.Ready: 'ready'>,
solution={'sensorData': '2;3159346;4338233...'}
)
>>> Akamai(api_key="CAI-BA9XXXXXXXXXXXXX2702E010",
... captcha_type=AntiAkamaiTaskEnm.AntiAkamaiBMPTask,
... ).captcha_handler()
CaptchaResponseSer(errorId=0,
errorCode=None,
errorDescription=None,
taskId='73bdcd28-6c77-4414-8....',
status=<ResponseStatusEnm.Ready: 'ready'>,
solution={'deviceId': '6DKFOD0...'}
)
>>> Akamai(api_key="CAI-BA9XXXXXXXXXXXXX2702E010",
... captcha_type=AntiAkamaiTaskEnm.AntiAkamaiWebTask,
... url="https://www.xxxx.com/nMRH2/aYJ/PQ4b/32/0peDlm/b9f5NJcXf7tiYE/OE9CMGI1/Nzsn/bCVKCnA",
... ).captcha_handler()
CaptchaResponseSer(errorId=0,
errorCode=None,
errorDescription=None,
taskId='73bdcd28-6c77-4414-8....',
status=<ResponseStatusEnm.Ready: 'ready'>,
solution={'sensorData': '2;3159346;4338233...'}
)
>>> Akamai(api_key="CAI-BA9XXXXXXXXXXXXX2702E010",
... captcha_type=AntiAkamaiTaskEnm.AntiAkamaiBMPTask,
... **{
... "version": "3.2.6",
... "deviceId": "90F9EAF5-D6E5-4E30-BC8B-B7780AD02600",
... "deviceName": "iPhone14,2/16.0.2",
... "count": 10,
... },
... ).captcha_handler()
CaptchaResponseSer(errorId=0,
errorCode=None,
errorDescription=None,
taskId="87f149f4-1c....",
status=<ResponseStatusEnm.Ready: 'ready'>,
solution={'deviceId': '90F9EAF...'}
)
>>> await Akamai(api_key="CAI-BA9650D2B9C2786B21120D512702E010",
... captcha_type="AntiAkamaiBMPTask",
... packageName="de.zalando.iphone",
... country="US",
... deviceId="90F9EAF5-D6E5-4E30-BC8B-B7780AD02600",
... deviceName="iPhone14,2/16.0.2",
... count=10,
... ).aio_captcha_handler()
CaptchaResponseSer(errorId=0,
errorCode=None,
errorDescription=None,
taskId='73bdcd28-6c77-4414-8....',
status=<ResponseStatusEnm.Ready: 'ready'>,
solution={'deviceId': '90F9EAF...'}
)
>>> await Akamai(api_key="CAI-BA9XXXXXXXXXXXXX2702E010",
... captcha_type=AntiAkamaiTaskEnm.AntiAkamaiWebTask,
... url="https://www.xxxx.com/nMRH2/aYJ/PQ4b/32/0peDlm/b9f5NJcXf7tiYE/OE9CMGI1/Nzsn/bCVKCnA",
... ).aio_captcha_handler()
CaptchaResponseSer(errorId=0,
errorCode=None,
errorDescription=None,
taskId='73bdcd28-6c77-4414-8....',
status=<ResponseStatusEnm.Ready: 'ready'>,
solution={'sensorData': '2;3159346;4338233...'}
)
Returns:
CaptchaResponseSer model with full server response
Notes:
https://docs.capsolver.com/guide/antibots/akamaibmp.html
https://docs.capsolver.com/guide/antibots/akamaiweb.html
"""

def __init__(
self,
captcha_type: Union[AntiAkamaiTaskEnm, str],
packageName: str = "de.zalando.iphone",
version: str = "3.2.6",
country: str = "US",
url: str = None,
*args,
**kwargs,
):
super().__init__(*args, **kwargs)
self.__serializer = PostRequestSer
self.__url_postfix = None

if captcha_type == AntiAkamaiTaskEnm.AntiAkamaiBMPTask:
self.task_params = AntiAkamaiBMPTaskSer(**locals()).dict()
self.__url_postfix = EndpointPostfixEnm.AKAMAI_BMP_INVOKE.value
elif captcha_type == AntiAkamaiTaskEnm.AntiAkamaiWebTask:
self.task_params = AntiAkamaiWebTaskSer(**locals()).dict()
self.__url_postfix = EndpointPostfixEnm.AKAMAI_WEB_INVOKE.value
else:
raise ValueError(
f"""Invalid `captcha_type` parameter set for `{self.__class__.__name__}`,
available - {AntiAkamaiTaskEnm.list_values()}"""
)

for key in kwargs:
self.task_params.update({key: kwargs[key]})

def captcha_handler(self) -> CaptchaResponseSer:
"""
Sync solving method
Returns:
CaptchaResponseSer model with full service response
Notes:
Check class docstring for more info
"""
self._prepare_create_task_payload(serializer=self.__serializer, create_params=self.task_params)
return CaptchaResponseSer(
**self._create_task(
url_postfix=self.__url_postfix,
)
)

async def aio_captcha_handler(self) -> CaptchaResponseSer:
"""
Async method for captcha solving
Returns:
CaptchaResponseSer model with full service response
Notes:
Check class docstring for more info
"""
self._prepare_create_task_payload(serializer=self.__serializer, create_params=self.task_params)
return CaptchaResponseSer(
**await self._aio_create_task(
url_postfix=self.__url_postfix,
)
)
7 changes: 7 additions & 0 deletions src/python3_capsolver/core/enum.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ class EndpointPostfixEnm(str, MyEnum):
GET_BALANCE = "getBalance"
CREATE_TASK = "createTask"
GET_TASK_RESULT = "getTaskResult"
AKAMAI_BMP_INVOKE = "/akamaibmp/invoke"
AKAMAI_WEB_INVOKE = "/akamaiweb/invoke"


class ImageToTextTaskTypeEnm(str, MyEnum):
Expand Down Expand Up @@ -110,6 +112,11 @@ class AntiCyberSiAraTaskTypeEnm(str, MyEnum):
AntiCyberSiAraTaskProxyLess = "AntiCyberSiAraTaskProxyLess"


class AntiAkamaiTaskEnm(str, MyEnum):
AntiAkamaiBMPTask = "AntiAkamaiBMPTask"
AntiAkamaiWebTask = "AntiAkamaiWebTask"


class ResponseStatusEnm(str, MyEnum):
"""
Enum store results `status` field variants
Expand Down
10 changes: 10 additions & 0 deletions src/python3_capsolver/core/serializer.py
Original file line number Diff line number Diff line change
Expand Up @@ -132,3 +132,13 @@ class CyberSiAraSer(WebsiteDataOptionsSer):
..., description="You can get MasterUrlId param form `api/CyberSiara/GetCyberSiara` endpoint request"
)
UserAgent: str = Field(..., description="Browser userAgent, you need submit your userAgent")


class AntiAkamaiBMPTaskSer(BaseModel):
packageName: str = Field("de.zalando.iphone", description="Package name of AkamaiBMP mobile APP")
version: str = Field("3.2.6", description="AKAMAI BMP Version number")
country: str = Field("US", description="AKAMAI BMP country")


class AntiAkamaiWebTaskSer(BaseModel):
url: str = Field(..., description="Browser url address")
2 changes: 1 addition & 1 deletion src/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
requests>=2.21.0
aiohttp>=3.7.4
pydantic==1.*
pydantic==1.10.*
tenacity==8.*
4 changes: 2 additions & 2 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@

@pytest.fixture(scope="function")
def delay_func():
time.sleep(0.5)
time.sleep(2)


@pytest.fixture(scope="class")
def delay_class():
time.sleep(2)
time.sleep(5)


@pytest.mark.usefixtures("delay_func")
Expand Down
25 changes: 25 additions & 0 deletions tests/test_akamai.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import pytest

from tests.conftest import BaseTest
from python3_capsolver.akamai import Akamai


class TestAkamaiBase(BaseTest):
AKAMAI_WEB_URL = "https://www.xxxx.com/nMRH2/aYJ/PQ4b/32/0peDlm/b9f5NJcXf7tiYE/OE9CMGI1/Nzsn/bCVKCnA"

def test_captcha_handler_exist(self):
assert "captcha_handler" in Akamai.__dict__.keys()

def test_aio_captcha_handler_exist(self):
assert "aio_captcha_handler" in Akamai.__dict__.keys()

def test_wrong_captcha_type(self):
with pytest.raises(ValueError):
Akamai(
api_key=self.get_random_string(36),
captcha_type="test",
)

def test_no_captcha_type(self):
with pytest.raises(TypeError):
Akamai(api_key=self.get_random_string(36))
4 changes: 2 additions & 2 deletions tests/test_fun_captcha.py
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ async def test_aio_api_key_err(self):
funcaptchaApiJSSubdomain=funcaptchaApiJSSubdomain,
).aio_captcha_handler()
assert result.errorId == 1
assert result.errorCode == "ERROR_KEY_DENIED_ACCESS"
assert result.errorCode in ["ERROR_KEY_DENIED_ACCESS", "ERROR_INVALID_TASK_DATA"]
assert not result.solution

def test_api_key_err(self):
Expand All @@ -187,7 +187,7 @@ def test_api_key_err(self):
funcaptchaApiJSSubdomain=funcaptchaApiJSSubdomain,
).captcha_handler()
assert result.errorId == 1
assert result.errorCode == "ERROR_KEY_DENIED_ACCESS"
assert result.errorCode in ["ERROR_KEY_DENIED_ACCESS", "ERROR_INVALID_TASK_DATA"]
assert not result.solution


Expand Down

0 comments on commit 78f46a1

Please sign in to comment.