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
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
MIT License

Copyright (c) 2021 Andrei
Copyright (c) 2025 Andrei

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
3 changes: 2 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@ build:
python3 -m build

upload:
pip3 install twine wheel setuptools build
pip3 install wheel setuptools build
pip3 install twine==6.1.0
twine upload dist/*

doc: install
Expand Down
1 change: 1 addition & 0 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
control,
gee_test,
turnstile,
amazon_waf,
custom_task,
fun_captcha,
recaptcha_v2,
Expand Down
3 changes: 3 additions & 0 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,12 @@ The library is intended for software developers and is used to work with the `An
modules/fun-captcha/example.rst
modules/gee-test/example.rst
modules/custom-task/example.rst
modules/friend/example.rst
modules/prosopo/example.rst
modules/image-to-coordinates/example.rst
modules/recaptcha-v2/example.rst
modules/recaptcha-v3/example.rst
modules/amazon-waf/example.rst

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

To import this module:

.. code-block:: python

from python3_anticaptcha.amazon_waf import AmazonWAF


.. autoclass:: python3_anticaptcha.amazon_waf.AmazonWAF
:members:
6 changes: 2 additions & 4 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ testpaths = [
addopts = "-vv --tb=short --durations=5"

[build-system]
requires = ["setuptools"]
requires = ["setuptools", "wheel"]
build-backend = "setuptools.build_meta"

[project]
Expand Down Expand Up @@ -66,10 +66,8 @@ keywords = [ "captcha",
"amazon_waf",
"friendly-captcha"
]
license = {text = "MIT License"}
license = "MIT"
classifiers = [
"License :: OSI Approved :: MIT License",
"License :: OSI Approved :: Mozilla Public License 2.0 (MPL 2.0)",
"Development Status :: 5 - Production/Stable",
"Programming Language :: Python",
"Programming Language :: Python :: 3",
Expand Down
2 changes: 1 addition & 1 deletion src/python3_anticaptcha/__version__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = "2.1.4"
__version__ = "2.2.0"
158 changes: 158 additions & 0 deletions src/python3_anticaptcha/amazon_waf.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
from typing import Union, Optional

from .core.base import CaptchaParams
from .core.enum import ProxyTypeEnm, CaptchaTypeEnm

__all__ = ("AmazonWAF",)


class AmazonWAF(CaptchaParams):
def __init__(
self,
api_key: str,
captcha_type: Union[CaptchaTypeEnm, str],
websiteURL: str,
websiteKey: str,
iv: str,
context: str,
proxyType: Optional[Union[ProxyTypeEnm, str]] = None,
proxyAddress: Optional[str] = None,
proxyPort: Optional[int] = None,
proxyLogin: Optional[str] = None,
proxyPassword: Optional[str] = None,
userAgent: Optional[str] = None,
sleep_time: Optional[int] = 10,
):
"""
The class is used to work with FunCaptcha.

Args:
api_key: Capsolver API key
captcha_type: Captcha type
websiteURL: Address of a target web page. Can be located anywhere on the web site, even in a member area
websiteKey: Value of key from window.gokuProps object in WAF page source code
iv: Value of iv from window.gokuProps object in WAF page source code
context: Value of context from window.gokuProps object in WAF page source code

proxyType: Type of the proxy
proxyAddress: Proxy IP address IPv4/IPv6. Not allowed to use:
host names instead of IPs,
transparent proxies (where client IP is visible),
proxies from local networks (192.., 10.., 127...)
proxyPort: Proxy port.
proxyLogin: Proxy login.
proxyPassword: Proxy password.
userAgent: Browser UserAgent.
sleep_time: The waiting time between requests to get the result of the Captcha

Examples:
>>> AmazonWAF(api_key="99d7d111a0111dc11184111c8bb111da",
... captcha_type="AmazonTaskProxyless",
... websiteURL="https://efw47fpad9.execute-api.us-east-1.amazonaws.com/latest",
... websiteKey="AQIDAgghr5y45ywZwdADFLWk7XOA==",
... iv="CgAAXFFFFSAAABVk",
... context="qoJYgnKscdqwdqwdqwaormh/dYYK+Y=",
... ).captcha_handler()
{
"errorId": 0,
"errorCode": None,
"errorDescription": None,
"status":"ready",
"solution":{
"token":"0.Qz0.....f1"
},
"cost": 0.002,
"ip": "46.53.249.230",
"createTime": 1679004358,
"endTime": 1679004368,
"solveCount": 0,
"taskId": 396687629
}

>>> await AmazonWAF(api_key="99d7d111a0111dc11184111c8bb111da",
... captcha_type="AmazonTaskProxyless",
... websiteURL="https://efw47fpad9.execute-api.us-east-1.amazonaws.com/latest",
... websiteKey="AQIDAgghr5y45ywZwdADFLWk7XOA==",
... iv="CgAAXFFFFSAAABVk",
... context="qoJYgnKscdqwdqwdqwaormh/dYYK+Y=",
... ).aio_captcha_handler()
{
"errorId": 0,
"errorCode": None,
"errorDescription": None,
"status":"ready",
"solution":{
"token":"0.Qz0.....f1"
},
"cost": 0.002,
"ip": "46.53.249.230",
"createTime": 1679004358,
"endTime": 1679004368,
"solveCount": 0,
"taskId": 396687629
}

>>> AmazonWAF(api_key="99d7d111a0111dc11184111c8bb111da",
... captcha_type="AmazonTaskProxyless",
... websiteURL="https://efw47fpad9.execute-api.us-east-1.amazonaws.com/latest",
... websiteKey="AQIDAgghr5y45ywZwdADFLWk7XOA==",
... iv="CgAAXFFFFSAAABVk",
... context="qoJYgnKscdqwdqwdqwaormh/dYYK+Y=",
... proxyType="http",
... proxyAddress="0.0.0.0",
... proxyPort=9988,
... proxyLogin="proxy_login",
... proxyPassword="proxy_password",
... userAgent="some_real_user_agent",
... ).captcha_handler()
{
"errorId": 0,
"errorCode": None,
"errorDescription": None,
"status":"ready",
"solution":{
"token":"0.Qz0.....f1"
},
"cost": 0.002,
"ip": "46.53.249.230",
"createTime": 1679004358,
"endTime": 1679004368,
"solveCount": 0,
"taskId": 396687629
}

Notes:
https://anti-captcha.com/apidoc/task-types/AmazonTask

https://anti-captcha.com/apidoc/task-types/AmazonTaskProxyless
"""
super().__init__(api_key=api_key, sleep_time=sleep_time)

# validation of the received parameters
if captcha_type == CaptchaTypeEnm.AmazonTask:
self.task_params = dict(
type=captcha_type,
websiteURL=websiteURL,
websitePublicKey=websiteKey,
iv=iv,
context=context,
proxyType=proxyType,
proxyAddress=proxyAddress,
proxyPort=proxyPort,
proxyLogin=proxyLogin,
proxyPassword=proxyPassword,
userAgent=userAgent,
)
elif captcha_type == CaptchaTypeEnm.AmazonTaskProxyless:
self.task_params = dict(
type=captcha_type,
websiteURL=websiteURL,
websitePublicKey=websiteKey,
iv=iv,
context=context,
)
else:
raise ValueError(
f"Invalid `captcha_type` parameter set for `{self.__class__.__name__}`, \
available - {CaptchaTypeEnm.FunCaptchaTaskProxyless.value,CaptchaTypeEnm.FunCaptchaTask.value}"
)
3 changes: 3 additions & 0 deletions src/python3_anticaptcha/core/enum.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@ class CaptchaTypeEnm(str, MyEnum):
# FriendlyCaptcha
ProsopoTask = "ProsopoTask"
ProsopoTaskProxyless = "ProsopoTaskProxyless"
# AmazonWAF
AmazonTask = "AmazonTask"
AmazonTaskProxyless = "AmazonTaskProxyless"
# Custom
AntiGateTask = "AntiGateTask"

Expand Down
76 changes: 76 additions & 0 deletions tests/test_amazon_waf.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import pytest

from tests.conftest import BaseTest
from python3_anticaptcha.core.enum import ProxyTypeEnm, CaptchaTypeEnm
from python3_anticaptcha.amazon_waf import AmazonWAF
from python3_anticaptcha.core.serializer import GetTaskResultResponseSer


class TestAmazonWAF(BaseTest):
websiteURL = "https://efw47fpad9.execute-api.us-east-1.amazonaws.com/latest"
websiteKey = "AQIDAgghr5y45ywZwdADFLWk7XOA=="
iv = "CgAAXFFFFSAAABVk"
_context = "qoJYgnKscdqwdqwdqwaormh/dYYK+Y="

def get_proxy_args(self) -> dict:
proxy_args = super().get_proxy_args()
proxy_args.update({"userAgent": self.get_random_string()})
return proxy_args

def test_sio_success(self):
instance = AmazonWAF(
api_key=self.API_KEY,
websiteURL=self.websiteURL,
websiteKey=self.websiteKey,
iv=self.iv,
context=self._context,
captcha_type=CaptchaTypeEnm.AmazonTaskProxyless,
)
result = instance.captcha_handler()

assert isinstance(result, dict)
ser_result = GetTaskResultResponseSer(**result)
assert ser_result.errorId == 24

async def test_aio_success(self):
instance = AmazonWAF(
api_key=self.API_KEY,
websiteURL=self.websiteURL,
websiteKey=self.websiteKey,
iv=self.iv,
context=self._context,
captcha_type=CaptchaTypeEnm.AmazonTaskProxyless,
)
result = await instance.aio_captcha_handler()

assert isinstance(result, dict)
ser_result = GetTaskResultResponseSer(**result)
assert ser_result.errorId == 24

@pytest.mark.parametrize("proxyType", ProxyTypeEnm)
def test_proxy_args(self, proxyType: ProxyTypeEnm):
proxy_args = self.get_proxy_args()
proxy_args.update({"proxyType": proxyType})

instance = AmazonWAF(
api_key=self.API_KEY,
websiteURL=self.websiteURL,
websiteKey=self.websiteKey,
iv=self.iv,
context=self._context,
captcha_type=CaptchaTypeEnm.AmazonTask,
**proxy_args,
)
for key, value in proxy_args.items():
assert instance.task_params[key] == value

def test_err_captcha_type(self):
with pytest.raises(ValueError):
AmazonWAF(
api_key=self.API_KEY,
websiteURL=self.websiteURL,
websiteKey=self.websiteKey,
iv=self.iv,
context=self._context,
captcha_type=self.get_random_string(length=10),
)