Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

0.8 #39

Merged
merged 15 commits into from
Sep 12, 2023
Merged

0.8 #39

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
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
Loading