diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 570c103f..f4c61d42 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -4,3 +4,10 @@ updates: directory: "/" # Location of package manifests schedule: interval: "weekly" + + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "daily" + commit-message: + prefix: "[github-actions] " diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 1dd10435..591166d1 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -20,12 +20,12 @@ jobs: strategy: fail-fast: false matrix: - python-version: ["3.7", "3.8", "3.9", "3.10", "3.11"] + python-version: ["3.9", "3.10", "3.11"] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v3 + uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} diff --git a/.github/workflows/install.yml b/.github/workflows/install.yml index 7eebaffe..74a3f8d6 100644 --- a/.github/workflows/install.yml +++ b/.github/workflows/install.yml @@ -20,12 +20,12 @@ jobs: strategy: fail-fast: false matrix: - python-version: ["3.7", "3.8", "3.9", "3.10", "3.11"] + python-version: ["3.9", "3.10", "3.11"] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v3 + uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 1df5ce2b..537ae4db 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -24,12 +24,12 @@ jobs: strategy: fail-fast: false matrix: - python-version: ["3.7", "3.8", "3.9", "3.10", "3.11"] + python-version: ["3.11"] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v3 + uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} diff --git a/.github/workflows/sphinx.yml b/.github/workflows/sphinx.yml index 07662d31..3f131ae4 100644 --- a/.github/workflows/sphinx.yml +++ b/.github/workflows/sphinx.yml @@ -14,8 +14,8 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 - - uses: actions/setup-python@v3 + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 - name: Build docs requirements run: pip install -r docs/requirements.txt diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 0d39b127..3df5408f 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -29,12 +29,12 @@ jobs: strategy: fail-fast: false matrix: - python-version: ["3.7", "3.8", "3.9", "3.10", "3.11"] + python-version: ["3.9", "3.10", "3.11"] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v3 + uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} diff --git a/.python-version b/.python-version new file mode 100644 index 00000000..9ac38041 --- /dev/null +++ b/.python-version @@ -0,0 +1 @@ +3.11.5 diff --git a/Makefile b/Makefile index 20903bb2..e4fbfbea 100644 --- a/Makefile +++ b/Makefile @@ -1,8 +1,8 @@ install: - cd src/ && pip install -e . + cd src/ && pip3 install -e . remove: - pip uninstall python_rucaptcha -y + pip3 uninstall python_rucaptcha -y refactor: black docs/ @@ -24,11 +24,12 @@ lint: isort src/ --check-only upload: - pip install twine + pip3 install twine cd src/ && python setup.py upload tests: install - coverage run --rcfile=.coveragerc -m pytest --verbose --showlocals --pastebin=all tests --disable-warnings && \ + coverage run --rcfile=.coveragerc -m pytest --verbose --showlocals --pastebin=all \ + tests/ --disable-warnings && \ coverage report --precision=3 --sort=cover --skip-empty --show-missing && \ coverage html --precision=3 --skip-empty -d coverage/html/ && \ coverage xml -o coverage/coverage.xml diff --git a/README.md b/README.md index baba5b97..89377ab3 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # python-rucaptcha -![](https://github.com/AndreiDrang/python-rucaptcha/blob/master/files/RuCaptcha.png) +![](files/RuCaptchaHigh.png) Capsolver's Banner @@ -12,7 +12,7 @@ At the lowest price on the market, you may receive a variety of solutions, inclu [![PyPI version](https://badge.fury.io/py/python-rucaptcha.svg)](https://badge.fury.io/py/python-rucaptcha) [![Python versions](https://img.shields.io/pypi/pyversions/python-rucaptcha.svg?logo=python&logoColor=FBE072)](https://badge.fury.io/py/python-rucaptcha) -[![Downloads](https://pepy.tech/badge/python-rucaptcha/month)](https://pepy.tech/project/python-rucaptcha) +[![Downloads](https://static.pepy.tech/badge/python-rucaptcha/month)](https://pepy.tech/project/python-rucaptcha) [![Maintainability](https://api.codeclimate.com/v1/badges/aec93bb04a277cf0dde9/maintainability)](https://codeclimate.com/github/AndreiDrang/python-rucaptcha/maintainability) [![Codacy Badge](https://app.codacy.com/project/badge/Grade/b4087362bd024b088b358b3e10e7a62f)](https://www.codacy.com/gh/AndreiDrang/python-rucaptcha/dashboard?utm_source=github.com&utm_medium=referral&utm_content=AndreiDrang/python-rucaptcha&utm_campaign=Badge_Grade) @@ -63,12 +63,14 @@ Is described in the [documentation-website](https://andreidrang.github.io/python ### Changelog +For full changelog info check - [Releases page](https://github.com/AndreiDrang/python-rucaptcha/releases). + +- v.6.0 - Library refactoring. Stop using `pydantic`, start using `msgspec`. Move to API v2. Drop Python 3.8 support. More details at [Releases page](https://github.com/AndreiDrang/python-rucaptcha/releases). - v.5.3 - Added support for [Death By Captcha](https://www.deathbycaptcha.com?refid=1237267242) and other services by changing `service_type` and `url_request` \ `url_response` parameters. - v.5.2 - Added Audio captcha method. - v.5.1 - Check [releases page](https://github.com/AndreiDrang/python-rucaptcha/releases). - v.5.0 - Added AmazonWAF captcha method. - v.4.2 - Added [Yandex Smart Captcha](https://rucaptcha.com/api-rucaptcha#yandex). -- v.4.0 - Rework classes and methods. Adding `TikTok` captcha. Adding inheritance and serializers. The `Callback server` is deprecated. ### Get API Key to work with the library 1. On the page - https://rucaptcha.com/enterpage diff --git a/docs/_static/Captcha300x.png b/docs/_static/Captcha300x.png deleted file mode 100644 index 8c9c1e2f..00000000 Binary files a/docs/_static/Captcha300x.png and /dev/null differ diff --git a/docs/_static/CaptchaESm.png b/docs/_static/CaptchaESm.png deleted file mode 100644 index b8661b8e..00000000 Binary files a/docs/_static/CaptchaESm.png and /dev/null differ diff --git a/docs/_static/CaptchaSm.png b/docs/_static/CaptchaSm.png deleted file mode 100644 index d2384acd..00000000 Binary files a/docs/_static/CaptchaSm.png and /dev/null differ diff --git a/docs/_static/RuCaptchaMedium.png b/docs/_static/RuCaptchaMedium.png new file mode 100644 index 00000000..fbedef3b Binary files /dev/null and b/docs/_static/RuCaptchaMedium.png differ diff --git a/docs/conf.py b/docs/conf.py index a5d171d9..11afbdfc 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -16,9 +16,8 @@ key_captcha, text_captcha, image_captcha, + lemin_captcha, rotate_captcha, - yandex_smart_captcha, - lemin_cropped_captcha, ) from python_rucaptcha.__version__ import __version__ @@ -44,8 +43,8 @@ html_theme = "jinja" html_theme_options = {"index_sidebar_logo": False} html_static_path = ["_static"] -html_favicon = "_static/CaptchaESm.png" -html_logo = "_static/CaptchaSm.png" +html_favicon = "_static/RuCaptchaMedium.png" +html_logo = "_static/RuCaptchaMedium.png" html_title = f"python-rucaptcha ({__version__})" html_show_sourcelink = False @@ -61,6 +60,7 @@ "DeathByCaptcha", "https://deathbycaptcha.com?refid=1237267242", ), + ProjectLink("RedPandaDev group", "https://red-panda-dev.xyz/blog/"), ] } html_sidebars = { diff --git a/docs/index.rst b/docs/index.rst index f9af11b5..d8630ede 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -2,7 +2,7 @@ python-rucaptcha ================ -.. image:: _static/Captcha300x.png +.. image:: _static/RuCaptchaMedium.png :align: center Python3 library for `RuCaptcha `_ and `2Captcha `_ service API. @@ -11,6 +11,8 @@ The library is intended for software developers and is used to work with the `Ru Support of the service `Death By Captcha `_ is integrated into this library, more information in the library documentation or in the `service docs `_. +Check our other projects here - `RedPandaDev group `_. For example - `Torrents Tracker bot `_ for Telegram + .. toctree:: :maxdepth: 1 :caption: Start here: @@ -36,7 +38,6 @@ Support of the service `Death By Captcha Capsolver's Banner diff --git a/docs/modules/other-libs/info.md b/docs/modules/other-libs/info.md index 4ee60708..b8f53b47 100644 --- a/docs/modules/other-libs/info.md +++ b/docs/modules/other-libs/info.md @@ -4,3 +4,6 @@ 1. [RuCaptcha / 2Captcha](https://github.com/AndreiDrang/python-rucaptcha) 2. [AntiCaptcha](https://github.com/AndreiDrang/python3-anticaptcha) 3. [Capsolver](https://github.com/AndreiDrang/python3-captchaai) + +Our other projects: +- [RedPandaDev group](https://red-panda-dev.xyz/blog/) diff --git a/docs/modules/serializer/info.rst b/docs/modules/serializer/info.rst index 578a5c55..f7346317 100644 --- a/docs/modules/serializer/info.rst +++ b/docs/modules/serializer/info.rst @@ -8,32 +8,6 @@ To import this module: from python_rucaptcha.core import serializer -.. autopydantic_model:: python_rucaptcha.core.serializer.ResponseSer +.. autoclass:: python_rucaptcha.core.serializer.GetTaskResultResponseSer :members: :undoc-members: - - -.. autopydantic_model:: python_rucaptcha.core.serializer.PostRequestSer - :members: - :undoc-members: - - -.. autopydantic_model:: python_rucaptcha.core.serializer.GetRequestSer - :members: - :undoc-members: - - -.. autopydantic_model:: python_rucaptcha.core.serializer.CaptchaOptionsSer - :members: - :undoc-members: - - -.. autopydantic_model:: python_rucaptcha.core.serializer.ServicePostResponseSer - :members: - :undoc-members: - - -.. autopydantic_model:: python_rucaptcha.core.serializer.ServiceGetResponseSer - :members: - :undoc-members: - diff --git a/docs/modules/yandex/example.rst b/docs/modules/yandex/example.rst deleted file mode 100644 index f95aafe5..00000000 --- a/docs/modules/yandex/example.rst +++ /dev/null @@ -1,12 +0,0 @@ -YandexSmartCaptcha -================== - -To import this module: - -.. code-block:: python - - from python_rucaptcha.yandex_smart_captcha import YandexSmartCaptcha - - -.. autoclass:: python_rucaptcha.yandex_smart_captcha.YandexSmartCaptcha - :members: \ No newline at end of file diff --git a/docs/requirements.txt b/docs/requirements.txt index 64a06013..0a305ba3 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -1,3 +1,6 @@ -pallets_sphinx_themes==2.* -myst-parser==1.0.* -autodoc_pydantic==1.8.* +sphinx==7.2.6 +pallets_sphinx_themes==2.1.1 +myst-parser==2.0.0 +autodoc_pydantic==2.0.1 +pydantic==2.4.2 +pydantic-settings==2.0.3 diff --git a/files/RuCaptcha.png b/files/RuCaptcha.png deleted file mode 100644 index d2384acd..00000000 Binary files a/files/RuCaptcha.png and /dev/null differ diff --git a/files/RuCaptchaHigh.png b/files/RuCaptchaHigh.png new file mode 100644 index 00000000..2f5aba72 Binary files /dev/null and b/files/RuCaptchaHigh.png differ diff --git a/files/RuCaptchaLow.png b/files/RuCaptchaLow.png deleted file mode 100644 index 96df96be..00000000 Binary files a/files/RuCaptchaLow.png and /dev/null differ diff --git a/files/drawing.svg b/files/drawing.svg new file mode 100644 index 00000000..cabe66ec --- /dev/null +++ b/files/drawing.svg @@ -0,0 +1,861 @@ + + + +RuCaptcha2Captcha diff --git a/pyproject.toml b/pyproject.toml index 9ac9eea7..41eab815 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.black] line-length = 120 -target-version = ['py310'] +target-version = ['py311'] exclude = ''' /( \.git diff --git a/requirements.style.txt b/requirements.style.txt index ceb18cb9..48f83b59 100644 --- a/requirements.style.txt +++ b/requirements.style.txt @@ -1,4 +1,4 @@ # codestyle isort==5.* -black==23.3.0 +black==23.10.0 autoflake==2.* diff --git a/src/examples/captcha_control_example.py b/src/examples/captcha_control_example.py deleted file mode 100644 index 25c7f76c..00000000 --- a/src/examples/captcha_control_example.py +++ /dev/null @@ -1,66 +0,0 @@ -import asyncio - -from python_rucaptcha.control import Control -from python_rucaptcha.core.enums import ControlEnm - -# Rucaptcha API Key from your account -RUCAPTCHA_KEY = "ad911111111111ca81755768608fa758570" - -# Balance control - -control_captcha = Control(rucaptcha_key=RUCAPTCHA_KEY, action=ControlEnm.GETBALANCE.value) -result = control_captcha.additional_methods() - -print(result) - -# Report control - -control_captcha = Control(rucaptcha_key=RUCAPTCHA_KEY, action=ControlEnm.REPORTBAD.value) -result = control_captcha.report(id="-1") - -print(result) - -control_captcha = Control(rucaptcha_key=RUCAPTCHA_KEY, action=ControlEnm.REPORTGOOD.value) -result = control_captcha.report(id="-1") - -print(result) - -# Pingback control - -control_captcha = Control(rucaptcha_key=RUCAPTCHA_KEY, action=ControlEnm.DEL_PINGBACK.value) -result = control_captcha.domain_control(addr="all") - -print(result) - -# ASYNC - - -async def run(): - # Balance control - - control_captcha = Control(rucaptcha_key=RUCAPTCHA_KEY, action=ControlEnm.GETBALANCE.value) - result = await control_captcha.aio_additional_methods() - - print(result) - - # Report control - - control_captcha = Control(rucaptcha_key=RUCAPTCHA_KEY, action=ControlEnm.REPORTBAD.value) - result = await control_captcha.aio_report(id="-1") - - print(result) - - control_captcha = Control(rucaptcha_key=RUCAPTCHA_KEY, action=ControlEnm.REPORTGOOD.value) - result = await control_captcha.aio_report(id="-1") - - print(result) - - # Pingback control - - control_captcha = Control(rucaptcha_key=RUCAPTCHA_KEY, action=ControlEnm.DEL_PINGBACK.value) - result = await control_captcha.aio_domain_control(addr="all") - - print(result) - - -asyncio.run(run()) diff --git a/src/examples/capy_captcha_example.py b/src/examples/capy_captcha_example.py deleted file mode 100644 index 694a38a9..00000000 --- a/src/examples/capy_captcha_example.py +++ /dev/null @@ -1,42 +0,0 @@ -import asyncio - -from python_rucaptcha.core.enums import CapyPuzzleEnm -from python_rucaptcha.capy_puzzle import CapyPuzzle - -# Rucaptcha API Key from your account -RUCAPTCHA_KEY = "ad911111111111ca81755768608fa758570" - -captchakey = "PUZZLE_Cme4hZLjuZRMYC3uh14C52D3uNms5w" -pageurl = "https://www.capy.me/account/register/" -api_server = "https://jp.api.capy.me/" -versions = ["puzzle", "avatar"] - -capy = CapyPuzzle( - rucaptcha_key=RUCAPTCHA_KEY, - captchakey=captchakey, - pageurl=pageurl, - method=CapyPuzzleEnm.CAPY.value, - api_server=api_server, - version=versions[0], -) -result = capy.captcha_handler() - -print(result) - - -async def run(): - try: - result = await CapyPuzzle( - rucaptcha_key=RUCAPTCHA_KEY, - captchakey=captchakey, - pageurl=pageurl, - method=CapyPuzzleEnm.CAPY.value, - api_server=api_server, - version=versions[0], - ).aio_captcha_handler() - print(result) - except Exception as err: - print(err) - - -asyncio.run(run()) diff --git a/src/examples/funcaptcha_example.py b/src/examples/funcaptcha_example.py deleted file mode 100644 index 1ad3fb40..00000000 --- a/src/examples/funcaptcha_example.py +++ /dev/null @@ -1,35 +0,0 @@ -import asyncio - -from python_rucaptcha.core.enums import FunCaptchaEnm -from python_rucaptcha.fun_captcha import FunCaptcha - -# Rucaptcha API Key from your account -RUCAPTCHA_KEY = "ad9053f111111111111111fa758570" - - -publickey = "69A21A01-CC7B-B9C6-1111-E7FA06677FFC" -pageurl = "https://api.funcaptcha.com/fc/api/nojs/" -surl = "https://client-api.arkoselabs.com" - -fun_captcha = FunCaptcha( - rucaptcha_key=RUCAPTCHA_KEY, pageurl=pageurl, publickey=publickey, surl=surl, method=FunCaptchaEnm.FUNCAPTCHA.value -) -result = fun_captcha.captcha_handler() -print(result) - - -async def run(): - try: - result = await FunCaptcha( - rucaptcha_key=RUCAPTCHA_KEY, - pageurl=pageurl, - publickey=publickey, - surl=surl, - method=FunCaptchaEnm.FUNCAPTCHA.value, - ).aio_captcha_handler() - print(result) - except Exception as err: - print(err) - - -asyncio.run(run()) diff --git a/src/examples/geetest_example.py b/src/examples/geetest_example.py deleted file mode 100644 index d0ed4643..00000000 --- a/src/examples/geetest_example.py +++ /dev/null @@ -1,68 +0,0 @@ -import asyncio - -import requests - -from python_rucaptcha.gee_test import GeeTest -from python_rucaptcha.core.enums import GeetestEnm - -# Rucaptcha API Key from your account -RUCAPTCHA_KEY = "ad9053f31111a8171111111111a758570" - -""" -Geetest example -""" - -resp = requests.get("https://www.geetest.com/demo/gt/register-enFullpage-official") -resp_data = resp.json() - -gt = GeeTest( - rucaptcha_key=RUCAPTCHA_KEY, - gt=resp_data["gt"], - method=GeetestEnm.GEETEST.value, - pageurl="https://www.site.com/page/", - api_server="api-na.geetest.com", -) - -print(gt.captcha_handler(challenge=resp_data["challenge"])) - - -async def run(): - gt = GeeTest( - rucaptcha_key=RUCAPTCHA_KEY, - gt="f1ab2cdefa3456789012345b6c78d90e", - method=GeetestEnm.GEETEST.value, - pageurl="https://www.site.com/page/", - api_server="api-na.geetest.com", - ) - result = await gt.aio_captcha_handler(challenge="12345678abc90123d45678ef90123a456b") - print(result) - - -asyncio.run(run()) - -""" -Geetest 4 example -""" - -gt = GeeTest( - rucaptcha_key=RUCAPTCHA_KEY, - method=GeetestEnm.GEETEST_V4.value, - pageurl="https://rucaptcha.com/demo/geetest-v4", - captcha_id="e392e1d7fd421dc63325744d5a2b9c73", -) - -print(gt.captcha_handler()) - - -async def run(): - gt = GeeTest( - rucaptcha_key=RUCAPTCHA_KEY, - method=GeetestEnm.GEETEST_V4.value, - pageurl="https://rucaptcha.com/demo/geetest-v4", - captcha_id="e392e1d7fd421dc63325744d5a2b9c73", - ) - result = await gt.aio_captcha_handler() - print(result) - - -asyncio.run(run()) diff --git a/src/examples/hcaptcha_example.py b/src/examples/hcaptcha_example.py deleted file mode 100644 index b9c6b5b1..00000000 --- a/src/examples/hcaptcha_example.py +++ /dev/null @@ -1,30 +0,0 @@ -import asyncio - -from python_rucaptcha.hcaptcha import HCaptcha -from python_rucaptcha.core.enums import HCaptchaEnm - -# Rucaptcha API Key from your account -RUCAPTCHA_KEY = "ad911111111111ca81755768608fa758570" - -sitekey = "3ceb8624-1970-4e6b-91d5-70317b70b651" -pageurl = "https://rucaptcha.com/demo/hcaptcha" - -lemin_captcha = HCaptcha( - rucaptcha_key=RUCAPTCHA_KEY, sitekey=sitekey, pageurl=pageurl, method=HCaptchaEnm.HCAPTCHA.value -) -result = lemin_captcha.captcha_handler() - -print(result) - - -async def run(): - try: - lemin_captcha = await HCaptcha( - rucaptcha_key=RUCAPTCHA_KEY, sitekey=sitekey, pageurl=pageurl, method=HCaptchaEnm.HCAPTCHA.value - ).aio_captcha_handler() - print(lemin_captcha) - except Exception as err: - print(err) - - -asyncio.run(run()) diff --git a/src/examples/image_captcha_example.py b/src/examples/image_captcha_example.py deleted file mode 100644 index e8927789..00000000 --- a/src/examples/image_captcha_example.py +++ /dev/null @@ -1,33 +0,0 @@ -import asyncio - -from python_rucaptcha.image_captcha import ImageCaptcha - -# Rucaptcha API Key from your account -RUCAPTCHA_KEY = "ad911111111111ca81755768608fa758570" - -captcha_file = "src/examples/088636.png" -captcha_url = "https://rucaptcha.com/dist/web/99581b9d446a509a0a01954438a5e36a.jpg" - - -image_captcha = ImageCaptcha(rucaptcha_key=RUCAPTCHA_KEY) -result = image_captcha.captcha_handler(captcha_file=captcha_file) - -print(result) - -image_captcha = ImageCaptcha(rucaptcha_key=RUCAPTCHA_KEY) -result = image_captcha.captcha_handler(captcha_link=captcha_url) - -print(result) - - -async def run(): - image_captcha = ImageCaptcha(rucaptcha_key=RUCAPTCHA_KEY) - result = await image_captcha.aio_captcha_handler(captcha_file=captcha_file) - print(result) - - image_captcha = ImageCaptcha(rucaptcha_key=RUCAPTCHA_KEY) - result = await image_captcha.aio_captcha_handler(captcha_link=captcha_url) - print(result) - - -asyncio.run(run()) diff --git a/src/examples/key_captcha_example.py b/src/examples/key_captcha_example.py deleted file mode 100644 index 1d14efb1..00000000 --- a/src/examples/key_captcha_example.py +++ /dev/null @@ -1,45 +0,0 @@ -import asyncio - -from python_rucaptcha.core.enums import KeyCaptchaEnm -from python_rucaptcha.key_captcha import KeyCaptcha - -# Rucaptcha API Key from your account -RUCAPTCHA_KEY = "ad9053f111111111111111fa758570" - -s_s_c_user_id = "184015" -s_s_c_session_id = "0917788cad24ad3a69813c4fcd556061" -s_s_c_web_server_sign = "02f7f9669f1269595c4c69bcd4a3c52e" -s_s_c_web_server_sign2 = "d888700f6f324ec0f32b44c32c50bde1" -pageurl = "https://rucaptcha.com/demo/keycaptcha" - -key_captcha = KeyCaptcha( - rucaptcha_key=RUCAPTCHA_KEY, - pageurl=pageurl, - s_s_c_user_id=s_s_c_user_id, - s_s_c_session_id=s_s_c_session_id, - s_s_c_web_server_sign=s_s_c_web_server_sign, - s_s_c_web_server_sign2=s_s_c_web_server_sign2, - method=KeyCaptchaEnm.KEYCAPTCHA.value, -) -result = key_captcha.captcha_handler() - -print(result) - - -async def run(): - try: - key_captcha = await KeyCaptcha( - rucaptcha_key=RUCAPTCHA_KEY, - pageurl=pageurl, - s_s_c_user_id=s_s_c_user_id, - s_s_c_session_id=s_s_c_session_id, - s_s_c_web_server_sign=s_s_c_web_server_sign, - s_s_c_web_server_sign2=s_s_c_web_server_sign2, - method=KeyCaptchaEnm.KEYCAPTCHA.value, - ).aio_captcha_handler() - print(key_captcha) - except Exception as err: - print(err) - - -asyncio.run(run()) diff --git a/src/examples/lemin_example.py b/src/examples/lemin_example.py deleted file mode 100644 index 191291ab..00000000 --- a/src/examples/lemin_example.py +++ /dev/null @@ -1,42 +0,0 @@ -import asyncio - -from python_rucaptcha.core.enums import LeminCroppedCaptchaEnm -from python_rucaptcha.lemin_cropped_captcha import LeminCroppedCaptcha - -# Rucaptcha API Key from your account -RUCAPTCHA_KEY = "ad9053f111111111111111fa758570" - -pageurl = "https://dashboard.leminnow.com/auth/signup" -api_server = "api.leminnow.com" -div_id = "lemin-cropped-captcha" -captcha_id = "CROPPED_099216d_8ba061383fa24ef498115023aa7189d4" - -lemin_captcha = LeminCroppedCaptcha( - rucaptcha_key=RUCAPTCHA_KEY, - pageurl=pageurl, - captcha_id=captcha_id, - div_id=div_id, - method=LeminCroppedCaptchaEnm.LEMIN.value, - api_server=api_server, -) -result = lemin_captcha.captcha_handler() - -print(result) - - -async def run(): - try: - lemin_captcha = await LeminCroppedCaptcha( - rucaptcha_key=RUCAPTCHA_KEY, - pageurl=pageurl, - captcha_id=captcha_id, - div_id=div_id, - method=LeminCroppedCaptchaEnm.LEMIN.value, - api_server=api_server, - ).aio_captcha_handler() - print(lemin_captcha) - except Exception as err: - print(err) - - -asyncio.run(run()) diff --git a/src/examples/recaptcha_example.py b/src/examples/recaptcha_example.py deleted file mode 100644 index 811646df..00000000 --- a/src/examples/recaptcha_example.py +++ /dev/null @@ -1,110 +0,0 @@ -import asyncio - -from python_rucaptcha.core.enums import ReCaptchaEnm -from python_rucaptcha.re_captcha import ReCaptcha - -# Rucaptcha API Key from your account -RUCAPTCHA_KEY = "ad9053f111111111111111fa758570" - -# ReCaptchaV3 - -googlekey = "6LeIxboZAAAAAFQy7d8GPzgRZu2bV0GwKS8ue_cH" -pageurl = "https://rucaptcha.com/demo/recaptcha-v2" - -re_captcha = ReCaptcha( - rucaptcha_key=RUCAPTCHA_KEY, - pageurl=pageurl, - googlekey=googlekey, - method=ReCaptchaEnm.USER_RECAPTCHA.value, -) -result = re_captcha.captcha_handler() - -print(result) - - -async def run(): - try: - re_captcha = await ReCaptcha( - rucaptcha_key=RUCAPTCHA_KEY, - pageurl=pageurl, - googlekey=googlekey, - method=ReCaptchaEnm.USER_RECAPTCHA.value, - ).aio_captcha_handler() - print(re_captcha) - except Exception as err: - print(err) - - -asyncio.run(run()) - -# ReCaptchaV3 invisible -googlekey = "6LfDxboZAAAAAD6GHukjvUy6lszoeG3H4nQW57b6" -pageurl = "https://rucaptcha.com/demo/recaptcha-v2-invisible" - -re_captcha = ReCaptcha( - rucaptcha_key=RUCAPTCHA_KEY, - pageurl=pageurl, - googlekey=googlekey, - method=ReCaptchaEnm.USER_RECAPTCHA.value, - invisible=1, -) -result = re_captcha.captcha_handler() - -print(result) - - -async def run(): - try: - re_captcha = await ReCaptcha( - rucaptcha_key=RUCAPTCHA_KEY, - pageurl=pageurl, - googlekey=googlekey, - method=ReCaptchaEnm.USER_RECAPTCHA.value, - invisible=1, - ).aio_captcha_handler() - print(re_captcha) - except Exception as err: - print(err) - - -asyncio.run(run()) - -# ReCaptchaV3 - -googlekey = "6LfB5_IbAAAAAMCtsjEHEHKqcB9iQocwwxTiihJu" -pageurl = "https://rucaptcha.com/demo/recaptcha-v3" -version = "v3" -action = "demo_action" -score = 0.1 - -re_captcha = ReCaptcha( - rucaptcha_key=RUCAPTCHA_KEY, - pageurl=pageurl, - googlekey=googlekey, - method=ReCaptchaEnm.USER_RECAPTCHA.value, - version=version, - action=action, - score=score, -) -result = re_captcha.captcha_handler() - -print(result) - - -async def run(): - try: - re_captcha = await aioReCaptcha( - rucaptcha_key=RUCAPTCHA_KEY, - pageurl=pageurl, - googlekey=googlekey, - method=ReCaptchaEnm.USER_RECAPTCHA.value, - version=version, - action=action, - score=score, - ).captcha_handler() - print(re_captcha) - except Exception as err: - print(err) - - -asyncio.run(run()) diff --git a/src/examples/rotate_example.py b/src/examples/rotate_example.py deleted file mode 100644 index e071a777..00000000 --- a/src/examples/rotate_example.py +++ /dev/null @@ -1,40 +0,0 @@ -import asyncio - -from python_rucaptcha.core.enums import RotateCaptchaEnm -from python_rucaptcha.rotate_captcha import RotateCaptcha - -# Rucaptcha API Key from your account -RUCAPTCHA_KEY = "ad911111111111ca81755768608fa758570" - -captcha_url = "https://rucaptcha.com/dist/web/b771cc7c5eb0c1a811fcb91d54e4443a.png" -captcha_path = "src/examples/rotate/rotate_ex.png" - -rotate_captcha = RotateCaptcha(rucaptcha_key=RUCAPTCHA_KEY, method=RotateCaptchaEnm.ROTATECAPTCHA.value) -# file URL -result = rotate_captcha.captcha_handler(captcha_link=captcha_url) - -print(result) - -# file path -result = rotate_captcha.captcha_handler(captcha_link=captcha_path) - -print(result) - -# ASYNC example - -rotate_captcha = RotateCaptcha(rucaptcha_key=RUCAPTCHA_KEY, method=RotateCaptchaEnm.ROTATECAPTCHA.value) - - -async def run(): - # file URL - result = await rotate_captcha.aio_captcha_handler(captcha_link=captcha_url) - - print(result) - - # file path - result = await rotate_captcha.aio_captcha_handler(captcha_link=captcha_path) - - print(result) - - -asyncio.run(run()) diff --git a/src/examples/text_captcha_example.py b/src/examples/text_captcha_example.py deleted file mode 100644 index 72951d7c..00000000 --- a/src/examples/text_captcha_example.py +++ /dev/null @@ -1,27 +0,0 @@ -import asyncio - -from python_rucaptcha.text_captcha import TextCaptcha - -# Rucaptcha API Key from your account -RUCAPTCHA_KEY = "ad911111111111ca81755768608fa758570" - -# Balance control - -text_captcha = TextCaptcha(rucaptcha_key=RUCAPTCHA_KEY, language=1) -result = text_captcha.captcha_handler(textcaptcha="Какой сегодня день недели?") - -print(result) - -# ASYNC - - -async def run(): - # Balance control - - text_captcha = TextCaptcha(rucaptcha_key=RUCAPTCHA_KEY, language=1) - result = await text_captcha.aio_captcha_handler(textcaptcha="Какой сегодня день недели?") - - print(result) - - -asyncio.run(run()) diff --git a/src/examples/tiktok_example.py b/src/examples/tiktok_example.py deleted file mode 100644 index 71775a4b..00000000 --- a/src/examples/tiktok_example.py +++ /dev/null @@ -1,46 +0,0 @@ -import asyncio - -from python_rucaptcha.core.enums import TikTokCaptchaEnm -from python_rucaptcha.TikTokCaptcha import TikTokCaptcha, aioTikTokCaptcha - -# Rucaptcha API Key from your account -RUCAPTCHA_KEY = "ad9053f111111111111111fa758570" - -pageurl = "https://www.tiktok.com/login/phone-or-email/email" -aid = "1459" -host = "https://www-useast1a.tiktok.com" -cookies = """tt_csrf_token=8TwpFXMK-xelhfHWNk3vCmOMS_IywmgR76J0; _abck=8C88FA5F886F14E362F71367E51C4A9E~-1~YAAQjHcRJX90XWqCAQAA741ldQgF9RvxGZfIEjhEFlVUSExtmO4pX+v3KcL4MDHYTdUnHP5y+auSOIIqFVMAhfKhu0OglashmiyFuGaRCbjoAKcSq18ov43zc4xIGnOIh2njJYLO8XTTK4NAUPzQsv90nNTiC4sJ8J28WJcD8rWiJohPmtVi++J2hkWuNrq4kfVHifiw0a6J11rPUgzoY0sYId9L3b7bEGlYidstBEVkxsdIakysU7WPRPQuXQ5ORX1y9VRI1/S8SRJCPT8hsw5VGnA3ZTWoos+U2QNe6jOmh+r2lVGQp26d1NuK4j4KeexEGwwIRC3NbMPnoM7svr7Ah5/ZgTbRdqrfr0TxYNtD+BQJ/BZvEtHQ0g==~-1~-1~-1; ak_bmsc=0C59B98852D34B6024F09565AEF3DABF~000000000000000000000000000000~YAAQjHcRJYB0XWqCAQAA741ldRAyqwRUurqvl1ooYUAfu4RlKyAekfk9EdU+PnOOEzfrYTH4vBiM5Tyu53PXzOFxSv+6Mmr/eS525r8YKkC4OlBSXNEKp49lcOeEir0EZc5FDSa1GsdGTOeqds7kEtGeAoGYOfbaFqebrqcgXIFm6bruPiaQSIa71ibE0RWEylGZUqEm9XidFgHi7owbbDfnFIHjAkY9OIBXtCyysN6f2LnjA77U6Iz8Vc+ZnnCy7EpU27zBp9g8gHc6XlsWgVZczCkI2sAyvLNyhNdNvr66DFXQGPooUVFt1eu7Wr84hyeqkVIZ/e6JeO7eeWD3m3BJdhSLFH9cG8Inu+ucssezA0HGBWRLLsuvtQcouMbyiC0/QMhAfy2ZEw==; bm_sz=2D2B267FF82108C34A71921FDD3E4210~YAAQjHcRJYJ0XWqCAQAA741ldRA3VZyY/6SSndh905A0t2BxLX6h2sT3tz6/c3OetEbNcLssuaKjLmUUBjCsMqknZi/wN8Ak90SsKwDcOxrRrVIbsiG1mvfU2XAkrCe+l9iBIi5PdoSje6KzSXfW975Ozpz6dADDiT+KRHaQV4S/HdmjZf4U8AH0JzZe2LvkB1Wuq/HOUVsP7HVY37MPf9RvRjCKvXG8JO5lZ6e3AZtn+Gb8CITDkOQb9Sf1HlFYFMt3PiwG6Rs1L7jiSaDIfqTUJcId0ho038whNTw4e0UPmLs=~4474177~3753529; __tea_cache_tokens_1988={"_type_":"default","user_unique_id":"7128902427751990789","timestamp":1659826966712}; ttwid=1|oK5Qviu6-AtiV6tRgdrXlMWI53OUuO9saqvbF-oeiK8|1659826966|21b12ceb761e86e9047915dc0ac9408df142065490e46ef5d28c92ba67c7593e; msToken=u4oKalLxmidukiJRtA0mRHvZtHc3xEbPiTstK6IsUUF_a1I4N94cB6OComtfBmmIdabLxfLi_eVSRGGW3_k3x2KlKqIp3XG04NEfrTyOl9URRszHOpX3; msToken=u4oKalLxmidukiJRtA0mRHvZtHc3xEbPiTstK6IsUUF_a1I4N94cB6OComtfBmmIdabLxfLi_eVSRGGW3_k3x2KlKqIp3XG04NEfrTyOl9URRszHOpX3""" - - -tiktok_captcha = TikTokCaptcha( - rucaptcha_key=RUCAPTCHA_KEY, - method=TikTokCaptchaEnm.TIKTOK.value, - pageurl=pageurl, - aid=aid, - host=host, - cookies=cookies, -) -result = tiktok_captcha.captcha_handler() - -print(result) - -# ASYNC - - -async def run(): - # Balance control - - tiktok_captcha = aioTikTokCaptcha( - rucaptcha_key=RUCAPTCHA_KEY, - method=TikTokCaptchaEnm.TIKTOK.value, - pageurl=pageurl, - aid=aid, - host=host, - cookies=cookies, - ) - result = await tiktok_captcha.captcha_handler() - - print(result) - - -asyncio.run(run()) diff --git a/src/examples/yandex_smart_example.py b/src/examples/yandex_smart_example.py deleted file mode 100644 index d2775032..00000000 --- a/src/examples/yandex_smart_example.py +++ /dev/null @@ -1,38 +0,0 @@ -import asyncio - -from python_rucaptcha.core.enums import YandexSmartCaptchaEnm -from python_rucaptcha.yandex_smart_captcha import YandexSmartCaptcha - -# Rucaptcha API Key from your account -RUCAPTCHA_KEY = "ad9053f111111111111111fa758570" - -# YandexSmartCaptcha - -sitekey = "FEXfAbHQsToo97VidNVk3j4dC74nGW1DgdxjtNB9" -pageurl = "https://captcha-api.yandex.ru/demo" - -ya_captcha = YandexSmartCaptcha( - rucaptcha_key=RUCAPTCHA_KEY, - pageurl=pageurl, - sitekey=sitekey, - method=YandexSmartCaptchaEnm.YANDEX.value, -) -result = ya_captcha.captcha_handler() - -print(result) - - -async def run(): - try: - ya_captcha = await YandexSmartCaptcha( - rucaptcha_key=RUCAPTCHA_KEY, - pageurl=pageurl, - sitekey=sitekey, - method=YandexSmartCaptchaEnm.YANDEX.value, - ).aio_captcha_handler() - print(ya_captcha) - except Exception as err: - print(err) - - -asyncio.run(run()) diff --git a/src/python_rucaptcha/SocketAPI.py b/src/python_rucaptcha/SocketAPI.py deleted file mode 100644 index 87618784..00000000 --- a/src/python_rucaptcha/SocketAPI.py +++ /dev/null @@ -1,104 +0,0 @@ -''' -class WebSocketRuCaptcha(BaseCaptcha): - def __init__(self, allSessions: bool = False, suppressSuccess: bool = True): - """ - Method setup WebSocket connection data - :param allSessions: `True` if u need send the results of solving captchas to all open sessions. - `False` if u will wait captcha result in current session. - :param suppressSuccess: `False` if u need intermediate info about your task in RuCaptcha system. - `True` if u need final answer without any addition info. - More info - https://wsrucaptcha.docs.apiary.io/#reference/0 - """ - self.sock: WebSocketClientProtocol = None - self.result = SocketResponse() - self.auth_result = SocketResponse() - - self.allSessions = allSessions or False - self.suppressSuccess = suppressSuccess or True - # RuCaptcha auth params check - if not self.allSessions and not self.suppressSuccess: - raise ValueError( - f"U set allSessions to `{self.allSessions}` and suppressSuccess to `{self.suppressSuccess}`.\n" - f"U will not able to get the final result of captcha solving, cause u close the current socket session " - f"but wait for the result ONLY in the current session(already closed).\n" - f"Try other param variants:\n" - f"\tlike default False/True(u will get an answer in this session for this captcha)\n" - f"\tor True/False(u will get info about the current captcha task and then get captcha solution in all " - f"opened sessions)" - ) - - self.URL = "wss://s.2captcha.com/" - # WebSocket SSL setup - self.ssl_context = ssl.create_default_context() - self.ssl_context.check_hostname = False - self.ssl_context.verify_mode = ssl.CERT_NONE - - async def __socket_session_close(self): - """ - Method close exist socket session - """ - if self.sock: - await self.sock.close() - - async def __socket_session(self): - """ - Create new socket session - """ - self.sock = await websockets.connect(self.URL, ssl=self.ssl_context) - - async def __socket_session_recreate(self): - """ - If socket session not exist - create it - """ - # if socket not exist - if not self.sock: - await self.__socket_session() - # if socket exist but closed - elif self.sock.closed: - await self.__socket_session_close() - await self.__socket_session() - - async def __auth(self): - """ - Method setup connection with RuCaptcha and auth user - """ - await self.__socket_session_recreate() - - auth_data = SockAuthSer( - **{ - "key": self.rucaptcha_key, - "options": {"allSessions": self.allSessions, "suppressSuccess": self.suppressSuccess}, - } - ) - await self.sock.send(auth_data.json()) - self.auth_result = self.auth_result.parse_raw(await self.sock.recv()) - - @retry(wait=wait_fixed(5), stop=stop_after_attempt(3), after=after_log(logging, logging.ERROR), reraise=True) - async def get_request(self) -> dict: - """ - Method send GET request and write result to response model - :return: server response info, serialized to dict without NONE values - """ - await self.__socket_session_recreate() - - response = await self.sock.recv() - await self.__socket_session_close() - - return self.result.parse_raw(response).dict(exclude_none=True) - - @retry(wait=wait_fixed(5), stop=stop_after_attempt(3), after=after_log(logging, logging.ERROR), reraise=True) - async def send_request(self, payload: str) -> dict: - """ - Method send request to server and wait response - :param payload: JSON payload with data - :return: Server response dict - """ - await self.__auth() - # check if auth is success - if self.auth_result.success: - await self.sock.send(payload) - return await self.get_request() - else: - await self.__socket_session_close() - return self.auth_result.dict(exclude_none=True) -''' diff --git a/src/python_rucaptcha/TikTokCaptcha.py b/src/python_rucaptcha/TikTokCaptcha.py deleted file mode 100644 index eb41fe48..00000000 --- a/src/python_rucaptcha/TikTokCaptcha.py +++ /dev/null @@ -1,59 +0,0 @@ -from .core.base import BaseCaptcha -from .core.enums import TikTokCaptchaEnm - - -class TikTokCaptcha(BaseCaptcha): - def __init__( - self, - pageurl: str, - cookies: str, - aid: str, - host: str, - method: str = TikTokCaptchaEnm.TIKTOK.value, - *args, - **kwargs, - ): - """ - The class is used to work with TikTokCaptcha. - Solve description: - https://rucaptcha.com/api-rucaptcha#solving_tiktok - """ - raise DeprecationWarning("This method is temporarily not supported.".upper()) - super().__init__(method=method, *args, **kwargs) - - self.post_payload.update( - { - "pageurl": pageurl, - "cookies": cookies, - "aid": aid, - "host": host, - } - ) - - # check user params - if method not in TikTokCaptchaEnm.list_values(): - raise ValueError(f"Invalid method parameter set, available - {TikTokCaptchaEnm.list_values()}") - - def captcha_handler(self, **kwargs): - """ - The method is responsible for sending data to the server to solve the captcha - :param kwargs: Parameters for the `requests` library - :return: Response to captcha as JSON string with fields: - captchaSolve - captcha solution, - taskId - finds the ID of the task to solve the captcha, - error - False - if everything is fine, True - if there is an error, - errorBody - error name - """ - - return self._processing_response(**kwargs) - - async def aio_captcha_handler(self): - """ - The method is responsible for sending data to the server to solve the captcha - :return: Response to captcha as JSON string with fields: - captchaSolve - captcha solution, - taskId - finds the ID of the task to solve the captcha, - error - False - if everything is fine, True - if there is an error, - errorBody - error name - """ - return await self._aio_processing_response() diff --git a/src/python_rucaptcha/__version__.py b/src/python_rucaptcha/__version__.py index 0419a93d..0ae036ba 100644 --- a/src/python_rucaptcha/__version__.py +++ b/src/python_rucaptcha/__version__.py @@ -1 +1 @@ -__version__ = "5.3.1" +__version__ = "6.0" diff --git a/src/python_rucaptcha/amazon_waf.py b/src/python_rucaptcha/amazon_waf.py index 92400161..eddc6623 100644 --- a/src/python_rucaptcha/amazon_waf.py +++ b/src/python_rucaptcha/amazon_waf.py @@ -1,3 +1,5 @@ +from typing import Union + from .core.base import BaseCaptcha from .core.enums import AmazonWAFCaptchaEnm @@ -5,11 +7,11 @@ class AmazonWAF(BaseCaptcha): def __init__( self, - pageurl: str, - sitekey: str, + websiteURL: str, + websiteKey: str, iv: str, context: str, - method: str = AmazonWAFCaptchaEnm.AMAZON_WAF.value, + method: Union[str, AmazonWAFCaptchaEnm] = AmazonWAFCaptchaEnm.AmazonTaskProxyless, *args, **kwargs, ): @@ -18,74 +20,80 @@ def __init__( Args: rucaptcha_key: User API key - pageurl: Full URL of the captcha page - sitekey: Key value from the page + websiteURL: Full URL of the captcha page + websiteKey: Key value from the page iv: Value iv from the page context: Value of context from page method: Captcha type Examples: >>> AmazonWAF(rucaptcha_key="aa9011f31111181111168611f1151122", - ... pageurl="https://page-with-waf.com/", - ... sitekey="some-site-key", + ... websiteURL="https://page-with-waf.com/", + ... websiteKey="some-site-key", ... iv="some-iv-value", ... context="some-context-value").captcha_handler() { - 'captchaSolve': 'eyJ0e......jNuSFqtyP4Ho', - 'taskId': '7111111984', - 'error': False, - 'errorBody': None + "errorId":0, + "status":"ready", + "solution":{ + "captcha_voucher":"eyJ0eXAiO...oQjTnJlBvAW4", + "existing_token":"f8ab5749-f916-...5D8yAA39JtKVbw=" + }, + "cost":"0.00145", + "ip":"1.2.3.4", + "createTime":1692863536, + "endTime":1692863556, + "solveCount":0, + "taskId": 73243152973, } >>> AmazonWAF(rucaptcha_key="aa9011f31111181111168611f1151122", - ... pageurl="https://page-with-waf.com/", - ... sitekey="some-site-key", + ... websiteURL="https://page-with-waf.com/", + ... websiteKey="some-site-key", ... iv="some-iv-value", ... context="some-context-value").aio_captcha_handler() { - 'captchaSolve': 'eyJ0e......jNuSFqtyP4Ho', - 'taskId': '7111111984', - 'error': False, - 'errorBody': None + "errorId":0, + "status":"ready", + "solution":{ + "captcha_voucher":"eyJ0eXAiO...oQjTnJlBvAW4", + "existing_token":"f8ab5749-f916-...5D8yAA39JtKVbw=" + }, + "cost":"0.00145", + "ip":"1.2.3.4", + "createTime":1692863536, + "endTime":1692863556, + "solveCount":0, + "taskId": 73243152973, } Returns: Dict with full server response Notes: - https://rucaptcha.com/api-rucaptcha#amazon-waf + https://rucaptcha.com/api-docs/amazon-aws-waf-captcha """ super().__init__(method=method, *args, **kwargs) - self.post_payload.update({"sitekey": sitekey, "pageurl": pageurl, "iv": iv, "context": context}) - # check user params if method not in AmazonWAFCaptchaEnm.list_values(): raise ValueError(f"Invalid method parameter set, available - {AmazonWAFCaptchaEnm.list_values()}") + # insert `gt` param to payload + self.create_task_payload["task"].update( + { + "websiteURL": websiteURL, + "websiteKey": websiteKey, + "iv": iv, + "context": context, + } + ) def captcha_handler(self, **kwargs) -> dict: """ Synchronous method for captcha solving - Examples: - >>> AmazonWAF(rucaptcha_key="aa9011f31111181111168611f1151122", - ... pageurl="https://page-with-waf.com/", - ... sitekey="some-site-key", - ... iv="some-iv-value", - ... context="some-context-value").captcha_handler() - { - 'captchaSolve': 'eyJ0e......jNuSFqtyP4Ho', - 'taskId': '7111111984', - 'error': False, - 'errorBody': None - } - Returns: - Response to captcha as JSON string with fields: - captchaSolve - captcha solution, - taskId - finds the ID of the task to solve the captcha, - error - False - if everything is fine, True - if there is an error, - errorBody - error name + Dict with full server response Notes: Check class docstirng for more info @@ -97,25 +105,8 @@ async def aio_captcha_handler(self) -> dict: """ Asynchronous method for captcha solving - Examples: - >>> await AmazonWAF(rucaptcha_key="aa9011f31111181111168611f1151122", - ... pageurl="https://page-with-waf.com/", - ... sitekey="some-site-key", - ... iv="some-iv-value", - ... context="some-context-value").aio_captcha_handler() - { - 'captchaSolve': 'eyJ0e......jNuSFqtyP4Ho', - 'taskId': '7111111984', - 'error': False, - 'errorBody': None - } - Returns: - Response to captcha as JSON string with fields: - captchaSolve - captcha solution, - taskId - finds the ID of the task to solve the captcha, - error - False - if everything is fine, True - if there is an error, - errorBody - error name + Dict with full server response Notes: Check class docstirng for more info diff --git a/src/python_rucaptcha/audio_captcha.py b/src/python_rucaptcha/audio_captcha.py index 6a5ff739..52421e91 100644 --- a/src/python_rucaptcha/audio_captcha.py +++ b/src/python_rucaptcha/audio_captcha.py @@ -1,15 +1,15 @@ -import base64 import shutil -from typing import Optional +from typing import Union, Optional from .core.base import BaseCaptcha from .core.enums import SaveFormatsEnm, AudioCaptchaEnm +from .core.serializer import GetTaskResultResponseSer class AudioCaptcha(BaseCaptcha): def __init__( self, - save_format: str = SaveFormatsEnm.TEMP.value, + save_format: Union[str, SaveFormatsEnm] = SaveFormatsEnm.TEMP, audio_clearing: bool = True, audio_path: str = "PythonRuCaptchaAudio", lang: str = "en", @@ -74,15 +74,16 @@ def __init__( Dict with full server response Notes: - https://rucaptcha.com/api-rucaptcha#audio + https://rucaptcha.com/api-docs/audio """ - super().__init__(method=AudioCaptchaEnm.AUDIO.value, *args, **kwargs) + super().__init__(method=AudioCaptchaEnm.AudioTask.value, *args, **kwargs) self.save_format = save_format self.audio_clearing = audio_clearing self.audio_path = audio_path + self.result = GetTaskResultResponseSer() - self.post_payload.update({"lang": lang}) + self.create_task_payload["task"].update({"lang": lang}) def captcha_handler( self, @@ -100,60 +101,25 @@ def captcha_handler( captcha_base64: Captcha file BASE64 info kwargs: additional params for `requests` library - Examples: - >>> AudioCaptcha(rucaptcha_key="aa9011f31111181111168611f1151122", - ... lang='en' - ... ).captcha_handler(captcha_file='examples/mediacaptcha_audio/recaptcha_55914.mp3') - { - 'captchaSolve': 'five five nine one four', - 'taskId': 73243152973, - 'error': False, - 'errorBody': None - } - - >>> AudioCaptcha(rucaptcha_key="aa9011f31111181111168611f1151122", - ... lang='en' - ... ).captcha_handler(captcha_link='http://some/link/address/recaptcha_55914.mp3') - { - 'captchaSolve': 'five five nine one four', - 'taskId': 73243152973, - 'error': False, - 'errorBody': None - } - Returns: Dict with full server response Notes: Check class docstirng for more info """ - # if a local file link is passed - if captcha_file: - self.post_payload.update({"body": base64.b64encode(self._local_file_captcha(captcha_file)).decode("utf-8")}) - # if the file is transferred in base64 encoding - elif captcha_base64: - self.post_payload.update({"body": base64.b64encode(captcha_base64).decode("utf-8")}) - # if a URL is passed - elif captcha_link: - try: - content = self.url_open(url=captcha_link, **kwargs).content - except Exception as error: - self.result.error = True - self.result.errorBody = str(error) - return self.result.dict() - - # according to the value of the passed parameter, select the function to save the file - if self.save_format == SaveFormatsEnm.CONST.value: - self._file_const_saver(content, self.audio_path, file_extension="mp3") - self.post_payload.update({"body": base64.b64encode(content).decode("utf-8")}) - - else: - # if none of the parameters are passed - self.result.error = True - self.result.errorBody = self.NO_CAPTCHA_ERR - return self.result.dict() - - return self._processing_response(**kwargs) + + self._body_file_processing( + save_format=self.save_format, + file_path=self.audio_path, + file_extension="mp3", + captcha_link=captcha_link, + captcha_file=captcha_file, + captcha_base64=captcha_base64, + **kwargs, + ) + if not self.result.errorId: + return self._processing_response(**kwargs) + return self.result.to_dict() async def aio_captcha_handler( self, @@ -171,59 +137,24 @@ async def aio_captcha_handler( captcha_base64: Captcha file BASE64 kwargs: additional params for `aiohttp` library - Examples: - >>> await AudioCaptcha(rucaptcha_key="aa9011f31111181111168611f1151122", - ... lang='en' - ... ).aio_captcha_handler(captcha_file='examples/mediacaptcha_audio/recaptcha_55914.mp3') - { - 'captchaSolve': 'five five nine one four', - 'taskId': 73243152973, - 'error': False, - 'errorBody': None - } - >>> await AudioCaptcha(rucaptcha_key="aa9011f31111181111168611f1151122", - ... lang='en' - ... ).aio_captcha_handler(captcha_link='http://some/link/address/recaptcha_55914.mp3') - { - 'captchaSolve': 'five five nine one four', - 'taskId': 73243152973, - 'error': False, - 'errorBody': None - } - Returns: Dict with full server response Notes: Check class docstirng for more info """ - # if a local file link is passed - if captcha_file: - self.post_payload.update({"body": base64.b64encode(self._local_file_captcha(captcha_file)).decode("utf-8")}) - # if the file is transferred in base64 encoding - elif captcha_base64: - self.post_payload.update({"body": base64.b64encode(captcha_base64).decode("utf-8")}) - # if a URL is passed - elif captcha_link: - try: - content = await self.aio_url_read(url=captcha_link, **kwargs) - except Exception as error: - self.result.error = True - self.result.errorBody = str(error) - return self.result.dict() - - # according to the value of the passed parameter, select the function to save the file - if self.save_format == SaveFormatsEnm.CONST.value: - self._file_const_saver(content, self.audio_path, file_extension="mp3") - self.post_payload.update({"body": base64.b64encode(content).decode("utf-8")}) - - else: - # if none of the parameters are passed - self.result.error = True - self.result.errorBody = self.NO_CAPTCHA_ERR - return self.result.dict() - - return await self._aio_processing_response() + await self._aio_body_file_processing( + save_format=self.save_format, + file_path=self.audio_path, + file_extension="mp3", + captcha_link=captcha_link, + captcha_file=captcha_file, + captcha_base64=captcha_base64, + **kwargs, + ) + if not self.result.errorId: + return await self._aio_processing_response() + return self.result.to_dict() def __del__(self): if self.save_format == SaveFormatsEnm.CONST.value and self.audio_clearing: diff --git a/src/python_rucaptcha/capy_puzzle.py b/src/python_rucaptcha/capy_puzzle.py index cd4ac770..e1de1e82 100644 --- a/src/python_rucaptcha/capy_puzzle.py +++ b/src/python_rucaptcha/capy_puzzle.py @@ -1,131 +1,121 @@ +from typing import Union + from .core.base import BaseCaptcha from .core.enums import CapyPuzzleEnm class CapyPuzzle(BaseCaptcha): - def __init__(self, pageurl: str, captchakey: str, method: str = CapyPuzzleEnm.CAPY.value, *args, **kwargs): + def __init__( + self, + websiteURL: str, + websiteKey: str, + method: Union[str, CapyPuzzleEnm] = CapyPuzzleEnm.CapyTaskProxyless, + *args, + **kwargs, + ): """ The class is used to work with CapyPuzzle. Args: rucaptcha_key: User API key - pageurl: Full URL of the captcha page - captchakey: The value of the `captchakey` parameter you found in the code of the page + websiteURL: Full URL of the captcha page + websiteKey: The value of the `captchakey` parameter you found in the code of the page method: Captcha type Examples: >>> CapyPuzzle(rucaptcha_key="aa9011f31111181111168611f1151122", - ... captchakey="PUZZLE_Cme4hZLjuZRMYC3uh14C52D3uNms5w", - ... pageurl="https://www.capy.me/account/register/", - ... method=CapyPuzzleEnm.CAPY.value, + ... websiteKey="PUZZLE_Cme4hZLjuZRMYC3uh14C52D3uNms5w", + ... websiteURL="https://www.capy.me/account/register/", + ... method=CapyPuzzleEnm.CapyTaskProxyless.value, ... api_server="https://jp.api.capy.me/", ... version="puzzle", ... ).captcha_handler() { - "captchaSolve": { - "captchakey": "PUZZLE_C...w", - "challengekey": "Uf....It", - "answer": "26x...x9mx" + "errorId":0, + "status":"ready", + "solution":{ + "captchakey":"PUZZLE_Abc1dEFghIJKLM2no34P56q7rStu8v", + "challengekey":"qHAPtn68KTnXFM8VQ3mtYRtmy3cSKuHJ", + "answer":"0xax8ex0xax84x0xkx7qx0xux7gx0xx42x0x3ox42x0x3ox4cx", + "respKey":"" }, - "taskId": 73052314114, - "error": False, - "errorBody": None + "cost":"0.00299", + "ip":"1.2.3.4", + "createTime":1692863536, + "endTime":1692863556, + "solveCount":1, + "taskId":75190409731 } >>> CapyPuzzle(rucaptcha_key="aa9011f31111181111168611f1151122", - ... captchakey="AVATAR_Cme4hZLjuZRMYC3uh14C52D3uNms5w", - ... pageurl="https://www.capy.me/account/register/", - ... method=CapyPuzzleEnm.CAPY.value, + ... websiteKey="PUZZLE_Cme4hZLjuZRMYC3uh14C52D3uNms5w", + ... websiteURL="https://www.capy.me/account/register/", + ... method=CapyPuzzleEnm.CapyTaskProxyless.value, ... api_server="https://jp.api.capy.me/", ... version="avatar", ... ).captcha_handler() { - "captchaSolve": { - "captchakey": "AVATART_C...w", - "challengekey": "Uf....It", - "answer": "26x...x9mx" + "errorId":0, + "status":"ready", + "solution":{ + "captchakey":"PUZZLE_Abc1dEFghIJKLM2no34P56q7rStu8v", + "challengekey":"qHAPtn68KTnXFM8VQ3mtYRtmy3cSKuHJ", + "answer":"0xax8ex0xax84x0xkx7qx0xux7gx0xx42x0x3ox42x0x3ox4cx", + "respKey":"" }, - "taskId": 73052314114, - "error": False, - "errorBody": None + "cost":"0.00299", + "ip":"1.2.3.4", + "createTime":1692863536, + "endTime":1692863556, + "solveCount":1, + "taskId":75190409731 } >>> CapyPuzzle(rucaptcha_key="aa9011f31111181111168611f1151122", - ... captchakey="PUZZLE_Cme4hZLjuZRMYC3uh14C52D3uNms5w", - ... pageurl="https://www.capy.me/account/register/", - ... method="capy", + ... websiteKey="PUZZLE_Cme4hZLjuZRMYC3uh14C52D3uNms5w", + ... websiteURL="https://www.capy.me/account/register/", + ... method="CapyTaskProxyless", ... api_server="https://jp.api.capy.me/", ... version="puzzle", ... ).captcha_handler() { - "captchaSolve": { - "captchakey": "PUZZLE_C...w", - "challengekey": "Uf....It", - "answer": "26x...x9mx" + "errorId":0, + "status":"ready", + "solution":{ + "captchakey":"PUZZLE_Abc1dEFghIJKLM2no34P56q7rStu8v", + "challengekey":"qHAPtn68KTnXFM8VQ3mtYRtmy3cSKuHJ", + "answer":"0xax8ex0xax84x0xkx7qx0xux7gx0xx42x0x3ox42x0x3ox4cx", + "respKey":"" }, - "taskId": 73052314114, - "error": False, - "errorBody": None + "cost":"0.00299", + "ip":"1.2.3.4", + "createTime":1692863536, + "endTime":1692863556, + "solveCount":1, + "taskId":75190409731 } Returns: Dict with full server response Notes: - https://rucaptcha.com/api-rucaptcha#solving_capy + https://rucaptcha.com/api-docs/capy-puzzle-captcha """ super().__init__(method=method, *args, **kwargs) - self.post_payload.update({"captchakey": captchakey, "pageurl": pageurl}) + self.create_task_payload["task"].update({"websiteURL": websiteURL, "websiteKey": websiteKey}) # check user params if method not in CapyPuzzleEnm.list_values(): raise ValueError(f"Invalid method parameter set, available - {CapyPuzzleEnm.list_values()}") - def captcha_handler(self, **kwargs): + def captcha_handler(self, **kwargs) -> dict: """ Sync solving method Args: kwargs: additional params for `requests` library - Examples: - >>> CapyPuzzle(rucaptcha_key="aa9011f31111181111168611f1151122", - ... captchakey="PUZZLE_Cme4hZLjuZRMYC3uh14C52D3uNms5w", - ... pageurl="https://www.capy.me/account/register/", - ... method=CapyPuzzleEnm.CAPY.value, - ... api_server="https://jp.api.capy.me/", - ... version="puzzle", - ... ).captcha_handler() - { - "captchaSolve": { - "captchakey": "PUZZLE_C...w", - "challengekey": "Uf....It", - "answer": "26x...x9mx" - }, - "taskId": 73052314114, - "error": False, - "errorBody": None - } - - >>> CapyPuzzle(rucaptcha_key="aa9011f31111181111168611f1151122", - ... captchakey="PUZZLE_Cme4hZLjuZRMYC3uh14C52D3uNms5w", - ... pageurl="https://www.capy.me/account/register/", - ... method=CapyPuzzleEnm.CAPY.value, - ... api_server="https://jp.api.capy.me/", - ... version="avatar", - ... ).captcha_handler() - { - "captchaSolve": { - "captchakey": "AVATART_C...w", - "challengekey": "Uf....It", - "answer": "26x...x9mx" - }, - "taskId": 73052314114, - "error": False, - "errorBody": None - } - Returns: Dict with full server response @@ -135,47 +125,10 @@ def captcha_handler(self, **kwargs): return self._processing_response(**kwargs) - async def aio_captcha_handler(self): + async def aio_captcha_handler(self) -> dict: """ Async solving method - Examples: - >>> await CapyPuzzle(rucaptcha_key="aa9011f31111181111168611f1151122", - ... captchakey="PUZZLE_Cme4hZLjuZRMYC3uh14C52D3uNms5w", - ... pageurl="https://www.capy.me/account/register/", - ... method=CapyPuzzleEnm.CAPY.value, - ... api_server="https://jp.api.capy.me/", - ... version="puzzle", - ... ).aio_captcha_handler() - { - "captchaSolve": { - "captchakey": "PUZZLE_C...w", - "challengekey": "Uf....It", - "answer": "26x...x9mx" - }, - "taskId": 73052314114, - "error": False, - "errorBody": None - } - - >>> await CapyPuzzle(rucaptcha_key="aa9011f31111181111168611f1151122", - ... captchakey="PUZZLE_Cme4hZLjuZRMYC3uh14C52D3uNms5w", - ... pageurl="https://www.capy.me/account/register/", - ... method=CapyPuzzleEnm.CAPY.value, - ... api_server="https://jp.api.capy.me/", - ... version="avatar", - ... ).aio_captcha_handler() - { - "captchaSolve": { - "captchakey": "AVATART_C...w", - "challengekey": "Uf....It", - "answer": "26x...x9mx" - }, - "taskId": 73052314114, - "error": False, - "errorBody": None - } - Returns: Dict with full server response diff --git a/src/python_rucaptcha/control.py b/src/python_rucaptcha/control.py index 88545c9a..1e222c14 100644 --- a/src/python_rucaptcha/control.py +++ b/src/python_rucaptcha/control.py @@ -1,5 +1,3 @@ -from typing import Optional - from .core.base import BaseCaptcha from .core.enums import ControlEnm from .core.result_handler import get_sync_result, get_async_result @@ -8,7 +6,6 @@ class Control(BaseCaptcha): def __init__( self, - action: str, *args, **kwargs, ): @@ -19,386 +16,159 @@ def __init__( action: Control action type Examples: - >>> Control(rucaptcha_key="aa9011f31111181111168611f1151122", - ... action=ControlEnm.DEL_PINGBACK.value).domain_control(addr="all") + >>> Control(rucaptcha_key="aa9.....").getBalance() { - 'captchaSolve': 'OK', - 'taskId': None, - 'error': False, - 'errorBody': None + 'balance': 1593.4479 } - >>> Control(rucaptcha_key="aa9011f31111181111168611f1151122", - ... action=ControlEnm.GET.value).report(id="73043727671") + >>> await Control(rucaptcha_key="aa9.....").aio_getBalance() { - 'captchaSolve': '1', - 'taskId': None, - 'error': False, - 'errorBody': None + 'balance': 1593.4479 } - DeathByCaptcha: + >>> Control(rucaptcha_key="aa9.....").reportCorrect(id=75188571838) + { + 'errorId': 0, + 'status': 'success' + } - >>> Control(rucaptcha_key="service_username:service_password", - ... service_type="other-captcha-services", - ... action=ControlEnm.GETBALANCE.value).additional_methods() + >>> await Control(rucaptcha_key="aa9.....").aio_reportCorrect(id=75188571838) { - 'captchaSolve': '0.00', - 'taskId': None, - 'error': False, - 'errorBody': None + 'errorId': 0, + 'status': 'success' } - DeathByCaptcha: + >>> Control(rucaptcha_key="aa9.....").reportIncorrect(id=75188571838) + { + 'errorId': 0, + 'status': 'success' + } - >>> from python_rucaptcha.core.enums import ControlEnm, ServiceEnm - >>> Control(rucaptcha_key="service_username:service_password", - ... service_type=ServiceEnm.DEATHBYCAPTCHA, - ... action=ControlEnm.GETBALANCE.value).additional_methods() + >>> await Control(rucaptcha_key="aa9.....").aio_reportIncorrect(id=75188571838) { - 'captchaSolve': '0.00', - 'taskId': None, - 'error': False, - 'errorBody': None + 'errorId': 0, + 'status': 'success' } Returns: Dict with full server response Notes: - https://rucaptcha.com/api-rucaptcha#manage_pingback - https://rucaptcha.com/api-rucaptcha#complain - https://rucaptcha.com/api-rucaptcha#additional + https://rucaptcha.com/api-docs/get-balance + https://rucaptcha.com/api-docs/report-correct + https://rucaptcha.com/api-docs/report-incorrect """ - super().__init__(method=ControlEnm.CONTROL.value, action=action, *args, **kwargs) - - # check user params - if action not in ControlEnm.list_values(): - raise ValueError(f"Invalid method parameter set, available - {ControlEnm.list_values()}") + super().__init__(method=ControlEnm.control, *args, **kwargs) - def domain_control(self, addr: Optional[str] = None) -> dict: + def reportCorrect(self, id: int) -> dict: """ - Callback domains control + reportCorrect method Args: - addr: URL for pingback or `all` with pingback delete param - - Examples: - >>> Control(rucaptcha_key="aa9011f31111181111168611f1151122", - ... action=ControlEnm.DEL_PINGBACK.value).domain_control(addr="all") - { - 'captchaSolve': 'OK', - 'taskId': None, - 'error': False, - 'errorBody': None - } - - >>> Control(rucaptcha_key="aa9011f31111181111168611f1151122", - ... action=ControlEnm.DEL_PINGBACK.value).domain_control(addr="http://mysite.com/pingback/url/") - { - 'captchaSolve': 'OK', - 'taskId': None, - 'error': False, - 'errorBody': None - } - - >>> Control(rucaptcha_key="aa9011f31111181111168611f1151122", - ... action=ControlEnm.ADD_PINGBACK.value).domain_control(addr="http://mysite.com/pingback/url/") - { - 'captchaSolve': 'OK', - 'taskId': None, - 'error': False, - 'errorBody': None - } - - >>> Control(rucaptcha_key="aa9011f31111181111168611f1151122", - ... action=ControlEnm.GET_PINGBACK.value).domain_control() - { - 'captchaSolve': 'http://mysite.com/pingback/url/', - 'taskId': None, - 'error': False, - 'errorBody': None - } - + id: Captcha task ID Returns: Dict with full server response Notes: - https://rucaptcha.com/api-rucaptcha#manage_pingback + https://2captcha.com/api-docs/report-correct """ - self.get_payload.update({"addr": addr}) + self.get_task_payload.taskId = id return get_sync_result( - get_payload=self.get_payload, + get_payload=self.get_task_payload, sleep_time=self.params.sleep_time, - url_response=self.params.url_response, - result=self.result, + url_response=f"https://api.{self.params.service_type}.com/reportCorrect", ) - async def aio_domain_control(self, addr: Optional[str] = None) -> dict: + async def aio_reportCorrect(self, id: int) -> dict: """ - Callback domains control + Captcha results report Args: - addr: URL for pingback or `all` with pingback delete param - - Examples: - >>> await Control(rucaptcha_key="aa9011f31111181111168611f1151122", - ... action=ControlEnm.DEL_PINGBACK.value).aio_domain_control(addr="all") - { - 'captchaSolve': 'OK', - 'taskId': None, - 'error': False, - 'errorBody': None - } - - >>> await Control(rucaptcha_key="aa9011f31111181111168611f1151122", - ... action=ControlEnm.DEL_PINGBACK.value).aio_domain_control(addr="http://mysite.com/pingback/url/") - { - 'captchaSolve': 'OK', - 'taskId': None, - 'error': False, - 'errorBody': None - } - - >>> await Control(rucaptcha_key="aa9011f31111181111168611f1151122", - ... action=ControlEnm.ADD_PINGBACK.value).aio_domain_control(addr="http://mysite.com/pingback/url/") - { - 'captchaSolve': 'OK', - 'taskId': None, - 'error': False, - 'errorBody': None - } - - >>> await Control(rucaptcha_key="aa9011f31111181111168611f1151122", - ... action=ControlEnm.GET_PINGBACK.value).aio_domain_control() - { - 'captchaSolve': 'http://mysite.com/pingback/url/', - 'taskId': None, - 'error': False, - 'errorBody': None - } - + id: Captcha task ID Returns: Dict with full server response Notes: - https://rucaptcha.com/api-rucaptcha#manage_pingback + https://2captcha.com/api-docs/report-correct """ - self.get_payload.update({"addr": addr}) + self.get_task_payload.taskId = id return await get_async_result( - get_payload=self.get_payload, + get_payload=self.get_task_payload, sleep_time=self.params.sleep_time, - url_response=self.params.url_response, - result=self.result, + url_response=f"https://api.{self.params.service_type}.com/reportCorrect", ) - def report(self, id: str) -> dict: + def reportIncorrect(self, id: int) -> dict: """ - Captcha results report + reportCorrect method Args: id: Captcha task ID - Examples: - >>> Control(rucaptcha_key="aa9011f31111181111168611f1151122", - ... action=ControlEnm.GET.value).report(id="73043727671") - { - 'captchaSolve': '1', - 'taskId': None, - 'error': False, - 'errorBody': None - } - - >>> Control(rucaptcha_key="aa9011f31111181111168611f1151122", - ... action=ControlEnm.REPORTGOOD.value).report(id="73043727671") - { - 'captchaSolve': 'OK_REPORT_RECORDED', - 'taskId': None, - 'error': False, - 'errorBody': None - } - - >>> Control(rucaptcha_key="aa9011f31111181111168611f1151122", - ... action=ControlEnm.REPORTBAD.value).report(id="73043727671") - { - 'captchaSolve': 'OK_REPORT_RECORDED', - 'taskId': None, - 'error': False, - 'errorBody': None - } - - Returns: Dict with full server response Notes: - https://rucaptcha.com/api-rucaptcha#complain + https://2captcha.com/api-docs/report-incorrect """ - self.get_payload.update({"id": id}) + self.get_task_payload.taskId = id return get_sync_result( - get_payload=self.get_payload, + get_payload=self.get_task_payload, sleep_time=self.params.sleep_time, - url_response=self.params.url_response, - result=self.result, + url_response=f"https://api.{self.params.service_type}.com/reportIncorrect", ) - async def aio_report(self, id: str) -> dict: + async def aio_reportIncorrect(self, id: int) -> dict: """ Captcha results report Args: id: Captcha task ID - Examples: - >>> await Control(rucaptcha_key="aa9011f31111181111168611f1151122", - ... action=ControlEnm.GET.value).aio_report(id="73043727671") - { - 'captchaSolve': '1', - 'taskId': None, - 'error': False, - 'errorBody': None - } - - >>> await Control(rucaptcha_key="aa9011f31111181111168611f1151122", - ... action=ControlEnm.REPORTGOOD.value).aio_report(id="73043727671") - { - 'captchaSolve': 'OK_REPORT_RECORDED', - 'taskId': None, - 'error': False, - 'errorBody': None - } - - >>> await Control(rucaptcha_key="aa9011f31111181111168611f1151122", - ... action=ControlEnm.REPORTBAD.value).aio_report(id="73043727671") - { - 'captchaSolve': 'OK_REPORT_RECORDED', - 'taskId': None, - 'error': False, - 'errorBody': None - } - - Returns: Dict with full server response Notes: - https://rucaptcha.com/api-rucaptcha#complain + https://2captcha.com/api-docs/report-incorrect """ - self.get_payload.update({"id": id}) + self.get_task_payload.taskId = id return await get_async_result( - get_payload=self.get_payload, + get_payload=self.get_task_payload, sleep_time=self.params.sleep_time, - url_response=self.params.url_response, - result=self.result, + url_response=f"https://api.{self.params.service_type}.com/reportIncorrect", ) - def additional_methods(self, **kwargs) -> dict: + def getBalance(self) -> dict: """ - Some additional methods for control API (like balance and etc.) - - Args: - kwargs: Additional params for method, like `id`, `ids`, more info in service docs. - - Examples: - >>> Control(rucaptcha_key="aa9011f31111181111168611f1151122", - ... action=ControlEnm.GETBALANCE.value).additional_methods() - { - 'captchaSolve': '1044.23118', - 'taskId': None, - 'error': False, - 'errorBody': None - } + GetBalance method Returns: Dict with full server response Notes: - https://rucaptcha.com/api-rucaptcha#additional + Check class docstirng for more info """ - for key in kwargs: - self.get_payload.update({key: kwargs[key]}) return get_sync_result( - get_payload=self.get_payload, + get_payload=self.get_task_payload, sleep_time=self.params.sleep_time, - url_response=self.params.url_response, - result=self.result, + url_response=f"https://api.{self.params.service_type}.com/getBalance", ) - async def aio_additional_methods(self, **kwargs) -> dict: + async def aio_getBalance(self) -> dict: """ - Some additional methods for control API (like balance and etc.) - - Args: - kwargs: Additional params for method, like `id`, `ids`, more info in service docs. - - Examples: - >>> await Control(rucaptcha_key="aa9011f31111181111168611f1151122", - ... action=ControlEnm.GETBALANCE.value).aio_additional_methods() - { - 'captchaSolve': '1044.23118', - 'taskId': None, - 'error': False, - 'errorBody': None - } + Async GetBalance method Returns: Dict with full server response Notes: - https://rucaptcha.com/api-rucaptcha#additional + Check class docstirng for more info """ - for key in kwargs: - self.get_payload.update({key: kwargs[key]}) - return await get_async_result( - get_payload=self.get_payload, + return get_sync_result( + get_payload=self.get_task_payload, sleep_time=self.params.sleep_time, - url_response=self.params.url_response, - result=self.result, - ) - - -''' -# Async WebSocket method -class sockCaptchaControl(WebSocketRuCaptcha): - def __init__(self, rucaptcha_key: str, allSessions: bool = None, suppressSuccess: bool = None): - """ - Method setup WebSocket connection data - Params description check in parent class - """ - super().__init__(allSessions, suppressSuccess) - self.rucaptcha_key = rucaptcha_key - - async def get_balance(self) -> dict: - """ - The asynchronous WebSocket method return account balance. - More info - https://wsrucaptcha.docs.apiary.io/#reference/4 - :return: Server response dict - """ - balance_payload = ControlCaptchaSocketSer( - **{ - "method": "balance", - } + url_response=f"https://api.{self.params.service_type}.com/getBalance", ) - return await self.send_request(balance_payload.json(exclude_none=True)) - - async def report(self, success: bool, captchaId: int) -> dict: - """ - The asynchronous WebSocket method send captcha solving reports (success or fail). - More info - https://wsrucaptcha.docs.apiary.io/#reference/2 - :param success: Is captcha solved success? - :param captchaId: Captcha task unique id. For example - 5034284222 - :return: Server response dict - """ - report_payload = ControlCaptchaSocketSer( - **{ - "method": "report", - "success": success, - "captchaId": captchaId, - } - ) - - return await self.send_request(report_payload.json(exclude_none=True)) -''' diff --git a/src/python_rucaptcha/core/base.py b/src/python_rucaptcha/core/base.py index 286f3c30..274dfdc7 100644 --- a/src/python_rucaptcha/core/base.py +++ b/src/python_rucaptcha/core/base.py @@ -1,7 +1,9 @@ import os import time import uuid +import base64 import asyncio +from typing import Union, Optional from pathlib import Path import aiohttp @@ -9,8 +11,9 @@ from requests.adapters import HTTPAdapter from . import enums +from .enums import SaveFormatsEnm from .config import RETRIES, ASYNC_RETRIES -from .serializer import ResponseSer, GetRequestSer, PostRequestSer, CaptchaOptionsSer, ServicePostResponseSer +from .serializer import TaskSer, CaptchaOptionsSer, CreateTaskBaseSer, GetTaskResultRequestSer, GetTaskResultResponseSer from .result_handler import get_sync_result, get_async_result @@ -21,74 +24,60 @@ def __init__( self, rucaptcha_key: str, method: str, - action: str = "get", - sleep_time: int = 15, + sleep_time: int = 10, service_type: str = enums.ServiceEnm.TWOCAPTCHA.value, **kwargs, ): """ :param rucaptcha_key: User API key :param method: Captcha type - :param action: Server action :param sleep_time: Time to wait for captcha solution :param service_type: URL with which the program will work, "2captcha" option is possible (standard) and "rucaptcha" :param kwargs: Designed to pass OPTIONAL parameters to the payload for a request to RuCaptcha """ + self.result = GetTaskResultResponseSer() # assign args to validator - self.params = CaptchaOptionsSer(**locals(), **kwargs) + self.params = CaptchaOptionsSer(sleep_time=sleep_time, service_type=service_type) + self.params.urls_set() - # prepare POST payload - self.post_payload = PostRequestSer(key=self.params.rucaptcha_key, method=method).dict(by_alias=True) - # prepare GET payload - self.get_payload = GetRequestSer(key=self.params.rucaptcha_key, action=action).dict( - by_alias=True, exclude_none=True - ) - # prepare result payload - self.result = ResponseSer() + # prepare create task payload + self.create_task_payload = CreateTaskBaseSer( + clientKey=rucaptcha_key, task=TaskSer(type=method).to_dict() + ).to_dict() + # prepare get task result data payload + self.get_task_payload = GetTaskResultRequestSer(clientKey=rucaptcha_key) for key in kwargs: - self.post_payload.update({key: kwargs[key]}) + self.create_task_payload["task"].update({key: kwargs[key]}) # prepare session self.session = requests.Session() self.session.mount("http://", HTTPAdapter(max_retries=RETRIES)) self.session.mount("https://", HTTPAdapter(max_retries=RETRIES)) - def _processing_response(self, **kwargs: dict) -> dict: + def _processing_response(self, **kwargs: dict) -> Union[dict, Exception]: """ Method processing captcha solving task creation result :param kwargs: additional params for Requests library """ try: - response = ServicePostResponseSer( - **self.session.post(self.params.url_request, data=self.post_payload, **kwargs).json() + response = GetTaskResultResponseSer( + **self.session.post(self.params.url_request, json=self.create_task_payload, **kwargs).json() ) # check response status - if response.status == 1: - self.result.taskId = response.request + if response.errorId == 0: + self.get_task_payload.taskId = response.taskId else: - self.result.error = True - self.result.errorBody = response.request + return response.to_dict() except Exception as error: - self.result.error = True - self.result.errorBody = str(error) - - # check for errors while make request to server - if self.result.error: - return self.result.dict() - - # if all is ok - send captcha to service and wait solution - # update payload - add captcha taskId - self.get_payload.update({"id": self.result.taskId}) + return error # wait captcha solving time.sleep(self.params.sleep_time) + return get_sync_result( - get_payload=self.get_payload, - sleep_time=self.params.sleep_time, - url_response=self.params.url_response, - result=self.result, + get_payload=self.get_task_payload, sleep_time=self.params.sleep_time, url_response=self.params.url_response ) def url_open(self, url: str, **kwargs): @@ -107,49 +96,38 @@ async def aio_url_read(self, url: str, **kwargs) -> bytes: async with session.get(url=url, **kwargs) as resp: return await resp.content.read() - async def _aio_processing_response(self) -> dict: + async def _aio_processing_response(self) -> Union[dict, Exception]: """ Method processing async captcha solving task creation result """ try: # make async or sync request - response = await self.__aio_make_post_request() + response = await self.__aio_create_task() # check response status - if response.status == 1: - self.result.taskId = response.request + if response.errorId == 0: + self.get_task_payload.taskId = response.taskId else: - self.result.error = True - self.result.errorBody = response.request + return response.to_dict() except Exception as error: - self.result.error = True - self.result.errorBody = str(error) - - # check for errors while make request to server - if self.result.error: - return self.result.dict() - - # if all is ok - send captcha to service and wait solution - # update payload - add captcha taskId - self.get_payload.update({"id": self.result.taskId}) + return error # wait captcha solving await asyncio.sleep(self.params.sleep_time) return await get_async_result( - get_payload=self.get_payload, + get_payload=self.get_task_payload, sleep_time=self.params.sleep_time, url_response=self.params.url_response, - result=self.result, ) - async def __aio_make_post_request(self) -> ServicePostResponseSer: + async def __aio_create_task(self) -> GetTaskResultResponseSer: async with aiohttp.ClientSession() as session: async for attempt in ASYNC_RETRIES: with attempt: async with session.post( - self.params.url_request, data=self.post_payload, raise_for_status=True + self.params.url_request, json=self.create_task_payload, raise_for_status=True ) as resp: response_json = await resp.json(content_type=None) - return ServicePostResponseSer(**response_json) + return GetTaskResultResponseSer(**response_json) # Working with images methods @@ -174,6 +152,76 @@ def _file_const_saver(self, content: bytes, file_path: str, file_extension: str with open(os.path.join(file_path, self._file_name), "wb") as out_image: out_image.write(content) + def _body_file_processing( + self, + save_format: SaveFormatsEnm, + file_path: str, + file_extension: str = "png", + captcha_link: Optional[str] = None, + captcha_file: Optional[str] = None, + captcha_base64: Optional[bytes] = None, + **kwargs, + ): + # if a local file link is passed + if captcha_file: + self.create_task_payload["task"].update( + {"body": base64.b64encode(self._local_file_captcha(captcha_file)).decode("utf-8")} + ) + # if the file is transferred in base64 encoding + elif captcha_base64: + self.create_task_payload["task"].update({"body": base64.b64encode(captcha_base64).decode("utf-8")}) + # if a URL is passed + elif captcha_link: + try: + content = self.url_open(url=captcha_link, **kwargs).content + # according to the value of the passed parameter, select the function to save the image + if save_format == SaveFormatsEnm.CONST.value: + self._file_const_saver(content, file_path, file_extension=file_extension) + self.create_task_payload["task"].update({"body": base64.b64encode(content).decode("utf-8")}) + except Exception as error: + self.result.errorId = 12 + self.result.errorCode = self.NO_CAPTCHA_ERR + self.result.errorDescription = str(error) + + else: + self.result.errorId = 12 + self.result.errorCode = self.NO_CAPTCHA_ERR + + async def _aio_body_file_processing( + self, + save_format: SaveFormatsEnm, + file_path: str, + file_extension: str = "png", + captcha_link: Optional[str] = None, + captcha_file: Optional[str] = None, + captcha_base64: Optional[bytes] = None, + **kwargs, + ): + # if a local file link is passed + if captcha_file: + self.create_task_payload["task"].update( + {"body": base64.b64encode(self._local_file_captcha(captcha_file)).decode("utf-8")} + ) + # if the file is transferred in base64 encoding + elif captcha_base64: + self.create_task_payload["task"].update({"body": base64.b64encode(captcha_base64).decode("utf-8")}) + # if a URL is passed + elif captcha_link: + try: + content = await self.aio_url_read(url=captcha_link, **kwargs) + # according to the value of the passed parameter, select the function to save the image + if save_format == SaveFormatsEnm.CONST.value: + self._file_const_saver(content, file_path, file_extension=file_extension) + self.create_task_payload["task"].update({"body": base64.b64encode(content).decode("utf-8")}) + except Exception as error: + self.result.errorId = 12 + self.result.errorCode = self.NO_CAPTCHA_ERR + self.result.errorDescription = str(error) + + else: + self.result.errorId = 12 + self.result.errorCode = self.NO_CAPTCHA_ERR + def __enter__(self): return self diff --git a/src/python_rucaptcha/core/config.py b/src/python_rucaptcha/core/config.py index 09e3dfca..4f194704 100644 --- a/src/python_rucaptcha/core/config.py +++ b/src/python_rucaptcha/core/config.py @@ -8,7 +8,7 @@ # Connection retry generator -def attempts_generator(amount: int = 7): +def attempts_generator(amount: int = 20): """ Function generates a generator of length equal to `amount` diff --git a/src/python_rucaptcha/core/enums.py b/src/python_rucaptcha/core/enums.py index 2ef92ca6..ca3fa916 100644 --- a/src/python_rucaptcha/core/enums.py +++ b/src/python_rucaptcha/core/enums.py @@ -32,40 +32,51 @@ class SaveFormatsEnm(str, MyEnum): class GeetestEnm(str, MyEnum): - GEETEST = "geetest" - GEETEST_V4 = "geetest_v4" + GeeTestTask = "GeeTestTask" + GeeTestTaskProxyless = "GeeTestTaskProxyless" class ImageCaptchaEnm(str, MyEnum): - BASE64 = "base64" + ImageToTextTask = "ImageToTextTask" class CapyPuzzleEnm(str, MyEnum): - CAPY = "capy" + CapyTask = "CapyTask" + CapyTaskProxyless = "CapyTaskProxyless" class FunCaptchaEnm(str, MyEnum): - FUNCAPTCHA = "funcaptcha" + FunCaptchaTaskProxyless = "FunCaptchaTaskProxyless" + FunCaptchaTask = "FunCaptchaTask" class ReCaptchaEnm(str, MyEnum): - USER_RECAPTCHA = "userrecaptcha" + RecaptchaV2TaskProxyless = "RecaptchaV2TaskProxyless" + RecaptchaV2Task = "RecaptchaV2Task" + RecaptchaV2EnterpriseTaskProxyless = "RecaptchaV2EnterpriseTaskProxyless" + RecaptchaV2EnterpriseTask = "RecaptchaV2EnterpriseTask" -class LeminCroppedCaptchaEnm(str, MyEnum): - LEMIN = "lemin" + RecaptchaV3TaskProxyless = "RecaptchaV3TaskProxyless" + + +class LeminCaptchaEnm(str, MyEnum): + LeminTaskProxyless = "LeminTaskProxyless" + LeminTask = "LeminTask" class HCaptchaEnm(str, MyEnum): - HCAPTCHA = "hcaptcha" + HCaptchaTask = "HCaptchaTask" + HCaptchaTaskProxyless = "HCaptchaTaskProxyless" class KeyCaptchaEnm(str, MyEnum): - KEYCAPTCHA = "keycaptcha" + KeyCaptchaTask = "KeyCaptchaTask" + KeyCaptchaTaskProxyless = "KeyCaptchaTaskProxyless" class RotateCaptchaEnm(str, MyEnum): - ROTATECAPTCHA = "rotatecaptcha" + RotateTask = "RotateTask" class TikTokCaptchaEnm(str, MyEnum): @@ -73,40 +84,28 @@ class TikTokCaptchaEnm(str, MyEnum): class ControlEnm(str, MyEnum): - # control method - CONTROL = "control" - - # default - GET = "get" - # https://rucaptcha.com/api-rucaptcha#manage_pingback - ADD_PINGBACK = "add_pingback" - GET_PINGBACK = "get_pingback" - DEL_PINGBACK = "del_pingback" - - # https://rucaptcha.com/api-rucaptcha#additional - GETBALANCE = "getbalance" - GET2 = "get2" - - # https://rucaptcha.com/api-rucaptcha#complain - REPORTGOOD = "reportgood" - REPORTBAD = "reportbad" - - -class YandexSmartCaptchaEnm(str, MyEnum): - YANDEX = "yandex" + control = "control" + # https://rucaptcha.com/api-docs/get-balance + getBalance = "getBalance" + # https://rucaptcha.com/api-docs/report-correct + reportCorrect = "reportCorrect" + # https://rucaptcha.com/api-docs/report-incorrect + reportIncorrect = "reportIncorrect" class TurnstileCaptchaEnm(str, MyEnum): - TURNSTILE = "turnstile" + TurnstileTaskProxyless = "TurnstileTaskProxyless" + TurnstileTask = "TurnstileTask" class AmazonWAFCaptchaEnm(str, MyEnum): - AMAZON_WAF = "amazon_waf" + AmazonTask = "AmazonTask" + AmazonTaskProxyless = "AmazonTaskProxyless" class TextCaptchaEnm(str, MyEnum): - TEXT = "text" + TextCaptchaTask = "TextCaptchaTask" class AudioCaptchaEnm(str, MyEnum): - AUDIO = "audio" + AudioTask = "AudioTask" diff --git a/src/python_rucaptcha/core/result_handler.py b/src/python_rucaptcha/core/result_handler.py index 20c854bb..936c1e70 100644 --- a/src/python_rucaptcha/core/result_handler.py +++ b/src/python_rucaptcha/core/result_handler.py @@ -1,44 +1,16 @@ import time import asyncio +import logging +from typing import Union import aiohttp import requests from .config import attempts_generator -from .serializer import ResponseSer, ServiceGetResponseSer +from .serializer import GetTaskResultRequestSer, GetTaskResultResponseSer -def result_processing(captcha_response: ServiceGetResponseSer, result: ResponseSer) -> dict: - """ - Function processing service response status values - """ - - # on error during solving - if captcha_response.status == 0: - result.error = True - result.errorBody = captcha_response.request - - # if solving is success - elif captcha_response.status == 1: - result.error = False - result.errorBody = None - result.captchaSolve = captcha_response.request - - # if this is ReCaptcha v3 then we get it from the server - if captcha_response.user_check and captcha_response.user_score: - result = result.dict() - result.update( - { - "user_check": captcha_response.user_check, - "user_score": captcha_response.user_score, - } - ) - return result - - return result.dict() - - -def get_sync_result(get_payload: dict, sleep_time: int, url_response: str, result: ResponseSer) -> dict: +def get_sync_result(get_payload: GetTaskResultRequestSer, sleep_time: int, url_response: str) -> Union[dict, Exception]: """ Function periodically send the SYNC request to service and wait for captcha solving result """ @@ -47,23 +19,26 @@ def get_sync_result(get_payload: dict, sleep_time: int, url_response: str, resul for _ in attempts: try: # send a request for the result of solving the captcha - captcha_response = ServiceGetResponseSer(**requests.get(url_response, params=get_payload).json()) + captcha_response = GetTaskResultResponseSer( + **requests.post(url_response, json=get_payload.to_dict()).json(), taskId=get_payload.taskId + ) + logging.warning(f"{captcha_response = }") # if the captcha has not been resolved yet, wait - if captcha_response.request == "CAPCHA_NOT_READY": + if captcha_response.status == "processing": time.sleep(sleep_time) - result.error = True - result.errorBody = "ERROR_CAPTCHA_UNSOLVABLE" - else: - return result_processing(captcha_response, result) - + continue + elif captcha_response.status == "ready": + break + elif captcha_response.errorId != 0: + return captcha_response.to_dict() except Exception as error: - result.error = True - result.errorBody = str(error) + return error + return captcha_response.to_dict() - return result.dict() - -async def get_async_result(get_payload: dict, sleep_time: int, url_response: str, result: ResponseSer) -> dict: +async def get_async_result( + get_payload: GetTaskResultRequestSer, sleep_time: int, url_response: str +) -> Union[dict, Exception]: """ Function periodically send the ASYNC request to service and wait for captcha solving result """ @@ -73,20 +48,18 @@ async def get_async_result(get_payload: dict, sleep_time: int, url_response: str for _ in attempts: try: # send a request for the result of solving the captcha - async with session.get(url_response, params=get_payload, raise_for_status=True) as resp: + async with session.post(url_response, json=get_payload.to_dict(), raise_for_status=True) as resp: captcha_response = await resp.json(content_type=None) - captcha_response = ServiceGetResponseSer(**captcha_response) + captcha_response = GetTaskResultResponseSer(**captcha_response, taskId=get_payload.taskId) # if the captcha has not been resolved yet, wait - if captcha_response.request == "CAPCHA_NOT_READY": + if captcha_response.status == "processing": await asyncio.sleep(sleep_time) - result.error = True - result.errorBody = "ERROR_CAPTCHA_UNSOLVABLE" - - else: - return result_processing(captcha_response, result) - + continue + elif captcha_response.status == "ready": + break + elif captcha_response.errorId != 0: + return captcha_response.to_dict() except Exception as error: - result.error = True - result.errorBody = str(error) - return result.dict() + return error + return captcha_response.to_dict() diff --git a/src/python_rucaptcha/core/serializer.py b/src/python_rucaptcha/core/serializer.py index 29eea887..b25b0d85 100644 --- a/src/python_rucaptcha/core/serializer.py +++ b/src/python_rucaptcha/core/serializer.py @@ -1,148 +1,60 @@ -import logging -from uuid import uuid4 -from typing import Union, Optional +from typing import Literal, Optional -from pydantic import Field, BaseModel, conint, constr, validator, root_validator +from msgspec import Struct from . import enums from .config import APP_KEY -""" -Socket API Serializers -""" - - -class MyBaseModel(BaseModel): - class Config: - validate_assignment = True - -class CaptchaOptionsSocketSer(MyBaseModel): - phrase: bool = False - caseSensitive: bool = False - numeric: conint(ge=1, le=4) = 0 - calc: bool = False - minLen: conint(ge=0, le=20) = 0 - maxLen: conint(ge=0, le=20) = 0 - lang: str = "" - hintText: constr(max_length=139) = "" - hintImg: str = "" - softId: str = Field(APP_KEY, const=True) +class MyBaseModel(Struct): + def to_dict(self): + return {f: getattr(self, f) for f in self.__struct_fields__} -class NormalCaptchaSocketSer(BaseModel): - method: str = "normal" - requestId: str = Field(default_factory=lambda: str(uuid4())) - body: str = str() - options: "CaptchaOptionsSocketSer" = CaptchaOptionsSocketSer() +""" +HTTP API Serializers +""" -class TextCaptchaSocketSer(BaseModel): - method: str = "text" - requestId: str = Field(default_factory=lambda: str(uuid4())) - body: str = str() - options: "CaptchaOptionsSocketSer" = CaptchaOptionsSocketSer() +class TaskSer(MyBaseModel): + type: str -class ControlCaptchaSocketSer(BaseModel): - method: str - requestId: str = Field(default_factory=lambda: str(uuid4())) - success: str = None - captchaId: int = None +class ErrorFieldsSer(Struct): + errorCode: str = None + errorDescription: str = None -class SocketResponse(BaseModel): - method: str = None - success: bool = None - code: str = None - # captcha task ID at RuCaptcha service - captchaId: int = None - # manually generated requestID - requestId: str = Field(default_factory=lambda: str(uuid4())) - error: str = None - # specific fields for balance request response - balance: float = None - valute: str = None +class CreateTaskBaseSer(MyBaseModel): + clientKey: str + task: TaskSer = {} + languagePool: str = "en" + callbackUrl: str = None + soft_id: Literal[APP_KEY] = APP_KEY -class SockAuthSer(BaseModel): - method: str = "auth" - requestId: str = Field(default_factory=lambda: str(uuid4())) - key: str - options: dict +class GetTaskResultRequestSer(MyBaseModel): + clientKey: str + taskId: int = None -""" -HTTP API Serializers -""" +class CaptchaOptionsSer(MyBaseModel): + sleep_time: int = 10 + service_type: enums.ServiceEnm = enums.ServiceEnm.TWOCAPTCHA.value + url_request: Optional[str] = None + url_response: Optional[str] = None -class PostRequestSer(MyBaseModel): - key: str - method: str - soft_id: str = Field(APP_KEY, const=True) - field_json: int = Field(1, alias="json") - - -class GetRequestSer(BaseModel): - key: str - action: str = "get" - field_json: int = Field(1, alias="json") - - # Control keys - ids: str = None - id: str = None - - -class CaptchaOptionsSer(BaseModel): - method: str - action: str - sleep_time: conint(gt=5) = 10 - service_type: str = enums.ServiceEnm.TWOCAPTCHA.value - rucaptcha_key: constr(min_length=1) - - url_request: Optional[str] = None # /in.php - url_response: Optional[str] = None # /res.php - - @validator("rucaptcha_key") - def rucaptcha_key_check(cls, value, values, **kwargs): - service_type = values.get("service_type") - if service_type in (enums.ServiceEnm.RUCAPTCHA, enums.ServiceEnm.TWOCAPTCHA): - if len(value) != 32: - raise ValueError(f"Invalid `rucaptcha_key` len, it must be - 32, u send - {len(value)}") - return value - - @validator("service_type") - def service_type_check(cls, value): - if value not in enums.ServiceEnm.list_values(): - logging.warning( - f"We support only this list of services - '{', '.join(enums.ServiceEnm.list_values())}', u send - '{value}'. " - f"All other services you use at your own risk" - ) - return value - - @root_validator - def urls_set(cls, values): + def urls_set(self): """ - Set request \ response URLs if they not set previously + Set request/response URLs if they not set previously """ - if not values.get("url_request") and not values.get("url_response"): - service_type = values.get("service_type") - if service_type == enums.ServiceEnm.DEATHBYCAPTCHA: - values.update( - { - "url_request": f"http://api.{service_type}.com/2captcha/in.php", - "url_response": f"http://api.{service_type}.com/2captcha/res.php", - } - ) - else: - values.update( - { - "url_request": f"http://{service_type}.com/in.php", - "url_response": f"http://{service_type}.com/res.php", - } - ) - return values + if self.service_type == enums.ServiceEnm.DEATHBYCAPTCHA: + self.url_request = f"http://api.{self.service_type}.com/2captcha/in.php" + self.url_response = f"http://api.{self.service_type}.com/2captcha/res.php" + else: + self.url_request = f"https://api.{self.service_type}.com/createTask" + self.url_response = f"https://api.{self.service_type}.com/getTaskResult" """ @@ -150,22 +62,15 @@ def urls_set(cls, values): """ -class ServicePostResponseSer(MyBaseModel): - status: int - request: str - - -class ServiceGetResponseSer(BaseModel): - status: int - request: Union[str, dict] - - # ReCaptcha V3 params - user_check: str = "" - user_score: str = "" - - -class ResponseSer(MyBaseModel): - captchaSolve: Union[dict, str] = {} - taskId: Optional[int] = None - error: bool = False - errorBody: Optional[str] = None +class GetTaskResultResponseSer(MyBaseModel, ErrorFieldsSer): + errorId: int = 0 + status: str = "ready" + solution: dict = None + cost: float = None + ip: str = None + createTime: int = None + endTime: int = None + solveCount: int = None + taskId: int = None + # control method params + balance: float = None diff --git a/src/python_rucaptcha/fun_captcha.py b/src/python_rucaptcha/fun_captcha.py index 39e0ae00..5e36e893 100644 --- a/src/python_rucaptcha/fun_captcha.py +++ b/src/python_rucaptcha/fun_captcha.py @@ -1,99 +1,103 @@ +from typing import Union + from .core.base import BaseCaptcha from .core.enums import FunCaptchaEnm class FunCaptcha(BaseCaptcha): - def __init__(self, pageurl: str, publickey: str, method: str = FunCaptchaEnm.FUNCAPTCHA.value, *args, **kwargs): + def __init__( + self, + websiteURL: str, + websitePublicKey: str, + method: Union[str, FunCaptchaEnm] = FunCaptchaEnm.FunCaptchaTaskProxyless, + *args, + **kwargs, + ): """ The class is used to work with Arkose Labs FunCaptcha. Args: rucaptcha_key: User API key - pageurl: Full URL of the captcha page - publickey: The value of the `pk` or `data-pkey` parameter you found in the page code + websiteURL: Full URL of the captcha page + websitePublicKey: The value of the `pk` or `data-pkey` parameter you found in the page code method: Captcha type Examples: >>> FunCaptcha(rucaptcha_key="aa9011f31111181111168611f1151122", - ... pageurl="https://api.funcaptcha.com/tile-game-lite-mode/fc/api/nojs/?pkey=69A21A01-CC7B-B9C6-0F9A-E7FA06677FFC&lang=en", - ... publickey="69A21A01-CC7B-B9C6-0F9A-E7FA06677FFC", - ... surl="https://client-api.arkoselabs.com", - ... method=FunCaptchaEnm.FUNCAPTCHA.value + ... websiteURL="https://api.funcaptcha.com/tile-game-lite-mode/fc/api/nojs/?pkey=69A21A01-CC7B-B9C6-0F9A-E7FA06677FFC&lang=en", + ... websitePublicKey="69A21A01-CC7B-B9C6-0F9A-E7FA06677FFC", + ... method=FunCaptchaEnm.FunCaptchaTaskProxyless.value ... ).captcha_handler() { - "captchaSolve": "23217....ger", - "taskId": 73052314114, - "error": False, - "errorBody": None + "errorId":0, + "status":"ready", + "solution":{ + "token":"142000f.....er" + }, + "cost":"0.002", + "ip":"1.2.3.4", + "createTime":1692863536, + "endTime":1692863556, + "solveCount":0, + "taskId": 73243152973, + } + + >>> await FunCaptcha(rucaptcha_key="aa9011f31111181111168611f1151122", + ... websiteURL="https://api.funcaptcha.com/tile-game-lite-mode/fc/api/nojs/?pkey=69A21A01-CC7B-B9C6-0F9A-E7FA06677FFC&lang=en", + ... websitePublicKey="69A21A01-CC7B-B9C6-0F9A-E7FA06677FFC", + ... method=FunCaptchaEnm.FunCaptchaTaskProxyless.value + ... ).aio_captcha_handler() + { + "errorId":0, + "status":"ready", + "solution":{ + "token":"142000f.....er" + }, + "cost":"0.002", + "ip":"1.2.3.4", + "createTime":1692863536, + "endTime":1692863556, + "solveCount":0, + "taskId": 73243152973, } Returns: Dict with full server response Notes: - https://rucaptcha.com/api-rucaptcha#solving_funcaptcha_new + https://rucaptcha.com/api-docs/arkoselabs-funcaptcha """ super().__init__(method=method, *args, **kwargs) - self.post_payload.update({"publickey": publickey, "pageurl": pageurl}) + self.create_task_payload["task"].update({"websiteURL": websiteURL, "websitePublicKey": websitePublicKey}) # check user params if method not in FunCaptchaEnm.list_values(): raise ValueError(f"Invalid method parameter set, available - {FunCaptchaEnm.list_values()}") - def captcha_handler(self, **kwargs): + def captcha_handler(self, **kwargs) -> dict: """ Sync solving method Args: kwargs: additional params for `requests` library - Examples: - >>> FunCaptcha(rucaptcha_key="aa9011f31111181111168611f1151122", - ... pageurl="https://api.funcaptcha.com/tile-game-lite-mode/fc/api/nojs/?pkey=69A21A01-CC7B-B9C6-0F9A-E7FA06677FFC&lang=en", - ... publickey="69A21A01-CC7B-B9C6-0F9A-E7FA06677FFC", - ... method=FunCaptchaEnm.FUNCAPTCHA.value, - ... surl="https://client-api.arkoselabs.com", - ... userAgent="some-user-agent" - ... ).captcha_handler() - { - "captchaSolve": "23217....ger", - "taskId": 73052314114, - "error": False, - "errorBody": None - } - Returns: Dict with full server response Notes: - https://rucaptcha.com/api-rucaptcha#solving_funcaptcha_new + Check class docstirng for more info """ return self._processing_response(**kwargs) - async def aio_captcha_handler(self): + async def aio_captcha_handler(self) -> dict: """ Async solving method - Examples: - >>> await FunCaptcha(rucaptcha_key="aa9011f31111181111168611f1151122", - ... pageurl="https://api.funcaptcha.com/tile-game-lite-mode/fc/api/nojs/?pkey=69A21A01-CC7B-B9C6-0F9A-E7FA06677FFC&lang=en", - ... publickey="69A21A01-CC7B-B9C6-0F9A-E7FA06677FFC", - ... method=FunCaptchaEnm.FUNCAPTCHA.value, - ... surl="https://client-api.arkoselabs.com", - ... userAgent="some-user-agent" - ... ).aio_captcha_handler() - { - "captchaSolve": "23217....ger", - "taskId": 73052314114, - "error": False, - "errorBody": None - } - Returns: Dict with full server response Notes: - https://rucaptcha.com/api-rucaptcha#solving_funcaptcha_new + Check class docstirng for more info """ return await self._aio_processing_response() diff --git a/src/python_rucaptcha/gee_test.py b/src/python_rucaptcha/gee_test.py index f1059fca..ce6f42da 100644 --- a/src/python_rucaptcha/gee_test.py +++ b/src/python_rucaptcha/gee_test.py @@ -1,4 +1,4 @@ -from typing import Optional +from typing import Union from .core.base import BaseCaptcha from .core.enums import GeetestEnm @@ -7,10 +7,11 @@ class GeeTest(BaseCaptcha): def __init__( self, - pageurl: str, - method: str, - gt: Optional[str] = None, - captcha_id: Optional[str] = None, + websiteURL: str, + method: Union[GeetestEnm, str], + gt: str, + version: int = 3, + initParameters: dict = None, *args, **kwargs, ): @@ -19,9 +20,11 @@ def __init__( Args: rucaptcha_key: User API key - pageurl: Full URL of the captcha page + websiteURL: Full URL of the captcha page gt: The value of the `gt` parameter found on the site - captcha_id: The value of the `captcha_id` parameter found on the site + version: GeeTest V4 captcha should be set to 4. + initParameters: Required for GeeTest V4. The parameter that is passed in the initGeetest4 function call must contain the captcha_id value. + Example of usage: { "captcha_id" : "e392e1d7fd421dc63325744d5a2b9c73"} method: Captcha type kwargs: Not required params for task creation request @@ -37,91 +40,129 @@ def __init__( } >>> GeeTest(rucaptcha_key="aa9011f31111181111168611f1151122", ... gt=resp_data["gt"], - ... pageurl="https://www.geetest.com/en/demo", - ... method=GeetestEnm.GEETEST.value, - ... api_server="api.geetest.com", - ... new_captcha=1, + ... websiteURL="https://www.geetest.com/en/demo", + ... method=GeetestEnm.GeeTestTaskProxyless.value ... ).captcha_handler(challenge=resp_data["challenge"]) { - "captchaSolve": { - "geetest_challenge": "1ad03db8aff920037fb8117827eab171gu", - "geetest_validate": "011309d29dab6e98e8fc3784a95469cc", - "geetest_seccode": "011309d29dab6e98e8fc3784a95469cc|jordan" + "errorId":0, + "status":"ready", + "solution":{ + "captcha_id":"e392e1d7fd421dc63325744d5a2b9c73", + "lot_number":"e6c3bed2854f41f880662c48afff5dcb", + "pass_token":"fad5eb52fc83bf7617402fcccfb211a21e0aa1d1044", + "gen_time":"1693924478", + "captcha_output":"fN36ufW6cQN4SQ-JRDQC70nSq9UcQBg==" }, - "taskId": 73052314114, - "error": False, - "errorBody": None + "cost":"0.00299", + "ip":"1.2.3.4", + "createTime":1692863536, + "endTime":1692863556, + "solveCount":1, + "taskId":75190409731 } - >>> import requests - >>> resp_data = requests.get("https://www.geetest.com/demo/gt/register-enFullpage-official").json() - >>> print(resp_data) - { - 'success': 1, - 'challenge': '1ad03db8aff920037fb8117827eab171', - 'gt': '022397c99c9f646f6477822485f30404', - 'new_captcha': True - } >>> await GeeTest(rucaptcha_key="aa9011f31111181111168611f1151122", ... gt=resp_data["gt"], - ... pageurl="https://www.geetest.com/en/demo", - ... method=GeetestEnm.GEETEST.value, - ... api_server="api.geetest.com", - ... new_captcha=1, + ... websiteURL="https://www.geetest.com/en/demo", + ... method=GeetestEnm.GeeTestTaskProxyless.value ... ).aio_captcha_handler(challenge=resp_data["challenge"]) { - "captchaSolve": { - "geetest_challenge": "1ad0....b171gu", - "geetest_validate": "011....69cc", - "geetest_seccode": "0....c|jordan" + "errorId":0, + "status":"ready", + "solution":{ + "captcha_id":"e392e1d7fd421dc63325744d5a2b9c73", + "lot_number":"e6c3bed2854f41f880662c48afff5dcb", + "pass_token":"fad5eb52fc83bf7617402fcccfb211a21e0aa1d1044", + "gen_time":"1693924478", + "captcha_output":"fN36ufW6cQN4SQ-JRDQC70nSq9UcQBg==" }, - "taskId": 73052314114, - "error": False, - "errorBody": None + "cost":"0.00299", + "ip":"1.2.3.4", + "createTime":1692863536, + "endTime":1692863556, + "solveCount":1, + "taskId":75190409731 } >>> GeeTest(rucaptcha_key="aa9011f31111181111168611f1151122", - ... captcha_id="e392e1d7fd421dc63325744d5a2b9c73", - ... pageurl="https://rucaptcha.com/demo/geetest-v4", - ... method=GeetestEnm.GEETEST_V4.value, - ... ).captcha_handler() + ... websiteURL="https://rucaptcha.com/demo/geetest-v4", + ... method=GeetestEnm.GeeTestTaskProxyless.value, + ... version=4, + ... initParameters={"captcha_id": "e392e1d7fd421dc63325744d5a2b9c73"}, + ... ).captcha_handler(challenge=resp_data["challenge"]) { - "captchaSolve": { - "captcha_id": "e39....73", - "lot_number": "1b....bd2", - "pass_token": "f3b....de7f", - "gen_time": "1678558017", - "captcha_output": "c3rHzKl....TE=", - }, - "taskId": 73052314114, - "error": False, - "errorBody": "None", + "errorId":0, + "status":"ready", + "solution":{ + "captcha_id":"e392e1d7fd421dc63325744d5a2b9c73", + "lot_number":"e6c3bed2854f41f880662c48afff5dcb", + "pass_token":"fad5eb52fc83bf7617402fcccfb211a21e0aa1d1044", + "gen_time":"1693924478", + "captcha_output":"fN36ufW6cQN4SQ-JRDQC70nSq9UcQBg==" + }, + "cost":"0.00299", + "ip":"1.2.3.4", + "createTime":1692863536, + "endTime":1692863556, + "solveCount":1, + "taskId":75190409731 } >>> await GeeTest(rucaptcha_key="aa9011f31111181111168611f1151122", - ... captcha_id="e392e1d7fd421dc63325744d5a2b9c73", - ... pageurl="https://rucaptcha.com/demo/geetest-v4", - ... method=GeetestEnm.GEETEST_V4.value, - ... ).aio_captcha_handler() + ... websiteURL="https://rucaptcha.com/demo/geetest-v4", + ... method=GeetestEnm.GeeTestTaskProxyless.value, + ... version=4, + ... initParameters={"captcha_id": "e392e1d7fd421dc63325744d5a2b9c73"}, + ... ).aio_captcha_handler(challenge=resp_data["challenge"]) { - "captchaSolve": { - "captcha_id": "e39....73", - "lot_number": "1b....bd2", - "pass_token": "f3b....de7f", - "gen_time": "1678558017", - "captcha_output": "c3r....TE=", - }, - "taskId": 73052314114, - "error": False, - "errorBody": "None", + "errorId":0, + "status":"ready", + "solution":{ + "captcha_id":"e392e1d7fd421dc63325744d5a2b9c73", + "lot_number":"e6c3bed2854f41f880662c48afff5dcb", + "pass_token":"fad5eb52fc83bf7617402fcccfb211a21e0aa1d1044", + "gen_time":"1693924478", + "captcha_output":"fN36ufW6cQN4SQ-JRDQC70nSq9UcQBg==" + }, + "cost":"0.00299", + "ip":"1.2.3.4", + "createTime":1692863536, + "endTime":1692863556, + "solveCount":1, + "taskId":75190409731 } + >>> GeeTest(rucaptcha_key="aa9011f31111181111168611f1151122", + ... gt=resp_data["gt"], + ... websiteURL="https://www.geetest.com/en/demo", + ... method=GeetestEnm.GeeTestTaskProxyless.value, + ... userAgent="Some specific user agent", + ... proxyType="socks5", + ... proxyAddress="0.0.0.0", + ... proxyPort=443, + ... ).captcha_handler(challenge=resp_data["challenge"]) + { + "errorId":0, + "status":"ready", + "solution":{ + "captcha_id":"e392e1d7fd421dc63325744d5a2b9c73", + "lot_number":"e6c3bed2854f41f880662c48afff5dcb", + "pass_token":"fad5eb52fc83bf7617402fcccfb211a21e0aa1d1044", + "gen_time":"1693924478", + "captcha_output":"fN36ufW6cQN4SQ-JRDQC70nSq9UcQBg==" + }, + "cost":"0.00299", + "ip":"1.2.3.4", + "createTime":1692863536, + "endTime":1692863556, + "solveCount":1, + "taskId":75190409731 + } Returns: Dict with full server response Notes: - https://rucaptcha.com/api-rucaptcha#solving_geetest - https://rucaptcha.com/api-rucaptcha#geetest-v4 + https://rucaptcha.com/api-docs/geetest """ self.method = method super().__init__(method=self.method, *args, **kwargs) @@ -130,14 +171,16 @@ def __init__( raise ValueError(f"Invalid method parameter set, available - {GeetestEnm.list_values()}") # insert `gt` param to payload - self.post_payload.update({"gt": gt, "pageurl": pageurl, "captcha_id": captcha_id}) - - if self.method == GeetestEnm.GEETEST_V4.value and captcha_id is None: - raise ValueError(f"For {self.method} captcha_id is required") - elif self.method == GeetestEnm.GEETEST.value and gt is None: - raise ValueError(f"For {self.method} gt is required") + self.create_task_payload["task"].update( + { + "websiteURL": websiteURL, + "gt": gt, + "version": version, + "initParameters": initParameters, + } + ) - def captcha_handler(self, challenge: Optional[str] = None, **kwargs) -> dict: + def captcha_handler(self, challenge: str, **kwargs) -> dict: """ Sync solving method @@ -145,110 +188,36 @@ def captcha_handler(self, challenge: Optional[str] = None, **kwargs) -> dict: challenge: The value of the challenge parameter found on the site kwargs: Parameters for the `requests` library - Examples: - >>> GeeTest(rucaptcha_key="aa9011f31111181111168611f1151122", - ... gt="022397c99c9f646f6477822485f30404", - ... pageurl="https://rucaptcha.com/demo/geetest", - ... method=GeetestEnm.GEETEST.value, - ... api_server="api.geetest.com", - ... ).captcha_handler(challenge="537b31c6ff5d2bcfa9d1b75e099edcb2") - { - "captchaSolve": { - "geetest_challenge": "1ad03db8aff920037fb8117827eab171gu", - "geetest_validate": "011309d29dab6e98e8fc3784a95469cc", - "geetest_seccode": "011309d29dab6e98e8fc3784a95469cc|jordan" - }, - "taskId": 73052314114, - "error": False, - "errorBody": None - } - - >>> GeeTest(rucaptcha_key="aa9011f31111181111168611f1151122", - ... captcha_id="e392e1d7fd421dc63325744d5a2b9c73", - ... pageurl="https://rucaptcha.com/demo/geetest-v4", - ... method=GeetestEnm.GEETEST_V4.value, - ... ).captcha_handler() - { - "captchaSolve": { - "captcha_id": "e39....73", - "lot_number": "1b....bd2", - "pass_token": "f3b....de7f", - "gen_time": "1678558017", - "captcha_output": "c3rHzKl....TE=", - }, - "taskId": 73052314114, - "error": False, - "errorBody": "None", - } - Returns: Dict with full server response Notes: - https://rucaptcha.com/api-rucaptcha#solving_geetest - https://rucaptcha.com/api-rucaptcha#geetest-v4 + Check class docstirng for more info """ - if self.method == GeetestEnm.GEETEST.value: + if self.method == GeetestEnm.GeeTestTaskProxyless.value: if challenge is not None: - self.post_payload.update({"challenge": challenge}) + self.create_task_payload["task"].update({"challenge": challenge}) else: raise ValueError(f"For {self.method} challenge is required") return self._processing_response(**kwargs) - async def aio_captcha_handler(self, challenge: Optional[str] = None) -> dict: + async def aio_captcha_handler(self, challenge: str) -> dict: """ Async solving method Args: challenge: The value of the challenge parameter found on the site - Examples: - >>> await GeeTest(rucaptcha_key="aa9011f31111181111168611f1151122", - ... gt="022397c99c9f646f6477822485f30404", - ... pageurl="https://rucaptcha.com/demo/geetest", - ... method=GeetestEnm.GEETEST.value, - ... api_server="api.geetest.com", - ... ).aio_captcha_handler(challenge="537b31c6ff5d2bcfa9d1b75e099edcb2") - { - "captchaSolve": { - "geetest_challenge": "1ad03db8aff920037fb8117827eab171gu", - "geetest_validate": "011309d29dab6e98e8fc3784a95469cc", - "geetest_seccode": "011309d29dab6e98e8fc3784a95469cc|jordan" - }, - "taskId": 73052314114, - "error": False, - "errorBody": None - } - - >>> await GeeTest(rucaptcha_key="aa9011f31111181111168611f1151122", - ... captcha_id="e392e1d7fd421dc63325744d5a2b9c73", - ... pageurl="https://rucaptcha.com/demo/geetest-v4", - ... method=GeetestEnm.GEETEST_V4.value, - ... ).aio_captcha_handler() - { - "captchaSolve": { - "captcha_id": "e39....73", - "lot_number": "1b....bd2", - "pass_token": "f3b....de7f", - "gen_time": "1678558017", - "captcha_output": "c3rHzKl....TE=", - }, - "taskId": 73052314114, - "error": False, - "errorBody": "None", - } - Returns: Dict with full server response Notes: - https://rucaptcha.com/api-rucaptcha#solving_geetest - https://rucaptcha.com/api-rucaptcha#geetest-v4 + Check class docstirng for more info """ - if self.method == GeetestEnm.GEETEST.value: + if self.method == GeetestEnm.GeeTestTaskProxyless.value: if challenge is not None: - self.post_payload.update({"challenge": challenge}) + self.create_task_payload["task"].update({"challenge": challenge}) else: raise ValueError(f"For {self.method} challenge is required") diff --git a/src/python_rucaptcha/hcaptcha.py b/src/python_rucaptcha/hcaptcha.py index 9cdd361c..25aadb8c 100644 --- a/src/python_rucaptcha/hcaptcha.py +++ b/src/python_rucaptcha/hcaptcha.py @@ -1,3 +1,5 @@ +from typing import Union + from .core.base import BaseCaptcha from .core.enums import HCaptchaEnm @@ -5,9 +7,9 @@ class HCaptcha(BaseCaptcha): def __init__( self, - sitekey: str, - pageurl: str, - method: str = HCaptchaEnm.HCAPTCHA.value, + websiteURL: str, + websiteKey: str, + method: Union[str, HCaptchaEnm] = HCaptchaEnm.HCaptchaTaskProxyless, *args, **kwargs, ): @@ -16,98 +18,77 @@ def __init__( Args: rucaptcha_key: User API key - sitekey: The value of the `data-sitekey` parameter found on the site - pageurl: Full URL of the captcha page + websiteURL: Full URL of the captcha page + websiteKey: The value of the `data-sitekey` parameter found on the site method: Captcha type kwargs: Not required params for task creation request Examples: >>> HCaptcha(rucaptcha_key="aa9011f31111181111168611f1151122", - ... sitekey="3ceb8624-1970-4e6b-91d5-70317b70b651", - ... pageurl="https://rucaptcha.com/demo/hcaptcha", - ... method=HCaptchaEnm.HCAPTCHA.value + ... websiteKey="3ceb8624-1970-4e6b-91d5-70317b70b651", + ... websiteURL="https://rucaptcha.com/demo/hcaptcha", + ... method=HCaptchaEnm.HCaptchaTaskProxyless.value ... ).captcha_handler() { - "captchaSolve": "P1_eyJ.....cp_J", - "taskId": 73052314114, - "error": False, - "errorBody": None + "errorId":0, + "status":"ready", + "solution":{ + "token":"P1_eyJ0eXAiOiJKV...1LDq89KyJ5A", + "respKey":"E0_eyJ0eXAiOiJK...y2w5_YbP8PGuJBBo", + "userAgent":"Mozilla/5.0 (.......", + "gRecaptchaResponse":"P1_eyJ0eXAiOiJKV...1LDq89KyJ5A" + }, + "cost":"0.00299", + "ip":"1.2.3.4", + "createTime":1692863536, + "endTime":1692863556, + "solveCount":1, + "taskId": 73243152973, } >>> await HCaptcha(rucaptcha_key="aa9011f31111181111168611f1151122", - ... sitekey="3ceb8624-1970-4e6b-91d5-70317b70b651", - ... pageurl="https://rucaptcha.com/demo/hcaptcha", - ... method=HCaptchaEnm.HCAPTCHA.value + ... websiteKey="3ceb8624-1970-4e6b-91d5-70317b70b651", + ... websiteURL="https://rucaptcha.com/demo/hcaptcha", + ... method=HCaptchaEnm.HCaptchaTaskProxyless.value ... ).aio_captcha_handler() { - "captchaSolve": "P1_eyJ.....cp_J", - "taskId": 73052314114, - "error": False, - "errorBody": None - } - - DeathByCaptcha: - - >>> HCaptcha(rucaptcha_key="some_username:some_password", - ... service_type="deathbycaptcha", - ... sitekey="3ceb8624-1970-4e6b-91d5-70317b70b651", - ... pageurl="https://rucaptcha.com/demo/hcaptcha", - ... method=HCaptchaEnm.HCAPTCHA.value - ... ).captcha_handler() - { - 'captchaSolve': '03A....8h', - 'taskId': '73043008354', - 'error': False, - 'errorBody': None - } - - >>> await HCaptcha(rucaptcha_key="some_username:some_password", - ... service_type="deathbycaptcha", - ... sitekey="3ceb8624-1970-4e6b-91d5-70317b70b651", - ... pageurl="https://rucaptcha.com/demo/hcaptcha", - ... method=HCaptchaEnm.HCAPTCHA.value - ... ).aio_captcha_handler() - { - 'captchaSolve': '03A....8h', - 'taskId': '73043008354', - 'error': False, - 'errorBody': None + "errorId":0, + "status":"ready", + "solution":{ + "token":"P1_eyJ0eXAiOiJKV...1LDq89KyJ5A", + "respKey":"E0_eyJ0eXAiOiJK...y2w5_YbP8PGuJBBo", + "userAgent":"Mozilla/5.0 (........", + "gRecaptchaResponse":"P1_eyJ0eXAiOiJKV...1LDq89KyJ5A" + }, + "cost":"0.00299", + "ip":"1.2.3.4", + "createTime":1692863536, + "endTime":1692863556, + "solveCount":1, + "taskId": 73243152973, } Returns: Dict with full server response Notes: - https://rucaptcha.com/api-rucaptcha#solving_hcaptcha + https://rucaptcha.com/api-docs/hcaptcha """ super().__init__(method=method, *args, **kwargs) - self.post_payload.update({"pageurl": pageurl, "sitekey": sitekey}) + self.create_task_payload["task"].update({"websiteURL": websiteURL, "websiteKey": websiteKey}) # check user params if method not in HCaptchaEnm.list_values(): raise ValueError(f"Invalid method parameter set, available - {HCaptchaEnm.list_values()}") - def captcha_handler(self, **kwargs): + def captcha_handler(self, **kwargs) -> dict: """ Sync solving method Args: kwargs: Parameters for the `requests` library - Examples: - >>> HCaptcha(rucaptcha_key="aa9011f31111181111168611f1151122", - ... sitekey="3ceb8624-1970-4e6b-91d5-70317b70b651", - ... pageurl="https://rucaptcha.com/demo/hcaptcha", - ... method=HCaptchaEnm.HCAPTCHA.value - ... ).captcha_handler() - { - "captchaSolve": "P1_eyJ.....cp_J", - "taskId": 73052314114, - "error": False, - "errorBody": None - } - Returns: Dict with full server response @@ -117,23 +98,10 @@ def captcha_handler(self, **kwargs): return self._processing_response(**kwargs) - async def aio_captcha_handler(self): + async def aio_captcha_handler(self) -> dict: """ Async solving method - Examples: - >>> await HCaptcha(rucaptcha_key="aa9011f31111181111168611f1151122", - ... sitekey="3ceb8624-1970-4e6b-91d5-70317b70b651", - ... pageurl="https://rucaptcha.com/demo/hcaptcha", - ... method=HCaptchaEnm.HCAPTCHA.value - ... ).aio_captcha_handler() - { - "captchaSolve": "P1_eyJ.....cp_J", - "taskId": 73052314114, - "error": False, - "errorBody": None - } - Returns: Dict with full server response diff --git a/src/python_rucaptcha/image_captcha.py b/src/python_rucaptcha/image_captcha.py index 65f4a55a..7f78bb92 100644 --- a/src/python_rucaptcha/image_captcha.py +++ b/src/python_rucaptcha/image_captcha.py @@ -1,6 +1,5 @@ -import base64 import shutil -from typing import Optional +from typing import Union, Optional from .core.base import BaseCaptcha from .core.enums import SaveFormatsEnm, ImageCaptchaEnm @@ -9,7 +8,7 @@ class ImageCaptcha(BaseCaptcha): def __init__( self, - save_format: str = SaveFormatsEnm.TEMP.value, + save_format: Union[str, SaveFormatsEnm] = SaveFormatsEnm.TEMP, img_clearing: bool = True, img_path: str = "PythonRuCaptchaImages", *args, @@ -24,24 +23,39 @@ def __init__( or as a regular image to a folder created by the library - 'const'. img_clearing: True - delete file after solution, False - don't delete file after solution img_path: Folder to save captcha images + kwargs: Additional not required params for this captcha type Examples: >>> ImageCaptcha(rucaptcha_key="aa9011f31111181111168611f1151122", ... ).captcha_handler(captcha_link="https://rucaptcha.com/dist/web/99581b9d446a509a0a01954438a5e36a.jpg") { - 'captchaSolve': 'W9H5K', - 'taskId': '73043008354', - 'error': False, - 'errorBody': None + "errorId":0, + "status":"ready", + "solution":{ + "text":"w9h5k" + }, + "cost":0.033, + "ip":"46.53.241.91", + "createTime":1696730723, + "endTime":1696730723, + "solveCount":1, + "taskId":74708110322 } >>> ImageCaptcha(rucaptcha_key="aa9011f31111181111168611f1151122", ... ).captcha_handler(captcha_file="src/examples/088636.png") { - 'captchaSolve': '088636', - 'taskId': '73043008354', - 'error': False, - 'errorBody': None + "errorId":0, + "status":"ready", + "solution":{ + "text":"w9h5k" + }, + "cost":0.033, + "ip":"46.53.241.91", + "createTime":1696730723, + "endTime":1696730723, + "solveCount":1, + "taskId":74708110322 } >>> with open("src/examples/088636.png", "rb") as f: @@ -49,50 +63,85 @@ def __init__( >>> ImageCaptcha(rucaptcha_key="aa9011f31111181111168611f1151122" ... ).captcha_handler(captcha_base64=file_data) { - 'captchaSolve': 'W9H5K', - 'taskId': 73243152973, - 'error': False, - 'errorBody': None + "errorId":0, + "status":"ready", + "solution":{ + "text":"w9h5k" + }, + "cost":0.033, + "ip":"46.53.241.91", + "createTime":1696730723, + "endTime":1696730723, + "solveCount":1, + "taskId":74708110322 } >>> await ImageCaptcha(rucaptcha_key="aa9011f31111181111168611f1151122", ... ).aio_captcha_handler(captcha_link="https://rucaptcha.com/dist/web/99581b9d446a509a0a01954438a5e36a.jpg") { - 'captchaSolve': 'W9H5K', - 'taskId': '73043008354', - 'error': False, - 'errorBody': None + "errorId":0, + "status":"ready", + "solution":{ + "text":"w9h5k" + }, + "cost":0.033, + "ip":"46.53.241.91", + "createTime":1696730723, + "endTime":1696730723, + "solveCount":1, + "taskId":74708110322 } >>> await ImageCaptcha(rucaptcha_key="aa9011f31111181111168611f1151122", ... ).aio_captcha_handler(captcha_file="src/examples/088636.png") { - 'captchaSolve': '088636', - 'taskId': '73043008354', - 'error': False, - 'errorBody': None + "errorId":0, + "status":"ready", + "solution":{ + "text":"w9h5k" + }, + "cost":0.033, + "ip":"46.53.241.91", + "createTime":1696730723, + "endTime":1696730723, + "solveCount":1, + "taskId":74708110322 } - Death yCaptcha + Death Captcha >>> ImageCaptcha(rucaptcha_key="some_username:some_password", ... service_type="deathbycaptcha" ... ).captcha_handler(captcha_file="src/examples/088636.jpg") { - 'captchaSolve': '03A....8h', - 'taskId': '73043008354', - 'error': False, - 'errorBody': None + "errorId":0, + "status":"ready", + "solution":{ + "text":"w9h5k" + }, + "cost":0.033, + "ip":"46.53.241.91", + "createTime":1696730723, + "endTime":1696730723, + "solveCount":1, + "taskId":74708110322 } >>> await ImageCaptcha(rucaptcha_key="some_username:some_password", ... service_type="deathbycaptcha" ... ).aio_captcha_handler(captcha_link="https://rucaptcha.com/dist/web/99581b9d446a509a0a01954438a5e36a.jpg") { - 'captchaSolve': '03A....8h', - 'taskId': '73043008354', - 'error': False, - 'errorBody': None + "errorId":0, + "status":"ready", + "solution":{ + "text":"w9h5k" + }, + "cost":0.033, + "ip":"46.53.241.91", + "createTime":1696730723, + "endTime":1696730723, + "solveCount":1, + "taskId":74708110322 } >>> with open("src/examples/088636.png", "rb") as f: @@ -100,19 +149,29 @@ def __init__( >>> await ImageCaptcha(rucaptcha_key="aa9011f31111181111168611f1151122" ... ).aio_captcha_handler(captcha_base64=file_data) { - 'captchaSolve': 'W9H5K', - 'taskId': 73243152973, - 'error': False, - 'errorBody': None + "errorId":0, + "status":"ready", + "solution":{ + "text":"w9h5k" + }, + "cost":0.033, + "ip":"46.53.241.91", + "createTime":1696730723, + "endTime":1696730723, + "solveCount":1, + "taskId":74708110322 } Returns: Dict with full server response Notes: - https://rucaptcha.com/api-rucaptcha#solving_normal_captcha + https://2captcha.com/api-docs/normal-captcha + + https://rucaptcha.com/api-docs/normal-captcha """ - super().__init__(method=ImageCaptchaEnm.BASE64.value, *args, **kwargs) + super().__init__(method=ImageCaptchaEnm.ImageToTextTask.value, *args, **kwargs) + self.save_format = save_format self.img_clearing = img_clearing self.img_path = img_path @@ -133,58 +192,23 @@ def captcha_handler( captcha_base64: Captcha image BASE64 info kwargs: additional params for `requests` library - Examples: - >>> ImageCaptcha(rucaptcha_key="aa9011f31111181111168611f1151122", - ... ).captcha_handler(captcha_link="https://rucaptcha.com/dist/web/99581b9d446a509a0a01954438a5e36a.jpg") - { - 'captchaSolve': 'W9H5K', - 'taskId': '73043008354', - 'error': False, - 'errorBody': None - } - - >>> ImageCaptcha(rucaptcha_key="aa9011f31111181111168611f1151122", - ... ).captcha_handler(captcha_file="src/examples/088636.png") - { - 'captchaSolve': '088636', - 'taskId': '73043008354', - 'error': False, - 'errorBody': None - } - Returns: Dict with full server response Notes: Check class docstirng for more info """ - # if a local file link is passed - if captcha_file: - self.post_payload.update({"body": base64.b64encode(self._local_file_captcha(captcha_file)).decode("utf-8")}) - # if the file is transferred in base64 encoding - elif captcha_base64: - self.post_payload.update({"body": base64.b64encode(captcha_base64).decode("utf-8")}) - # if a URL is passed - elif captcha_link: - try: - content = self.url_open(url=captcha_link, **kwargs).content - except Exception as error: - self.result.error = True - self.result.errorBody = str(error) - return self.result.dict() - - # according to the value of the passed parameter, select the function to save the image - if self.save_format == SaveFormatsEnm.CONST.value: - self._file_const_saver(content, self.img_path) - self.post_payload.update({"body": base64.b64encode(content).decode("utf-8")}) - - else: - # if none of the parameters are passed - self.result.error = True - self.result.errorBody = self.NO_CAPTCHA_ERR - return self.result.dict() - - return self._processing_response(**kwargs) + self._body_file_processing( + save_format=self.save_format, + file_path=self.img_path, + captcha_link=captcha_link, + captcha_file=captcha_file, + captcha_base64=captcha_base64, + **kwargs, + ) + if not self.result.errorId: + return self._processing_response(**kwargs) + return self.result.to_dict() async def aio_captcha_handler( self, @@ -202,93 +226,24 @@ async def aio_captcha_handler( captcha_base64: Captcha image BASE64 info kwargs: additional params for `aiohttp` library - Examples: - >>> await ImageCaptcha(rucaptcha_key="aa9011f31111181111168611f1151122", - ... ).aio_captcha_handler(captcha_link="https://rucaptcha.com/dist/web/99581b9d446a509a0a01954438a5e36a.jpg") - { - 'captchaSolve': 'W9H5K', - 'taskId': '73043008354', - 'error': False, - 'errorBody': None - } - - >>> await ImageCaptcha(rucaptcha_key="aa9011f31111181111168611f1151122", - ... ).aio_captcha_handler(captcha_file="src/examples/088636.png") - { - 'captchaSolve': '088636', - 'taskId': '73043008354', - 'error': False, - 'errorBody': None - } - Returns: Dict with full server response Notes: Check class docstirng for more info """ - # if a local file link is passed - if captcha_file: - self.post_payload.update({"body": base64.b64encode(self._local_file_captcha(captcha_file)).decode("utf-8")}) - # if the file is transferred in base64 encoding - elif captcha_base64: - self.post_payload.update({"body": base64.b64encode(captcha_base64).decode("utf-8")}) - # if a URL is passed - elif captcha_link: - try: - content = await self.aio_url_read(url=captcha_link, **kwargs) - except Exception as error: - self.result.error = True - self.result.errorBody = str(error) - return self.result.dict() - - # according to the value of the passed parameter, select the function to save the image - if self.save_format == SaveFormatsEnm.CONST.value: - self._file_const_saver(content, self.img_path) - self.post_payload.update({"body": base64.b64encode(content).decode("utf-8")}) - - else: - # if none of the parameters are passed - self.result.error = True - self.result.errorBody = self.NO_CAPTCHA_ERR - return self.result.dict() - - return await self._aio_processing_response() + await self._aio_body_file_processing( + save_format=self.save_format, + file_path=self.img_path, + captcha_link=captcha_link, + captcha_file=captcha_file, + captcha_base64=captcha_base64, + **kwargs, + ) + if not self.result.errorId: + return await self._aio_processing_response() + return self.result.to_dict() def __del__(self): if self.save_format == SaveFormatsEnm.CONST.value and self.img_clearing: shutil.rmtree(self.img_path) - - -''' -class sockNormalCaptcha(WebSocketRuCaptcha): - """ - Class for ImageCaptcha - """ - - def __init__(self, rucaptcha_key: str, allSessions: bool = None, suppressSuccess: bool = None): - """ - Method setup WebSocket connection data - """ - super().__init__(allSessions, suppressSuccess) - self.rucaptcha_key = rucaptcha_key - - async def captcha_handler(self, captcha_image_base64: str, **kwargs) -> dict: - """ - The asynchronous WebSocket method return account balance. - More info - https://wsrucaptcha.docs.apiary.io/#reference/text-captcha - :param captcha_image_base64: Image captcha base64 data in string format (decoded in utf-8) - :param kwargs: Options variables - :return: Server response dict - """ - normal_captcha_payload = NormalCaptchaSocketSer( - **{ - "method": "normal", - "requestId": str(uuid4()), - "body": captcha_image_base64, - "options": CaptchaOptionsSocketSer(**kwargs), - } - ) - - return await self.send_request(normal_captcha_payload.dict()) -''' diff --git a/src/python_rucaptcha/key_captcha.py b/src/python_rucaptcha/key_captcha.py index 2db08377..28a31d1d 100644 --- a/src/python_rucaptcha/key_captcha.py +++ b/src/python_rucaptcha/key_captcha.py @@ -1,3 +1,5 @@ +from typing import Union + from .core.base import BaseCaptcha from .core.enums import KeyCaptchaEnm @@ -5,12 +7,12 @@ class KeyCaptcha(BaseCaptcha): def __init__( self, - pageurl: str, + websiteURL: str, s_s_c_user_id: str, s_s_c_session_id: str, s_s_c_web_server_sign: str, s_s_c_web_server_sign2: str, - method: str = KeyCaptchaEnm.KEYCAPTCHA.value, + method: Union[str, KeyCaptchaEnm] = KeyCaptchaEnm.KeyCaptchaTaskProxyless, *args, **kwargs, ): @@ -19,7 +21,7 @@ def __init__( Args: rucaptcha_key: User API key - pageurl: Full URL of the captcha page + websiteURL: Full URL of the captcha page s_s_c_user_id: Value of `s_s_c_user_id` parameter found on the page s_s_c_session_id: Value of `s_s_c_session_id` parameter found on the page s_s_c_web_server_sign: Value of `s_s_c_web_server_sign` parameter found on the page @@ -34,7 +36,7 @@ def __init__( ... s_s_c_session_id="0917788cad24ad3a69813c4fcd556061", ... s_s_c_web_server_sign="02f7f9669f1269595c4c69bcd4a3c52e", ... s_s_c_web_server_sign2="d888700f6f324ec0f32b44c32c50bde1", - ... method=KeyCaptchaEnm.KEYCAPTCHA.value + ... method=KeyCaptchaEnm.KeyCaptchaTaskProxyless.value ... ).captcha_handler() { "captchaSolve": "d58....61|1", @@ -49,7 +51,7 @@ def __init__( ... s_s_c_session_id="0917788cad24ad3a69813c4fcd556061", ... s_s_c_web_server_sign="02f7f9669f1269595c4c69bcd4a3c52e", ... s_s_c_web_server_sign2="d888700f6f324ec0f32b44c32c50bde1", - ... method=KeyCaptchaEnm.KEYCAPTCHA.value + ... method=KeyCaptchaEnm.KeyCaptchaTaskProxyless.value ... ).aio_captcha_handler() { "captchaSolve": "P1_eyJ.....cp_J", @@ -62,13 +64,13 @@ def __init__( Dict with full server response Notes: - https://rucaptcha.com/api-rucaptcha#solving_keycaptcha + https://rucaptcha.com/api-docs/keycaptcha """ super().__init__(method=method, *args, **kwargs) - self.post_payload.update( + self.create_task_payload["task"].update( { - "pageurl": pageurl, + "websiteURL": websiteURL, "s_s_c_user_id": s_s_c_user_id, "s_s_c_session_id": s_s_c_session_id, "s_s_c_web_server_sign": s_s_c_web_server_sign, @@ -80,56 +82,30 @@ def __init__( if method not in KeyCaptchaEnm.list_values(): raise ValueError(f"Invalid method parameter set, available - {KeyCaptchaEnm.list_values()}") - def captcha_handler(self, **kwargs): + def captcha_handler(self, **kwargs) -> dict: """ Sync solving method Args: kwargs: Parameters for the `requests` library - Examples: - >>> KeyCaptcha(rucaptcha_key="aa9011f31111181111168611f1151122", - ... sitekey="3ceb8624-1970-4e6b-91d5-70317b70b651", - ... pageurl="https://rucaptcha.com/demo/hcaptcha", - ... method=KeyCaptchaEnm.KEYCAPTCHA.value - ... ).captcha_handler() - { - "captchaSolve": "P1_eyJ.....cp_J", - "taskId": 73052314114, - "error": False, - "errorBody": None - } - Returns: Dict with full server response Notes: - https://rucaptcha.com/api-rucaptcha#solving_hcaptcha + Check class docstirng for more info """ return self._processing_response(**kwargs) - async def aio_captcha_handler(self): + async def aio_captcha_handler(self) -> dict: """ Async solving method - Examples: - >>> KeyCaptcha(rucaptcha_key="aa9011f31111181111168611f1151122", - ... sitekey="3ceb8624-1970-4e6b-91d5-70317b70b651", - ... pageurl="https://rucaptcha.com/demo/hcaptcha", - ... method=KeyCaptchaEnm.KEYCAPTCHA.value - ... ).captcha_handler() - { - "captchaSolve": "P1_eyJ.....cp_J", - "taskId": 73052314114, - "error": False, - "errorBody": None - } - Returns: Dict with full server response Notes: - https://rucaptcha.com/api-rucaptcha#solving_hcaptcha + Check class docstirng for more info """ return await self._aio_processing_response() diff --git a/src/python_rucaptcha/lemin_captcha.py b/src/python_rucaptcha/lemin_captcha.py new file mode 100644 index 00000000..0c637db9 --- /dev/null +++ b/src/python_rucaptcha/lemin_captcha.py @@ -0,0 +1,112 @@ +from typing import Union + +from .core.base import BaseCaptcha +from .core.enums import LeminCaptchaEnm + + +class LeminCaptcha(BaseCaptcha): + def __init__( + self, + websiteURL: str, + captchaId: str, + div_id: str, + method: Union[str, LeminCaptchaEnm] = LeminCaptchaEnm.LeminTaskProxyless, + *args, + **kwargs, + ): + """ + The class is used to work with Lemin Cropped Captcha. + + Args: + rucaptcha_key: User API key + websiteURL: Full URL of the captcha page + captchaId: The value of the `captcha_id` parameter found on the site + div_id: The `id` of the parent `div`, which contains the captcha + method: Captcha type + kwargs: Not required params for task creation request + + Examples: + >>> LeminCaptcha(rucaptcha_key="aa9011f31111181111168611f1151122", + ... websiteURL="https://dashboard.leminnow.com/auth/signup", + ... captchaId="CROPPED_099216d_8ba061383fa24ef498115023aa7189d4", + ... div_id="lemin-cropped-captcha", + ... method=LeminCaptchaEnm.LeminTaskProxyless.value, + ... api_server="api.leminnow.com" + ... ).captcha_handler() + { + "errorId":0, + "status":"ready", + "solution":{ + "answer":"0xaxakx0xaxaax0xkxx3ox0x3ox3ox_...gAAAAABk8bgzEFOg9i3Jm", + "challenge_id":"e0348984-92ec-23af-1488-446e3a58946c" + }, + "cost":"0.00299", + "ip":"1.2.3.4", + "createTime":1692863536, + "endTime":1692863556, + "solveCount":1, + "taskId": 73243152973, + } + + >>> await LeminCaptcha(rucaptcha_key="aa9011f31111181111168611f1151122", + ... websiteURL="https://dashboard.leminnow.com/auth/signup", + ... captcha_id="CROPPED_099216d_8ba061383fa24ef498115023aa7189d4", + ... div_id="lemin-cropped-captcha", + ... method=LeminCaptchaEnm.LeminTaskProxyless.value, + ... api_server="api.leminnow.com" + ... ).aio_captcha_handler() + { + "errorId":0, + "status":"ready", + "solution":{ + "answer":"0xaxakx0xaxaax0xkxx3ox0x3ox3ox_...gAAAAABk8bgzEFOg9i3Jm", + "challenge_id":"e0348984-92ec-23af-1488-446e3a58946c" + }, + "cost":"0.00299", + "ip":"1.2.3.4", + "createTime":1692863536, + "endTime":1692863556, + "solveCount":1, + "taskId": 73243152973, + } + + Returns: + Dict with full server response + + Notes: + https://rucaptcha.com/api-docs/lemin + """ + super().__init__(method=method, *args, **kwargs) + + self.create_task_payload["task"].update({"websiteURL": websiteURL, "captchaId": captchaId, "div_id": div_id}) + + # check user params + if method not in LeminCaptchaEnm.list_values(): + raise ValueError(f"Invalid method parameter set, available - {LeminCaptchaEnm.list_values()}") + + def captcha_handler(self, **kwargs) -> dict: + """ + Sync solving method + + Args: + kwargs: Parameters for the `requests` library + + Returns: + Dict with full server response + + Notes: + Check class docstirng for more info + """ + return self._processing_response(**kwargs) + + async def aio_captcha_handler(self) -> dict: + """ + Async solving method + + Returns: + Dict with full server response + + Notes: + Check class docstirng for more info + """ + return await self._aio_processing_response() diff --git a/src/python_rucaptcha/lemin_cropped_captcha.py b/src/python_rucaptcha/lemin_cropped_captcha.py deleted file mode 100644 index cac3d3ba..00000000 --- a/src/python_rucaptcha/lemin_cropped_captcha.py +++ /dev/null @@ -1,136 +0,0 @@ -from .core.base import BaseCaptcha -from .core.enums import LeminCroppedCaptchaEnm - - -class LeminCroppedCaptcha(BaseCaptcha): - def __init__( - self, - pageurl: str, - captcha_id: str, - div_id: str, - method: str = LeminCroppedCaptchaEnm.LEMIN.value, - *args, - **kwargs, - ): - """ - The class is used to work with Lemin Cropped Captcha. - - Args: - rucaptcha_key: User API key - pageurl: Full URL of the captcha page - captcha_id: The value of the `captcha_id` parameter found on the site - div_id: The `id` of the parent `div`, which contains the captcha - method: Captcha type - kwargs: Not required params for task creation request - - Examples: - >>> LeminCroppedCaptcha(rucaptcha_key="aa9011f31111181111168611f1151122", - ... pageurl="https://dashboard.leminnow.com/auth/signup", - ... captcha_id="CROPPED_099216d_8ba061383fa24ef498115023aa7189d4", - ... div_id="lemin-cropped-captcha", - ... method=LeminCroppedCaptchaEnm.LEMIN.value, - ... api_server="api.leminnow.com" - ... ).captcha_handler() - { - "captchaSolve": { - "answer":"0xc....EUa", - "challenge_id":"58.....63a" - }, - "taskId": 73052314114, - "error": False, - "errorBody": None - } - - >>> await LeminCroppedCaptcha(rucaptcha_key="aa9011f31111181111168611f1151122", - ... pageurl="https://dashboard.leminnow.com/auth/signup", - ... captcha_id="CROPPED_099216d_8ba061383fa24ef498115023aa7189d4", - ... div_id="lemin-cropped-captcha", - ... method=LeminCroppedCaptchaEnm.LEMIN.value, - ... api_server="api.leminnow.com" - ... ).aio_captcha_handler() - { - "captchaSolve": { - "answer":"0xc....EUa", - "challenge_id":"58.....63a" - }, - "taskId": 73052314114, - "error": False, - "errorBody": None - } - - Returns: - Dict with full server response - - Notes: - https://rucaptcha.com/api-rucaptcha#lemin - """ - super().__init__(method=method, *args, **kwargs) - - self.post_payload.update({"pageurl": pageurl, "captcha_id": captcha_id, "div_id": div_id}) - - # check user params - if method not in LeminCroppedCaptchaEnm.list_values(): - raise ValueError(f"Invalid method parameter set, available - {LeminCroppedCaptchaEnm.list_values()}") - - def captcha_handler(self, **kwargs): - """ - Sync solving method - - Args: - kwargs: Parameters for the `requests` library - - Examples: - >>> LeminCroppedCaptcha(rucaptcha_key="aa9011f31111181111168611f1151122", - ... pageurl="https://dashboard.leminnow.com/auth/signup", - ... captcha_id="CROPPED_099216d_8ba061383fa24ef498115023aa7189d4", - ... div_id="lemin-cropped-captcha", - ... method=LeminCroppedCaptchaEnm.LEMIN.value, - ... api_server="api.leminnow.com" - ... ).captcha_handler() - { - "captchaSolve": { - "answer":"0xc....EUa", - "challenge_id":"58.....63a" - }, - "taskId": 73052314114, - "error": False, - "errorBody": None - } - - Returns: - Dict with full server response - - Notes: - https://rucaptcha.com/api-rucaptcha#lemin - """ - return self._processing_response(**kwargs) - - async def aio_captcha_handler(self): - """ - Async solving method - - Examples: - >>> LeminCroppedCaptcha(rucaptcha_key="aa9011f31111181111168611f1151122", - ... pageurl="https://dashboard.leminnow.com/auth/signup", - ... captcha_id="CROPPED_099216d_8ba061383fa24ef498115023aa7189d4", - ... div_id="lemin-cropped-captcha", - ... method=LeminCroppedCaptchaEnm.LEMIN.value, - ... api_server="api.leminnow.com" - ... ).captcha_handler() - { - "captchaSolve": { - "answer":"0xc....EUa", - "challenge_id":"58.....63a" - }, - "taskId": 73052314114, - "error": False, - "errorBody": None - } - - Returns: - Dict with full server response - - Notes: - https://rucaptcha.com/api-rucaptcha#lemin - """ - return await self._aio_processing_response() diff --git a/src/python_rucaptcha/re_captcha.py b/src/python_rucaptcha/re_captcha.py index ac27cc5c..2ecfbada 100644 --- a/src/python_rucaptcha/re_captcha.py +++ b/src/python_rucaptcha/re_captcha.py @@ -1,4 +1,4 @@ -from typing import Optional +from typing import Union from .core.base import BaseCaptcha from .core.enums import ReCaptchaEnm @@ -7,10 +7,10 @@ class ReCaptcha(BaseCaptcha): def __init__( self, - pageurl: str, - googlekey: str, - version: Optional[str] = None, - method: str = ReCaptchaEnm.USER_RECAPTCHA.value, + websiteURL: str, + websiteKey: str, + minScore: float = 0.3, + method: Union[str, ReCaptchaEnm] = ReCaptchaEnm.RecaptchaV2TaskProxyless.value, *args, **kwargs, ): @@ -19,157 +19,154 @@ def __init__( Args: rucaptcha_key: User API key - pageurl: Full URL of the captcha page - googlekey: The value of the `googlekey` parameter you found in the page code + websiteURL: Full URL of the captcha page + websiteKey: The value of the `data-sitekey` parameter you found in the page code version: `v3` - indicates that this is reCAPTCHA V3 method: Captcha type Examples: >>> ReCaptcha(rucaptcha_key="aa9011f31111181111168611f1151122", - ... pageurl="https://rucaptcha.com/demo/recaptcha-v2", - ... googlekey="6LeIxboZAAAAAFQy7d8GPzgRZu2bV0GwKS8ue_cH", - ... method=ReCaptchaEnm.USER_RECAPTCHA.value + ... websiteURL="https://rucaptcha.com/demo/recaptcha-v2", + ... websiteKey="6LeIxboZAAAAAFQy7d8GPzgRZu2bV0GwKS8ue_cH", + ... method=ReCaptchaEnm.RecaptchaV2TaskProxyless.value ... ).captcha_handler() { - 'captchaSolve': '03A....8h', - 'taskId': '73043008354', - 'error': False, - 'errorBody': None + "errorId":0, + "status":"ready", + "solution":{ + "gRecaptchaResponse":"03ADUVZw...UWxTAe6ncIa", + "token":"03ADUVZw...UWxTAe6ncIa" + }, + "cost":"0.00299", + "ip":"1.2.3.4", + "createTime":1692863536, + "endTime":1692863556, + "solveCount":1, + "taskId": 73043008354 } >>> ReCaptcha(rucaptcha_key="aa9011f31111181111168611f1151122", - ... pageurl="https://rucaptcha.com/demo/recaptcha-v2", - ... googlekey="6LeIxboZAAAAAFQy7d8GPzgRZu2bV0GwKS8ue_cH", - ... domain="google.com", - ... invisible=1, + ... websiteURL="https://rucaptcha.com/demo/recaptcha-v2", + ... websiteKey="6LeIxboZAAAAAFQy7d8GPzgRZu2bV0GwKS8ue_cH" ... ).captcha_handler() { - 'captchaSolve': '03A....8h', - 'taskId': '73043008354', - 'error': False, - 'errorBody': None + "errorId":0, + "status":"ready", + "solution":{ + "gRecaptchaResponse":"03ADUVZw...UWxTAe6ncIa", + "token":"03ADUVZw...UWxTAe6ncIa" + }, + "cost":"0.00299", + "ip":"1.2.3.4", + "createTime":1692863536, + "endTime":1692863556, + "solveCount":1, + "taskId": 73043008354 } >>> ReCaptcha(rucaptcha_key="aa9011f31111181111168611f1151122", - ... pageurl="https://rucaptcha.com/demo/recaptcha-v2", - ... googlekey="6LeIxboZAAAAAFQy7d8GPzgRZu2bV0GwKS8ue_cH", - ... version="v3", - ... action="verify", - ... min_score=0.2, + ... websiteURL="https://rucaptcha.com/demo/recaptcha-v2", + ... websiteKey="6LeIxboZAAAAAFQy7d8GPzgRZu2bV0GwKS8ue_cH", ... ).captcha_handler() { - 'captchaSolve': '03A....8h', - 'taskId': '73043008354', - 'error': False, - 'errorBody': None + "errorId":0, + "status":"ready", + "solution":{ + "gRecaptchaResponse":"03ADUVZw...UWxTAe6ncIa", + "token":"03ADUVZw...UWxTAe6ncIa" + }, + "cost":"0.00299", + "ip":"1.2.3.4", + "createTime":1692863536, + "endTime":1692863556, + "solveCount":1, + "taskId": 73043008354 } - >>> await ReCaptcha(rucaptcha_key="aa9011f31111181111168611f1151122", - ... pageurl="https://rucaptcha.com/demo/recaptcha-v2", - ... googlekey="6LeIxboZAAAAAFQy7d8GPzgRZu2bV0GwKS8ue_cH", - ... method=ReCaptchaEnm.USER_RECAPTCHA.value - ... ).aio_captcha_handler() - { - 'captchaSolve': '03A....8h', - 'taskId': '73043008354', - 'error': False, - 'errorBody': None - } - - DeathByCaptcha: - - >>> ReCaptcha(rucaptcha_key="some_username:some_password", - ... service_type="deathbycaptcha", - ... pageurl="https://rucaptcha.com/demo/recaptcha-v2", - ... googlekey="6LeIxboZAAAAAFQy7d8GPzgRZu2bV0GwKS8ue_cH", - ... method=ReCaptchaEnm.USER_RECAPTCHA.value + >>> ReCaptcha(rucaptcha_key="aa9011f31111181111168611f1151122", + ... websiteURL="https://rucaptcha.com/demo/recaptcha-v2", + ... websiteKey="6LeIxboZAAAAAFQy7d8GPzgRZu2bV0GwKS8ue_cH", + ... method=ReCaptchaEnm.RecaptchaV3TaskProxyless.value, + ... min_score=0.3, ... ).captcha_handler() { - 'captchaSolve': '03A....8h', - 'taskId': '73043008354', - 'error': False, - 'errorBody': None + "errorId":0, + "status":"ready", + "solution":{ + "gRecaptchaResponse":"03ADUVZw...UWxTAe6ncIa", + "token":"03ADUVZw...UWxTAe6ncIa" + }, + "cost":"0.00299", + "ip":"1.2.3.4", + "createTime":1692863536, + "endTime":1692863556, + "solveCount":1, + "taskId": 73043008354 } - >>> await ReCaptcha(rucaptcha_key="some_username:some_password", - ... service_type="deathbycaptcha", - ... pageurl="https://rucaptcha.com/demo/recaptcha-v2", - ... googlekey="6LeIxboZAAAAAFQy7d8GPzgRZu2bV0GwKS8ue_cH", - ... method=ReCaptchaEnm.USER_RECAPTCHA.value + >>> await ReCaptcha(rucaptcha_key="aa9011f31111181111168611f1151122", + ... websiteURL="https://rucaptcha.com/demo/recaptcha-v2", + ... websiteKey="6LeIxboZAAAAAFQy7d8GPzgRZu2bV0GwKS8ue_cH", + ... method=ReCaptchaEnm.RecaptchaV2TaskProxyless.value ... ).aio_captcha_handler() { - 'captchaSolve': '03A....8h', - 'taskId': '73043008354', - 'error': False, - 'errorBody': None + "errorId":0, + "status":"ready", + "solution":{ + "gRecaptchaResponse":"03ADUVZw...UWxTAe6ncIa", + "token":"03ADUVZw...UWxTAe6ncIa" + }, + "cost":"0.00299", + "ip":"1.2.3.4", + "createTime":1692863536, + "endTime":1692863556, + "solveCount":1, + "taskId": 73043008354 } Returns: Dict with full server response Notes: - https://rucaptcha.com/api-rucaptcha#solving_recaptchav2_new - https://rucaptcha.com/api-rucaptcha#invisible - https://rucaptcha.com/api-rucaptcha#solving_recaptchav3 - https://rucaptcha.com/api-rucaptcha#solving_recaptcha_enterprise + https://rucaptcha.com/api-docs/recaptcha-v2 + + https://rucaptcha.com/api-docs/recaptcha-v3 + + https://rucaptcha.com/api-docs/recaptcha-v2-enterprise """ super().__init__(method=method, *args, **kwargs) - self.post_payload.update({"googlekey": googlekey, "pageurl": pageurl, "version": version}) + self.create_task_payload["task"].update( + {"websiteURL": websiteURL, "websiteKey": websiteKey, "minScore": minScore} + ) # check user params if method not in ReCaptchaEnm.list_values(): raise ValueError(f"Invalid method parameter set, available - {ReCaptchaEnm.list_values()}") - def captcha_handler(self, **kwargs): + def captcha_handler(self, **kwargs) -> dict: """ Sync solving method Args: kwargs: additional params for `requests` library - Examples: - >>> ReCaptcha(rucaptcha_key="aa9011f31111181111168611f1151122", - ... pageurl="https://rucaptcha.com/demo/recaptcha-v2", - ... googlekey="6LeIxboZAAAAAFQy7d8GPzgRZu2bV0GwKS8ue_cH", - ... method=ReCaptchaEnm.USER_RECAPTCHA.value - ... ).captcha_handler() - { - 'captchaSolve': '03A....8h', - 'taskId': '73043008354', - 'error': False, - 'errorBody': None - } - Returns: Dict with full server response Notes: - https://rucaptcha.com/api-rucaptcha#solving_funcaptcha_new + Check class docstirng for more info """ return self._processing_response(**kwargs) - async def aio_captcha_handler(self): + async def aio_captcha_handler(self) -> dict: """ Async solving method - Examples: - >>> await ReCaptcha(rucaptcha_key="aa9011f31111181111168611f1151122", - ... pageurl="https://rucaptcha.com/demo/recaptcha-v2", - ... googlekey="6LeIxboZAAAAAFQy7d8GPzgRZu2bV0GwKS8ue_cH", - ... method=ReCaptchaEnm.USER_RECAPTCHA.value - ... ).aio_captcha_handler() - { - 'captchaSolve': '03A....8h', - 'taskId': '73043008354', - 'error': False, - 'errorBody': None - } - Returns: Dict with full server response Notes: - https://rucaptcha.com/api-rucaptcha#solving_funcaptcha_new + Check class docstirng for more info """ return await self._aio_processing_response() diff --git a/src/python_rucaptcha/rotate_captcha.py b/src/python_rucaptcha/rotate_captcha.py index f3f83603..25f2568d 100644 --- a/src/python_rucaptcha/rotate_captcha.py +++ b/src/python_rucaptcha/rotate_captcha.py @@ -1,17 +1,20 @@ -import base64 -from typing import Optional +import shutil +import logging +from typing import Union, Optional from .core.base import BaseCaptcha -from .core.enums import RotateCaptchaEnm +from .core.enums import SaveFormatsEnm, RotateCaptchaEnm class RotateCaptcha(BaseCaptcha): - """ - The class is used to work with RotateCaptcha - Solve description: - """ - - def __init__(self, method: str = RotateCaptchaEnm.ROTATECAPTCHA.value, *args, **kwargs): + def __init__( + self, + save_format: Union[str, SaveFormatsEnm] = SaveFormatsEnm.TEMP, + img_clearing: bool = True, + img_path: str = "PythonRotateCaptchaFiles", + *args, + **kwargs, + ): """ The class is used to work with Rotate Captcha. @@ -23,10 +26,17 @@ def __init__(self, method: str = RotateCaptchaEnm.ROTATECAPTCHA.value, *args, ** >>> RotateCaptcha(rucaptcha_key="aa9011f31111181111168611f1151122", ... ).captcha_handler(captcha_file="examples/rotate/rotate_ex.png") { - 'captchaSolve': '160', - 'taskId': '73043008354', - 'error': False, - 'errorBody': None + "errorId":0, + "status":"ready", + "solution":{ + "rotate":180 + }, + "cost":"0.0005", + "ip":"1.2.3.4", + "createTime":1692863536, + "endTime":1692863556, + "solveCount":1, + "taskId": 73043008354 } >>> with open("src/examples/rotate/rotate_ex.png", "rb") as f: @@ -34,28 +44,49 @@ def __init__(self, method: str = RotateCaptchaEnm.ROTATECAPTCHA.value, *args, ** >>> RotateCaptcha(rucaptcha_key="aa9011f31111181111168611f1151122" ... ).captcha_handler(captcha_base64=file_data) { - 'captchaSolve': '160', - 'taskId': 73243152973, - 'error': False, - 'errorBody': None + "errorId":0, + "status":"ready", + "solution":{ + "rotate":180 + }, + "cost":"0.0005", + "ip":"1.2.3.4", + "createTime":1692863536, + "endTime":1692863556, + "solveCount":1, + "taskId": 73043008354 } >>> await RotateCaptcha(rucaptcha_key="aa9011f31111181111168611f1151122", ... ).aio_captcha_handler(captcha_file="examples/rotate/rotate_ex.png") { - 'captchaSolve': '160', - 'taskId': '73043008354', - 'error': False, - 'errorBody': None + "errorId":0, + "status":"ready", + "solution":{ + "rotate":180 + }, + "cost":"0.0005", + "ip":"1.2.3.4", + "createTime":1692863536, + "endTime":1692863556, + "solveCount":1, + "taskId": 73043008354 } >>> await RotateCaptcha(rucaptcha_key="aa9011f31111181111168611f1151122", ... angle=45).aio_captcha_handler(captcha_file="examples/rotate/rotate_ex.png") { - 'captchaSolve': '125', - 'taskId': '73043008354', - 'error': False, - 'errorBody': None + "errorId":0, + "status":"ready", + "solution":{ + "rotate":90 + }, + "cost":"0.0005", + "ip":"1.2.3.4", + "createTime":1692863536, + "endTime":1692863556, + "solveCount":1, + "taskId": 73043008354 } >>> with open("src/examples/rotate/rotate_ex.png", "rb") as f: @@ -63,24 +94,30 @@ def __init__(self, method: str = RotateCaptchaEnm.ROTATECAPTCHA.value, *args, ** >>> await RotateCaptcha(rucaptcha_key="aa9011f31111181111168611f1151122" ... ).aio_captcha_handler(captcha_base64=file_data) { - 'captchaSolve': '160', - 'taskId': 73243152973, - 'error': False, - 'errorBody': None + "errorId":0, + "status":"ready", + "solution":{ + "rotate":180 + }, + "cost":"0.0005", + "ip":"1.2.3.4", + "createTime":1692863536, + "endTime":1692863556, + "solveCount":1, + "taskId": 73043008354 } - Returns: Dict with full server response Notes: - https://rucaptcha.com/api-rucaptcha#solving_rotatecaptcha + https://rucaptcha.com/api-docs/rotate """ - super().__init__(method=method, *args, **kwargs) + super().__init__(method=RotateCaptchaEnm.RotateTask, *args, **kwargs) - # check user params - if method not in RotateCaptchaEnm.list_values(): - raise ValueError(f"Invalid method parameter set, available - {RotateCaptchaEnm.list_values()}") + self.save_format = save_format + self.img_clearing = img_clearing + self.img_path = img_path def captcha_handler( self, @@ -98,45 +135,25 @@ def captcha_handler( captcha_base64: Captcha image BASE64 info kwargs: additional params for `requests` library - Examples: - >>> RotateCaptcha(rucaptcha_key="aa9011f31111181111168611f1151122", - ... angle=45).captcha_handler(captcha_file="examples/rotate/rotate_ex.png") - { - 'captchaSolve': '125', - 'taskId': '73043008354', - 'error': False, - 'errorBody': None - } - Returns: Dict with full server response Notes: - https://rucaptcha.com/api-rucaptcha#solving_funcaptcha_new + Check class docstirng for more info """ - - # if a local file link is passed - if captcha_file: - self.post_payload.update({"body": base64.b64encode(self._local_file_captcha(captcha_file)).decode("utf-8")}) - # if the file is transferred in base64 encoding - elif captcha_base64: - self.post_payload.update({"body": base64.b64encode(captcha_base64).decode("utf-8")}) - # if a URL is passed - elif captcha_link: - try: - content = self.url_open(url=captcha_link, **kwargs).content - self.post_payload.update({"body": base64.b64encode(content).decode("utf-8")}) - except Exception as error: - self.result.error = True - self.result.errorBody = str(error) - return self.result.dict() - - else: - # if none of the parameters are passed - self.result.error = True - self.result.errorBody = self.NO_CAPTCHA_ERR - return self.result.dict() - return self._processing_response(**kwargs) + self._body_file_processing( + save_format=self.save_format, + file_path=self.img_path, + captcha_link=captcha_link, + captcha_file=captcha_file, + captcha_base64=captcha_base64, + **kwargs, + ) + logging.warning(f"{self.result = }") + if not self.result.errorId: + return self._processing_response(**kwargs) + logging.warning("ERROR ID IS EXISTS") + return self.result.to_dict() async def aio_captcha_handler( self, @@ -154,43 +171,26 @@ async def aio_captcha_handler( captcha_base64: Captcha image BASE64 info kwargs: additional params for `aiohttp` library - Examples: - >>> await RotateCaptcha(rucaptcha_key="aa9011f31111181111168611f1151122", - ... angle=45).aio_captcha_handler(captcha_file="examples/rotate/rotate_ex.png") - { - 'captchaSolve': '125', - 'taskId': '73043008354', - 'error': False, - 'errorBody': None - } - Returns: Dict with full server response Notes: - https://rucaptcha.com/api-rucaptcha#solving_funcaptcha_new + Check class docstirng for more info """ - # if a local file link is passed - if captcha_file: - self.post_payload.update({"body": base64.b64encode(self._local_file_captcha(captcha_file)).decode("utf-8")}) - # if the file is transferred in base64 encoding - elif captcha_base64: - self.post_payload.update({"body": base64.b64encode(captcha_base64).decode("utf-8")}) - # if a URL is passed - elif captcha_link: - try: - content = await self.aio_url_read(url=captcha_link, **kwargs) - self.post_payload.update({"body": base64.b64encode(content).decode("utf-8")}) - except Exception as error: - self.result.error = True - self.result.errorBody = str(error) - return self.result.dict() - - else: - # if none of the parameters are passed - self.result.error = True - self.result.errorBody = self.NO_CAPTCHA_ERR - return self.result.dict() - - return await self._aio_processing_response() + await self._aio_body_file_processing( + save_format=self.save_format, + file_path=self.img_path, + captcha_link=captcha_link, + captcha_file=captcha_file, + captcha_base64=captcha_base64, + **kwargs, + ) + logging.warning(f"{self.result = }") + if not self.result.errorId: + return await self._aio_processing_response() + return self.result.to_dict() + + def __del__(self): + if self.save_format == SaveFormatsEnm.CONST.value and self.img_clearing: + shutil.rmtree(self.img_path) diff --git a/src/python_rucaptcha/text_captcha.py b/src/python_rucaptcha/text_captcha.py index a074b877..cf98fa97 100644 --- a/src/python_rucaptcha/text_captcha.py +++ b/src/python_rucaptcha/text_captcha.py @@ -1,3 +1,5 @@ +import logging + from .core.base import BaseCaptcha from .core.enums import TextCaptchaEnm @@ -5,7 +7,7 @@ class TextCaptcha(BaseCaptcha): def __init__( self, - language: int = 0, + languagePool: str = "en", *args, **kwargs, ): @@ -14,40 +16,75 @@ def __init__( Args: rucaptcha_key: User API key - language: Captcha text lang: - 0 - not defined - 1 - captcha contains only Cyrillic - 2 - captcha contains only latin characters + languagePool: Used to choose the workers for solving the captcha by their language. + Applicable to image-based and text-based captchas.\n + `en` - English-speaking workers\n + `rn` - Russian-speaking workers. + kwargs: Additional not required params for this captcha type Examples: - >>> TextCaptcha(rucaptcha_key="aa9011f31111181111168611f1151122", - ... language=2).captcha_handler(textcaptcha="Our planet name?") + >>> TextCaptcha(rucaptcha_key="aa90...51122", + ... languagePool='en' + ... ).captcha_handler(textcaptcha="If tomorrow is Saturday, what day is today?") + { + "errorId":0, + "status":"ready", + "solution":{ + "text":"SUNDAY" + }, + "cost":0.03669, + "ip":"46.53.241.91", + "createTime":1695617910, + "endTime":1695617965, + "solveCount":2, + "taskId":5423543 + } + + >>> TextCaptcha(rucaptcha_key="aa90...51122", + ... ).captcha_handler(textcaptcha="If tomorrow is Saturday, what day is today?") { - 'captchaSolve': 'earth', - 'taskId': '73043008354', - 'error': False, - 'errorBody': None + "errorId":0, + "status":"ready", + "solution":{ + "text":"SUNDAY" + }, + "cost":0.03669, + "ip":"46.53.241.91", + "createTime":1695617910, + "endTime":1695617965, + "solveCount":2, + "taskId":5423543 } - >>> TextCaptcha(rucaptcha_key="aa9011f31111181111168611f1151122" - ... ).captcha_handler(textcaptcha="Our planet name?") + >>> await TextCaptcha(rucaptcha_key="aa90...51122", + ... ).aio_captcha_handler(textcaptcha="If tomorrow is Saturday, what day is today?") { - 'captchaSolve': 'earth', - 'taskId': '73043008354', - 'error': False, - 'errorBody': None + "errorId":0, + "status":"ready", + "solution":{ + "text":"SUNDAY" + }, + "cost":0.03669, + "ip":"46.53.241.91", + "createTime":1695617910, + "endTime":1695617965, + "solveCount":2, + "taskId":5423543 } Returns: Dict with full server response Notes: - https://rucaptcha.com/api-rucaptcha#solving_text_captcha + https://2captcha.com/api-docs/text + + https://rucaptcha.com/api-docs/text """ - super().__init__(method=TextCaptchaEnm.TEXT.value, *args, **kwargs) + super().__init__(method=TextCaptchaEnm.TextCaptchaTask.value, *args, **kwargs) - self.post_payload.update({"language": language}) + self.create_task_payload.update({"languagePool": languagePool}) + logging.warning(f"{self.create_task_payload = }") def captcha_handler(self, textcaptcha: str, **kwargs) -> dict: """ @@ -56,24 +93,13 @@ def captcha_handler(self, textcaptcha: str, **kwargs) -> dict: Args: textcaptcha: Captcha text - Examples: - >>> TextCaptcha(rucaptcha_key="aa9011f31111181111168611f1151122", - ... language=2).captcha_handler(textcaptcha="Our planet name?") - { - 'captchaSolve': 'earth', - 'taskId': '73043008354', - 'error': False, - 'errorBody': None - } - Returns: Dict with full server response Notes: Check class docstirng for more info """ - self.post_payload.update({"textcaptcha": textcaptcha}) - + self.create_task_payload["task"].update({"comment": textcaptcha}) return self._processing_response(**kwargs) async def aio_captcha_handler(self, textcaptcha: str) -> dict: @@ -83,21 +109,11 @@ async def aio_captcha_handler(self, textcaptcha: str) -> dict: Args: textcaptcha: Captcha text - Examples: - >>> await TextCaptcha(rucaptcha_key="aa9011f31111181111168611f1151122", - ... language=2).aio_captcha_handler(textcaptcha="Our planet name?") - { - 'captchaSolve': 'earth', - 'taskId': '73043008354', - 'error': False, - 'errorBody': None - } - Returns: Dict with full server response Notes: Check class docstirng for more info """ - self.post_payload.update({"textcaptcha": textcaptcha}) + self.create_task_payload["task"].update({"comment": textcaptcha}) return await self._aio_processing_response() diff --git a/src/python_rucaptcha/turnstile.py b/src/python_rucaptcha/turnstile.py index 7bdd52d2..a1aa3786 100644 --- a/src/python_rucaptcha/turnstile.py +++ b/src/python_rucaptcha/turnstile.py @@ -1,78 +1,95 @@ +from typing import Union + from .core.base import BaseCaptcha from .core.enums import TurnstileCaptchaEnm class Turnstile(BaseCaptcha): - def __init__(self, pageurl: str, sitekey: str, method: str = TurnstileCaptchaEnm.TURNSTILE.value, *args, **kwargs): + def __init__( + self, + websiteURL: str, + websiteKey: str, + userAgent: str, + method: Union[str, TurnstileCaptchaEnm] = TurnstileCaptchaEnm.TurnstileTaskProxyless, + *args, + **kwargs, + ): """ The class is used to work with Cloudflare Turnstile. Args: rucaptcha_key: User API key - pageurl: Full URL of the captcha page - sitekey: The value of the `sitekey` parameter found on the site + websiteURL: Full URL of the captcha page + websiteKey: The value of the `sitekey` parameter found on the site + userAgent: Your browser UserAgent method: Captcha type kwargs: Not required params for task creation request Examples: >>> Turnstile(rucaptcha_key="aa9011f31111181111168611f1151122", - ... pageurl="https://www.geetest.com/en/demo", - ... sitekey="0x4AAAAAAAC3DHQFLr1GavRN", - ... method=TurnstileCaptchaEnm.TURNSTILE.value, + ... websiteURL="https://www.geetest.com/en/demo", + ... websiteKey="0x4AAAAAAAC3DHQFLr1GavRN", + ... method=TurnstileCaptchaEnm.TurnstileTaskProxyless.value, ... ).captcha_handler() { - "captchaSolve": "0._VMG....Pv", - "taskId": 73052314114, - "error": False, - "errorBody": None + "errorId":0, + "status":"ready", + "solution":{ + "token":"0.zrSnRHO7h0HwSjSCU8oyzbjEtD8p.d62306d4ee00c77dda697f959ebbd7bd97", + "userAgent":"Mozilla/5.0 (....." + }, + "cost":"0.00145", + "ip":"1.2.3.4", + "createTime":1692863536, + "endTime":1692863556, + "solveCount":1, + "taskId": 73243152973, } >>> await Turnstile(rucaptcha_key="aa9011f31111181111168611f1151122", - ... pageurl="https://www.geetest.com/en/demo", - ... sitekey="0x4AAAAAAAC3DHQFLr1GavRN", - ... method=TurnstileCaptchaEnm.TURNSTILE.value, + ... websiteURL="https://www.geetest.com/en/demo", + ... websiteKey="0x4AAAAAAAC3DHQFLr1GavRN", + ... method=TurnstileCaptchaEnm.TurnstileTaskProxyless.value, ... ).aio_captcha_handler() { - "captchaSolve": "0._VMG....Pv", - "taskId": 73052314114, - "error": False, - "errorBody": None + "errorId":0, + "status":"ready", + "solution":{ + "token":"0.zrSnRHO7h0HwSjSCU8oyzbjEtD8p.d62306d4ee00c77dda697f959ebbd7bd97", + "userAgent":"Mozilla/5.0 (....." + }, + "cost":"0.00145", + "ip":"1.2.3.4", + "createTime":1692863536, + "endTime":1692863556, + "solveCount":1, + "taskId": 73243152973, } Returns: Dict with full server response Notes: - https://rucaptcha.com/api-rucaptcha#turnstile + https://rucaptcha.com/api-docs/cloudflare-turnstile """ + super().__init__(method=method, *args, **kwargs) - self.post_payload.update({"sitekey": sitekey, "pageurl": pageurl}) + self.create_task_payload["task"].update( + {"websiteURL": websiteURL, "websiteKey": websiteKey, "userAgent": userAgent} + ) # check user params if method not in TurnstileCaptchaEnm.list_values(): raise ValueError(f"Invalid method parameter set, available - {TurnstileCaptchaEnm.list_values()}") - def captcha_handler(self, **kwargs): + def captcha_handler(self, **kwargs) -> dict: """ Sync solving method Args: kwargs: Parameters for the `requests` library - Examples: - >>> Turnstile(rucaptcha_key="aa9011f31111181111168611f1151122", - ... pageurl="https://www.geetest.com/en/demo", - ... sitekey="0x4AAAAAAAC3DHQFLr1GavRN", - ... method=TurnstileCaptchaEnm.TURNSTILE.value, - ... ).captcha_handler() - { - "captchaSolve": "0._VMG....Pv", - "taskId": 73052314114, - "error": False, - "errorBody": None - } - Returns: Dict with full server response @@ -81,23 +98,10 @@ def captcha_handler(self, **kwargs): """ return self._processing_response(**kwargs) - async def aio_captcha_handler(self): + async def aio_captcha_handler(self) -> dict: """ Async solving method - Examples: - >>> await Turnstile(rucaptcha_key="aa9011f31111181111168611f1151122", - ... pageurl="https://www.geetest.com/en/demo", - ... sitekey="0x4AAAAAAAC3DHQFLr1GavRN", - ... method=TurnstileCaptchaEnm.TURNSTILE.value, - ... ).aio_captcha_handler() - { - "captchaSolve": "0._VMG....Pv", - "taskId": 73052314114, - "error": False, - "errorBody": None - } - Returns: Dict with full server response diff --git a/src/python_rucaptcha/yandex_smart_captcha.py b/src/python_rucaptcha/yandex_smart_captcha.py deleted file mode 100644 index 713fc1ff..00000000 --- a/src/python_rucaptcha/yandex_smart_captcha.py +++ /dev/null @@ -1,127 +0,0 @@ -from .core.base import BaseCaptcha -from .core.enums import YandexSmartCaptchaEnm - - -class YandexSmartCaptcha(BaseCaptcha): - def __init__(self, pageurl: str, sitekey: str, method: str = YandexSmartCaptchaEnm.YANDEX.value, *args, **kwargs): - """ - The class is used to work with Yandex Smart Captcha - - Args: - rucaptcha_key: User API key - pageurl: Full URL of the captcha page - sitekey: The value of the `data-sitekey` parameter found on the site - method: Captcha type - kwargs: Not required params for task creation request - - Examples: - >>> YandexSmartCaptcha(rucaptcha_key="aa9011f31111181111168611f1151122", - ... pageurl="https://captcha-api.yandex.ru/demo", - ... sitekey="FEXfAbHQsToo97VidNVk3j4dC74nGW1DgdxjtNB9", - ... method=YandexSmartCaptchaEnm.YANDEX.value, - ... ).captcha_handler() - { - "captchaSolve": "dD0x....Pv", - "taskId": 73052314114, - "error": False, - "errorBody": None - } - - >>> YandexSmartCaptcha(rucaptcha_key="aa9011f31111181111168611f1151122", - ... pageurl="https://captcha-api.yandex.ru/demo", - ... sitekey="FEXfAbHQsToo97VidNVk3j4dC74nGW1DgdxjtNB9" - ... ).captcha_handler() - { - "captchaSolve": "dD0x....Pv", - "taskId": 73052314114, - "error": False, - "errorBody": None - } - - >>> await YandexSmartCaptcha(rucaptcha_key="aa9011f31111181111168611f1151122", - ... pageurl="https://captcha-api.yandex.ru/demo", - ... sitekey="FEXfAbHQsToo97VidNVk3j4dC74nGW1DgdxjtNB9", - ... method=YandexSmartCaptchaEnm.YANDEX.value, - ... ).aio_captcha_handler() - { - "captchaSolve": "dD0x....Pv", - "taskId": 73052314114, - "error": False, - "errorBody": None - } - - >>> await YandexSmartCaptcha(rucaptcha_key="aa9011f31111181111168611f1151122", - ... pageurl="https://captcha-api.yandex.ru/demo", - ... sitekey="FEXfAbHQsToo97VidNVk3j4dC74nGW1DgdxjtNB9" - ... ).aio_captcha_handler() - { - "captchaSolve": "dD0x....Pv", - "taskId": 73052314114, - "error": False, - "errorBody": None - } - - Returns: - Dict with full server response - - Notes: - https://rucaptcha.com/api-rucaptcha#yandex - """ - super().__init__(method=method, *args, **kwargs) - - self.post_payload.update({"sitekey": sitekey, "pageurl": pageurl}) - - # check user params - if method not in YandexSmartCaptchaEnm.list_values(): - raise ValueError(f"Invalid method parameter set, available - {YandexSmartCaptchaEnm.list_values()}") - - def captcha_handler(self, **kwargs): - """ - Sync solving method - - Args: - kwargs: Parameters for the `requests` library - - Examples: - >>> YandexSmartCaptcha(rucaptcha_key="aa9011f31111181111168611f1151122", - ... pageurl="https://captcha-api.yandex.ru/demo", - ... sitekey="FEXfAbHQsToo97VidNVk3j4dC74nGW1DgdxjtNB9" - ... ).captcha_handler() - { - "captchaSolve": "dD0x....Pv", - "taskId": 73052314114, - "error": False, - "errorBody": None - } - - Returns: - Dict with full server response - - Notes: - Check class docstirng for more info - """ - return self._processing_response(**kwargs) - - async def aio_captcha_handler(self): - """ - Async solving method - - Examples: - >>> await YandexSmartCaptcha(rucaptcha_key="aa9011f31111181111168611f1151122", - ... pageurl="https://captcha-api.yandex.ru/demo", - ... sitekey="FEXfAbHQsToo97VidNVk3j4dC74nGW1DgdxjtNB9" - ... ).aio_captcha_handler() - { - "captchaSolve": "dD0x....Pv", - "taskId": 73052314114, - "error": False, - "errorBody": None - } - - Returns: - Dict with full server response - - Notes: - Check class docstirng for more info - """ - return await self._aio_processing_response() diff --git a/src/requirements.txt b/src/requirements.txt index 889ea9fd..c9b17689 100644 --- a/src/requirements.txt +++ b/src/requirements.txt @@ -1,5 +1,4 @@ -requests>=2.21.0 -aiohttp>=3.7.4 -pydantic==1.* -tenacity==8.* -# websockets==11.* +requests>=2.28.0 +aiohttp>=3.9.0 +msgspec==0.18.* +tenacity==8.2.* diff --git a/src/setup.py b/src/setup.py index e1f9fd12..f2e1117c 100644 --- a/src/setup.py +++ b/src/setup.py @@ -15,7 +15,7 @@ URL = "https://andreidrang.github.io/python-rucaptcha/" EMAIL = "python-captcha@pm.me" AUTHOR = "AndreiDrang, redV0ID" -REQUIRES_PYTHON = ">=3.7.0" +REQUIRES_PYTHON = ">=3.9.0" VERSION = __version__ with open("requirements.txt", "rt") as requirements_txt: REQUIRED = [str(requirement) for requirement in parse_requirements(requirements_txt)] @@ -125,11 +125,10 @@ def run(self): "Programming Language :: Python", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3 :: Only", - "Programming Language :: Python :: 3.7", - "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", "Development Status :: 5 - Production/Stable", "Framework :: AsyncIO", "Operating System :: Unix", diff --git a/tests/conftest.py b/tests/conftest.py index 8d0559c7..4ff61cfc 100755 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -9,12 +9,12 @@ @pytest.fixture(scope="function") def delay_func(): - time.sleep(5) + time.sleep(0.5) @pytest.fixture(scope="class") def delay_class(): - time.sleep(20) + time.sleep(3) @pytest.mark.usefixtures("delay_func") diff --git a/tests/test_amazon.py b/tests/test_amazon.py index d56477be..a06639f0 100644 --- a/tests/test_amazon.py +++ b/tests/test_amazon.py @@ -11,6 +11,23 @@ class TestAmazonCaptcha(BaseTest): iv = "some-iv-value" context = "some-context-value" + @pytest.mark.parametrize("method", AmazonWAFCaptchaEnm.list_values()) + def test_args(self, method: str): + instance = AmazonWAF( + rucaptcha_key=self.RUCAPTCHA_KEY, + websiteURL=self.pageurl, + websiteKey=self.sitekey, + iv=self.iv, + context=self.context, + method=method, + ) + assert instance.create_task_payload["clientKey"] == self.RUCAPTCHA_KEY + assert instance.create_task_payload["task"]["websiteURL"] == self.pageurl + assert instance.create_task_payload["task"]["websiteKey"] == self.sitekey + assert instance.create_task_payload["task"]["iv"] == self.iv + assert instance.create_task_payload["task"]["context"] == self.context + assert instance.create_task_payload["task"]["type"] == method + """ Success tests """ @@ -22,34 +39,46 @@ def test_methods_exists(self): def test_basic_data(self): instance = AmazonWAF( rucaptcha_key=self.RUCAPTCHA_KEY, - pageurl=self.pageurl, - sitekey=self.sitekey, + websiteURL=self.pageurl, + websiteKey=self.sitekey, iv=self.iv, context=self.context, - method=AmazonWAFCaptchaEnm.AMAZON_WAF.value, + method=AmazonWAFCaptchaEnm.AmazonTaskProxyless.value, ) - assert instance.params.rucaptcha_key == self.RUCAPTCHA_KEY - assert instance.post_payload["method"] == AmazonWAFCaptchaEnm.AMAZON_WAF.value - assert instance.post_payload["pageurl"] == self.pageurl - assert instance.post_payload["sitekey"] == self.sitekey - assert instance.post_payload["iv"] == self.iv - assert instance.post_payload["context"] == self.context + assert instance.captcha_handler() def test_context_basic_data(self): with AmazonWAF( rucaptcha_key=self.RUCAPTCHA_KEY, - pageurl=self.pageurl, - sitekey=self.sitekey, + websiteURL=self.pageurl, + websiteKey=self.sitekey, + iv=self.iv, + context=self.context, + method=AmazonWAFCaptchaEnm.AmazonTaskProxyless.value, + ) as instance: + assert instance.captcha_handler() + + async def test_aio_basic_data(self): + instance = AmazonWAF( + rucaptcha_key=self.RUCAPTCHA_KEY, + websiteURL=self.pageurl, + websiteKey=self.sitekey, + iv=self.iv, + context=self.context, + method=AmazonWAFCaptchaEnm.AmazonTaskProxyless.value, + ) + assert await instance.aio_captcha_handler() + + async def test_aio_context_basic_data(self): + async with AmazonWAF( + rucaptcha_key=self.RUCAPTCHA_KEY, + websiteURL=self.pageurl, + websiteKey=self.sitekey, iv=self.iv, context=self.context, - method=AmazonWAFCaptchaEnm.AMAZON_WAF.value, + method=AmazonWAFCaptchaEnm.AmazonTaskProxyless.value, ) as instance: - assert instance.params.rucaptcha_key == self.RUCAPTCHA_KEY - assert instance.post_payload["method"] == AmazonWAFCaptchaEnm.AMAZON_WAF.value - assert instance.post_payload["pageurl"] == self.pageurl - assert instance.post_payload["sitekey"] == self.sitekey - assert instance.post_payload["iv"] == self.iv - assert instance.post_payload["context"] == self.context + assert await instance.aio_captcha_handler() """ Fail tests @@ -59,8 +88,8 @@ def test_wrong_method(self): with pytest.raises(ValueError): AmazonWAF( rucaptcha_key=self.RUCAPTCHA_KEY, - pageurl=self.pageurl, - sitekey=self.sitekey, + websiteURL=self.pageurl, + websiteKey=self.sitekey, iv=self.iv, context=self.context, method=self.get_random_string(5), diff --git a/tests/test_audio.py b/tests/test_audio.py index 5059f92a..a63018fb 100644 --- a/tests/test_audio.py +++ b/tests/test_audio.py @@ -3,7 +3,7 @@ from tests.conftest import BaseTest from python_rucaptcha.core.enums import SaveFormatsEnm from python_rucaptcha.audio_captcha import AudioCaptcha -from python_rucaptcha.core.serializer import ResponseSer +from python_rucaptcha.core.serializer import GetTaskResultResponseSer class TestAudioCaptcha(BaseTest): @@ -18,130 +18,113 @@ def test_methods_exists(self): assert "captcha_handler" in AudioCaptcha.__dict__.keys() assert "aio_captcha_handler" in AudioCaptcha.__dict__.keys() + def test_args(self): + instance = AudioCaptcha(rucaptcha_key=self.RUCAPTCHA_KEY) + assert instance.create_task_payload["clientKey"] == self.RUCAPTCHA_KEY + @pytest.mark.parametrize("save_format", [SaveFormatsEnm.TEMP, SaveFormatsEnm.CONST]) def test_basic_data_file(self, save_format): instance = AudioCaptcha(rucaptcha_key=self.RUCAPTCHA_KEY, save_format=save_format) - assert instance.params.rucaptcha_key == self.RUCAPTCHA_KEY - result = instance.captcha_handler(captcha_file=self.captcha_file) assert isinstance(result, dict) is True - if result["error"] is False: - assert result["error"] is False + if not result["errorId"]: + assert result["status"] == "ready" + assert isinstance(result["solution"]["token"], str) is True assert isinstance(result["taskId"], int) is True - assert result["errorBody"] is None - assert isinstance(result["captchaSolve"], str) is True else: - assert result["error"] is True - assert result["errorBody"] == "ERROR_CAPTCHA_UNSOLVABLE" + assert result["errorId"] in (1, 12) + assert result["errorCode"] == "ERROR_CAPTCHA_UNSOLVABLE" - assert result.keys() == ResponseSer().dict().keys() + assert result.keys() == GetTaskResultResponseSer().to_dict().keys() @pytest.mark.parametrize("save_format", [SaveFormatsEnm.TEMP, SaveFormatsEnm.CONST]) def test_basic_data_link(self, save_format): instance = AudioCaptcha(rucaptcha_key=self.RUCAPTCHA_KEY, save_format=save_format) - assert instance.params.rucaptcha_key == self.RUCAPTCHA_KEY - result = instance.captcha_handler(captcha_link=self.captcha_link) assert isinstance(result, dict) is True - if result["error"] is False: - assert result["error"] is False + if not result["errorId"]: + assert result["status"] == "ready" + assert isinstance(result["solution"]["token"], str) is True assert isinstance(result["taskId"], int) is True - assert result["errorBody"] is None - assert isinstance(result["captchaSolve"], str) is True else: - assert result["error"] is True - assert result["errorBody"] == "ERROR_CAPTCHA_UNSOLVABLE" + assert result["errorId"] in (1, 12) + assert result["errorCode"] == "ERROR_CAPTCHA_UNSOLVABLE" - assert result.keys() == ResponseSer().dict().keys() + assert result.keys() == GetTaskResultResponseSer().to_dict().keys() @pytest.mark.parametrize("save_format", [SaveFormatsEnm.TEMP, SaveFormatsEnm.CONST]) def test_basic_data_base64(self, save_format): instance = AudioCaptcha(rucaptcha_key=self.RUCAPTCHA_KEY, save_format=save_format) - assert instance.params.rucaptcha_key == self.RUCAPTCHA_KEY - with open(self.captcha_file, "rb") as f: result = instance.captcha_handler(captcha_base64=f.read()) assert isinstance(result, dict) is True - if result["error"] is False: - assert result["error"] is False + if not result["errorId"]: + assert result["status"] == "ready" + assert isinstance(result["solution"]["token"], str) is True assert isinstance(result["taskId"], int) is True - assert result["errorBody"] is None - assert isinstance(result["captchaSolve"], str) is True else: - assert result["error"] is True - assert result["errorBody"] == "ERROR_CAPTCHA_UNSOLVABLE" + assert result["errorId"] in (1, 12) + assert result["errorCode"] == "ERROR_CAPTCHA_UNSOLVABLE" - assert result.keys() == ResponseSer().dict().keys() + assert result.keys() == GetTaskResultResponseSer().to_dict().keys() - @pytest.mark.asyncio @pytest.mark.parametrize("save_format", [SaveFormatsEnm.TEMP, SaveFormatsEnm.CONST]) async def test_aio_basic_data_file(self, save_format): instance = AudioCaptcha(rucaptcha_key=self.RUCAPTCHA_KEY, save_format=save_format) - assert instance.params.rucaptcha_key == self.RUCAPTCHA_KEY - result = await instance.aio_captcha_handler(captcha_file=self.captcha_file) assert isinstance(result, dict) is True - if result["error"] is False: - assert result["error"] is False + if not result["errorId"]: + assert result["status"] == "ready" + assert isinstance(result["solution"]["token"], str) is True assert isinstance(result["taskId"], int) is True - assert result["errorBody"] is None - assert isinstance(result["captchaSolve"], str) is True else: - assert result["error"] is True - assert result["errorBody"] == "ERROR_CAPTCHA_UNSOLVABLE" + assert result["errorId"] in (1, 12) + assert result["errorCode"] == "ERROR_CAPTCHA_UNSOLVABLE" - assert result.keys() == ResponseSer().dict().keys() + assert result.keys() == GetTaskResultResponseSer().to_dict().keys() - @pytest.mark.asyncio @pytest.mark.parametrize("save_format", [SaveFormatsEnm.TEMP, SaveFormatsEnm.CONST]) async def test_aio_basic_data_link(self, save_format): instance = AudioCaptcha(rucaptcha_key=self.RUCAPTCHA_KEY, save_format=save_format) - assert instance.params.rucaptcha_key == self.RUCAPTCHA_KEY - result = await instance.aio_captcha_handler(captcha_link=self.captcha_link) assert isinstance(result, dict) is True - if result["error"] is False: - assert result["error"] is False + if not result["errorId"]: + assert result["status"] == "ready" + assert isinstance(result["solution"]["token"], str) is True assert isinstance(result["taskId"], int) is True - assert result["errorBody"] is None - assert isinstance(result["captchaSolve"], str) is True else: - assert result["error"] is True - assert result["errorBody"] == "ERROR_CAPTCHA_UNSOLVABLE" + assert result["errorId"] in (1, 12) + assert result["errorCode"] == "ERROR_CAPTCHA_UNSOLVABLE" - assert result.keys() == ResponseSer().dict().keys() + assert result.keys() == GetTaskResultResponseSer().to_dict().keys() - @pytest.mark.asyncio @pytest.mark.parametrize("save_format", [SaveFormatsEnm.TEMP, SaveFormatsEnm.CONST]) async def test_aio_basic_data_base64(self, save_format): instance = AudioCaptcha(rucaptcha_key=self.RUCAPTCHA_KEY, save_format=save_format) - assert instance.params.rucaptcha_key == self.RUCAPTCHA_KEY - with open(self.captcha_file, "rb") as f: result = await instance.aio_captcha_handler(captcha_base64=f.read()) assert isinstance(result, dict) is True - if result["error"] is False: - assert result["error"] is False + if not result["errorId"]: + assert result["status"] == "ready" + assert isinstance(result["solution"]["token"], str) is True assert isinstance(result["taskId"], int) is True - assert result["errorBody"] is None - assert isinstance(result["captchaSolve"], str) is True else: - assert result["error"] is True - assert result["errorBody"] == "ERROR_CAPTCHA_UNSOLVABLE" + assert result["errorId"] in (1, 12) + assert result["errorCode"] == "ERROR_CAPTCHA_UNSOLVABLE" - assert result.keys() == ResponseSer().dict().keys() + assert result.keys() == GetTaskResultResponseSer().to_dict().keys() """ Fail tests @@ -150,108 +133,63 @@ async def test_aio_basic_data_base64(self, save_format): def test_no_captcha(self): instance = AudioCaptcha(rucaptcha_key=self.RUCAPTCHA_KEY) - assert instance.params.rucaptcha_key == self.RUCAPTCHA_KEY - result = instance.captcha_handler() assert isinstance(result, dict) is True - assert result["error"] is True - assert result["taskId"] is None - assert result["errorBody"] == AudioCaptcha.NO_CAPTCHA_ERR - assert result["captchaSolve"] == {} + assert result["errorId"] in (12, 5) - assert result.keys() == ResponseSer().dict().keys() - - @pytest.mark.asyncio async def test_aio_no_captcha(self): instance = AudioCaptcha(rucaptcha_key=self.RUCAPTCHA_KEY) - assert instance.params.rucaptcha_key == self.RUCAPTCHA_KEY - result = await instance.aio_captcha_handler() assert isinstance(result, dict) is True - assert result["error"] is True - assert result["taskId"] is None - assert result["errorBody"] == AudioCaptcha.NO_CAPTCHA_ERR - assert result["captchaSolve"] == {} - assert result.keys() == ResponseSer().dict().keys() + assert result["errorId"] in (12, 5) + assert result.keys() == GetTaskResultResponseSer().to_dict().keys() def test_wrong_link(self): instance = AudioCaptcha(rucaptcha_key=self.RUCAPTCHA_KEY) - assert instance.params.rucaptcha_key == self.RUCAPTCHA_KEY - result = instance.captcha_handler(captcha_link=self.get_random_string(length=50)) assert isinstance(result, dict) is True - assert result["error"] is True - assert result["taskId"] is None - assert result["captchaSolve"] == {} - assert result.keys() == ResponseSer().dict().keys() + assert result["errorId"] in (12, 5) + assert result.keys() == GetTaskResultResponseSer().to_dict().keys() def test_wrong_path(self): instance = AudioCaptcha(rucaptcha_key=self.RUCAPTCHA_KEY) - assert instance.params.rucaptcha_key == self.RUCAPTCHA_KEY - with pytest.raises(FileNotFoundError): - result = instance.captcha_handler(captcha_file=self.get_random_string(length=50)) - - assert isinstance(result, dict) is True - assert result["error"] is True - assert result["taskId"] is None - assert result["captchaSolve"] == {} - assert result.keys() == ResponseSer().dict().keys() + instance.captcha_handler(captcha_file=self.get_random_string(length=50)) def test_wrong_base64(self): instance = AudioCaptcha(rucaptcha_key=self.RUCAPTCHA_KEY) - assert instance.params.rucaptcha_key == self.RUCAPTCHA_KEY + result = instance.captcha_handler(captcha_base64=self.get_random_string(length=50).encode(encoding="UTF-8")) + assert isinstance(result, dict) is True - assert result["error"] is True - assert result["taskId"] is None - assert result["captchaSolve"] == {} - assert result.keys() == ResponseSer().dict().keys() + assert result["errorId"] in (12, 5) - @pytest.mark.asyncio async def test_aio_wrong_link(self): instance = AudioCaptcha(rucaptcha_key=self.RUCAPTCHA_KEY) - assert instance.params.rucaptcha_key == self.RUCAPTCHA_KEY - result = await instance.aio_captcha_handler(captcha_link=self.get_random_string(length=50)) assert isinstance(result, dict) is True - assert result["error"] is True - assert result["taskId"] is None - assert result["captchaSolve"] == {} - assert result.keys() == ResponseSer().dict().keys() + assert result["errorId"] in (12, 5) - @pytest.mark.asyncio async def test_aio_wrong_path(self): instance = AudioCaptcha(rucaptcha_key=self.RUCAPTCHA_KEY) - assert instance.params.rucaptcha_key == self.RUCAPTCHA_KEY - with pytest.raises(FileNotFoundError): - result = await instance.aio_captcha_handler(captcha_file=self.get_random_string(length=50)) - - assert isinstance(result, dict) is True - assert result["error"] is True - assert result["taskId"] is None - assert result["captchaSolve"] == {} - assert result.keys() == ResponseSer().dict().keys() + await instance.aio_captcha_handler(captcha_file=self.get_random_string(length=50)) - @pytest.mark.asyncio async def test_aio_wrong_base64(self): instance = AudioCaptcha(rucaptcha_key=self.RUCAPTCHA_KEY) - assert instance.params.rucaptcha_key == self.RUCAPTCHA_KEY + result = await instance.aio_captcha_handler( captcha_base64=self.get_random_string(length=50).encode(encoding="UTF-8") ) + assert isinstance(result, dict) is True - assert result["error"] is True - assert result["taskId"] is None - assert result["captchaSolve"] == {} - assert result.keys() == ResponseSer().dict().keys() + assert result["errorId"] in (12, 5) diff --git a/tests/test_capypuzzle.py b/tests/test_capypuzzle.py index af6db7a4..0e06c752 100644 --- a/tests/test_capypuzzle.py +++ b/tests/test_capypuzzle.py @@ -3,7 +3,7 @@ from tests.conftest import BaseTest from python_rucaptcha.core.enums import CapyPuzzleEnm from python_rucaptcha.capy_puzzle import CapyPuzzle -from python_rucaptcha.core.serializer import ResponseSer +from python_rucaptcha.core.serializer import GetTaskResultResponseSer class TestCapyPuzzle(BaseTest): @@ -12,105 +12,112 @@ class TestCapyPuzzle(BaseTest): api_server = "https://jp.api.capy.me/" versions = ["puzzle", "avatar"] - """ - Success tests - """ - def test_methods_exists(self): assert "captcha_handler" in CapyPuzzle.__dict__.keys() assert "aio_captcha_handler" in CapyPuzzle.__dict__.keys() + @pytest.mark.parametrize("method", CapyPuzzleEnm.list_values()) + def test_args(self, method: str): + instance = CapyPuzzle( + websiteURL=self.pageurl, + websiteKey=self.captchakey, + method=method, + rucaptcha_key=self.RUCAPTCHA_KEY, + api_server=self.api_server, + version=self.versions[0], + ) + assert instance.create_task_payload["clientKey"] == self.RUCAPTCHA_KEY + assert instance.create_task_payload["task"]["websiteURL"] == self.pageurl + assert instance.create_task_payload["task"]["websiteKey"] == self.captchakey + assert instance.create_task_payload["task"]["type"] == method + + """ + Success tests + """ + def test_basic_data(self): instance = CapyPuzzle( - pageurl=self.pageurl, - captchakey=self.captchakey, - method=CapyPuzzleEnm.CAPY.value, + websiteURL=self.pageurl, + websiteKey=self.captchakey, + method=CapyPuzzleEnm.CapyTaskProxyless.value, rucaptcha_key=self.RUCAPTCHA_KEY, api_server=self.api_server, version=self.versions[0], ) - assert instance.params.rucaptcha_key == self.RUCAPTCHA_KEY - assert instance.post_payload["method"] == CapyPuzzleEnm.CAPY.value - assert instance.post_payload["pageurl"] == self.pageurl - assert instance.post_payload["api_server"] == self.api_server - assert instance.post_payload["version"] == self.versions[0] result = instance.captcha_handler() assert isinstance(result, dict) is True - if result["error"] is False: - assert result["error"] is False + if not result["errorId"]: + assert result["status"] in ("ready", "processing") assert isinstance(result["taskId"], int) is True - assert result["errorBody"] is None - assert isinstance(result["captchaSolve"], dict) is True else: - assert result["error"] is True - assert isinstance(result["taskId"], int) is True - assert result["errorBody"] == "ERROR_CAPTCHA_UNSOLVABLE" + assert result["errorId"] in (1, 12) + assert result["errorCode"] == "ERROR_CAPTCHA_UNSOLVABLE" - assert result.keys() == ResponseSer().dict().keys() + assert result.keys() == GetTaskResultResponseSer().to_dict().keys() - @pytest.mark.asyncio async def test_aio_basic_data(self): instance = CapyPuzzle( - pageurl=self.pageurl, - captchakey=self.captchakey, - method=CapyPuzzleEnm.CAPY.value, + websiteURL=self.pageurl, + websiteKey=self.captchakey, + method=CapyPuzzleEnm.CapyTaskProxyless.value, rucaptcha_key=self.RUCAPTCHA_KEY, api_server=self.api_server, version=self.versions[0], ) - assert instance.params.rucaptcha_key == self.RUCAPTCHA_KEY - assert instance.post_payload["method"] == CapyPuzzleEnm.CAPY.value - assert instance.post_payload["pageurl"] == self.pageurl - assert instance.post_payload["api_server"] == self.api_server - assert instance.post_payload["version"] == self.versions[0] result = await instance.aio_captcha_handler() assert isinstance(result, dict) is True - if result["error"] is False: - assert result["error"] is False + if not result["errorId"]: + assert result["status"] in ("ready", "processing") assert isinstance(result["taskId"], int) is True - assert result["errorBody"] is None - assert isinstance(result["captchaSolve"], dict) is True else: - assert result["error"] is True - assert isinstance(result["taskId"], int) is True - assert result["errorBody"] == "ERROR_CAPTCHA_UNSOLVABLE" + assert result["errorId"] in (1, 12) + assert result["errorCode"] == "ERROR_CAPTCHA_UNSOLVABLE" - assert result.keys() == ResponseSer().dict().keys() + assert result.keys() == GetTaskResultResponseSer().to_dict().keys() def test_context_basic_data(self): with CapyPuzzle( - pageurl=self.pageurl, - captchakey=self.captchakey, - method=CapyPuzzleEnm.CAPY.value, + websiteURL=self.pageurl, + websiteKey=self.captchakey, + method=CapyPuzzleEnm.CapyTaskProxyless.value, rucaptcha_key=self.RUCAPTCHA_KEY, api_server=self.api_server, version=self.versions[0], ) as instance: - assert instance.params.rucaptcha_key == self.RUCAPTCHA_KEY - assert instance.post_payload["method"] == CapyPuzzleEnm.CAPY.value - assert instance.post_payload["pageurl"] == self.pageurl - assert instance.post_payload["api_server"] == self.api_server - assert instance.post_payload["version"] == self.versions[0] + result = instance.captcha_handler() + assert isinstance(result, dict) is True + if not result["errorId"]: + assert result["status"] in ("ready", "processing") + assert isinstance(result["taskId"], int) is True + else: + assert result["errorId"] in (1, 12) + assert result["errorCode"] == "ERROR_CAPTCHA_UNSOLVABLE" + + assert result.keys() == GetTaskResultResponseSer().to_dict().keys() - @pytest.mark.asyncio async def test_context_aio_basic_data(self): async with CapyPuzzle( - pageurl=self.pageurl, - captchakey=self.captchakey, - method=CapyPuzzleEnm.CAPY.value, + websiteURL=self.pageurl, + websiteKey=self.captchakey, + method=CapyPuzzleEnm.CapyTaskProxyless.value, rucaptcha_key=self.RUCAPTCHA_KEY, api_server=self.api_server, version=self.versions[0], ) as instance: - assert instance.params.rucaptcha_key == self.RUCAPTCHA_KEY - assert instance.post_payload["method"] == CapyPuzzleEnm.CAPY.value - assert instance.post_payload["pageurl"] == self.pageurl - assert instance.post_payload["api_server"] == self.api_server - assert instance.post_payload["version"] == self.versions[0] + result = await instance.aio_captcha_handler() + assert isinstance(result, dict) is True + if not result["errorId"]: + assert result["status"] in ("ready", "processing") + assert isinstance(result["taskId"], int) is True + else: + assert result["errorId"] in (1, 12) + assert result["errorCode"] == "ERROR_CAPTCHA_UNSOLVABLE" + + assert result.keys() == GetTaskResultResponseSer().to_dict().keys() """ Fail tests @@ -119,8 +126,8 @@ async def test_context_aio_basic_data(self): def test_wrong_method(self): with pytest.raises(ValueError): CapyPuzzle( - pageurl=self.pageurl, - captchakey=self.captchakey, + websiteURL=self.pageurl, + websiteKey=self.captchakey, method=self.get_random_string(length=5), rucaptcha_key=self.RUCAPTCHA_KEY, ) diff --git a/tests/test_control.py b/tests/test_control.py index 5dbeb74a..5ee402c9 100644 --- a/tests/test_control.py +++ b/tests/test_control.py @@ -1,9 +1,8 @@ -import pytest +import random from tests.conftest import BaseTest from python_rucaptcha.control import Control -from python_rucaptcha.core.enums import ControlEnm -from python_rucaptcha.core.serializer import ResponseSer +from python_rucaptcha.core.serializer import GetTaskResultResponseSer class TestControl(BaseTest): @@ -12,279 +11,81 @@ class TestControl(BaseTest): """ def test_methods_exists(self): - assert "domain_control" in Control.__dict__.keys() - assert "aio_domain_control" in Control.__dict__.keys() - assert "report" in Control.__dict__.keys() - assert "aio_report" in Control.__dict__.keys() - assert "additional_methods" in Control.__dict__.keys() - assert "aio_additional_methods" in Control.__dict__.keys() + assert "reportCorrect" in Control.__dict__.keys() + assert "aio_reportCorrect" in Control.__dict__.keys() + assert "reportIncorrect" in Control.__dict__.keys() + assert "aio_reportIncorrect" in Control.__dict__.keys() + assert "getBalance" in Control.__dict__.keys() + assert "getBalance" in Control.__dict__.keys() def test_get_balance(self): - instance = Control(rucaptcha_key=self.RUCAPTCHA_KEY, action=ControlEnm.GETBALANCE.value) - assert instance.params.rucaptcha_key == self.RUCAPTCHA_KEY - assert instance.params.action == ControlEnm.GETBALANCE.value + instance = Control(rucaptcha_key=self.RUCAPTCHA_KEY) - result = instance.additional_methods() + result = instance.getBalance() assert isinstance(result, dict) is True - assert result["error"] is False - assert result["taskId"] is None - assert result["errorBody"] is None - assert isinstance(result["captchaSolve"], str) is True - assert float(result["captchaSolve"]) > 1 - assert result.keys() == ResponseSer().dict().keys() + assert result["balance"] > 1 + assert result.keys() == GetTaskResultResponseSer().to_dict().keys() def test_context_get_balance(self): - with Control(rucaptcha_key=self.RUCAPTCHA_KEY, action=ControlEnm.GETBALANCE.value) as instance: - assert instance.params.rucaptcha_key == self.RUCAPTCHA_KEY - assert instance.params.action == ControlEnm.GETBALANCE.value + with Control(rucaptcha_key=self.RUCAPTCHA_KEY) as instance: + assert instance.getBalance() - @pytest.mark.asyncio async def test_aio_get_balance(self): - instance = Control(rucaptcha_key=self.RUCAPTCHA_KEY, action=ControlEnm.GETBALANCE.value) - assert instance.params.rucaptcha_key == self.RUCAPTCHA_KEY - assert instance.params.action == ControlEnm.GETBALANCE.value + instance = Control(rucaptcha_key=self.RUCAPTCHA_KEY) - result = await instance.aio_additional_methods() + result = await instance.aio_getBalance() assert isinstance(result, dict) is True - assert result["error"] is False - assert result["taskId"] is None - assert result["errorBody"] is None - assert isinstance(result["captchaSolve"], str) is True - assert float(result["captchaSolve"]) > 1 - assert result.keys() == ResponseSer().dict().keys() + assert result["balance"] > 1 + assert result.keys() == GetTaskResultResponseSer().to_dict().keys() - @pytest.mark.asyncio async def test_aio_context_get_balance(self): - async with Control(rucaptcha_key=self.RUCAPTCHA_KEY, action=ControlEnm.GETBALANCE.value) as instance: - assert instance.params.rucaptcha_key == self.RUCAPTCHA_KEY - assert instance.params.action == ControlEnm.GETBALANCE.value - - def test_get_solution(self): - instance = Control(rucaptcha_key=self.RUCAPTCHA_KEY, action=ControlEnm.GET.value) - assert instance.params.rucaptcha_key == self.RUCAPTCHA_KEY - assert instance.params.action == ControlEnm.GET.value - - result = instance.additional_methods(ids={self.get_random_string(5)}) - - assert isinstance(result, dict) is True - assert result["error"] is False - assert result["taskId"] is None - assert result["errorBody"] is None - assert isinstance(result["captchaSolve"], str) is True - assert result["captchaSolve"] == "ERROR_NO_SUCH_CAPCHA_ID" - assert result.keys() == ResponseSer().dict().keys() - - def test_context_get_solution(self): - with Control(rucaptcha_key=self.RUCAPTCHA_KEY, action=ControlEnm.GET.value) as instance: - assert instance.params.rucaptcha_key == self.RUCAPTCHA_KEY - assert instance.params.action == ControlEnm.GET.value - - @pytest.mark.asyncio - async def test_aio_get_solution(self): - instance = Control(rucaptcha_key=self.RUCAPTCHA_KEY, action=ControlEnm.GET.value) - assert instance.params.rucaptcha_key == self.RUCAPTCHA_KEY - assert instance.params.action == ControlEnm.GET.value - - result = await instance.aio_additional_methods(ids=self.get_random_string(5)) - - assert isinstance(result, dict) is True - assert result["error"] is False - assert result["taskId"] is None - assert result["errorBody"] is None - assert isinstance(result["captchaSolve"], str) is True - assert result["captchaSolve"] == "ERROR_NO_SUCH_CAPCHA_ID" - assert result.keys() == ResponseSer().dict().keys() - - @pytest.mark.asyncio - async def test_aio_context_get_solution(self): - async with Control(rucaptcha_key=self.RUCAPTCHA_KEY, action=ControlEnm.GET.value) as instance: - assert instance.params.rucaptcha_key == self.RUCAPTCHA_KEY - assert instance.params.action == ControlEnm.GET.value - - def test_get_cost(self): - instance = Control(rucaptcha_key=self.RUCAPTCHA_KEY, action=ControlEnm.GET2.value) - assert instance.params.rucaptcha_key == self.RUCAPTCHA_KEY - assert instance.params.action == ControlEnm.GET2.value - - result = instance.additional_methods(ids=f"{self.get_random_string(5)},{self.get_random_string(5)}") - - assert isinstance(result, dict) is True - assert result["error"] is False - assert result["taskId"] is None - assert result["errorBody"] is None - assert isinstance(result["captchaSolve"], str) is True - assert result["captchaSolve"] == "ERROR_NO_SUCH_CAPCHA_ID|ERROR_NO_SUCH_CAPCHA_ID" - assert result.keys() == ResponseSer().dict().keys() - - def test_context_get_cost(self): - with Control(rucaptcha_key=self.RUCAPTCHA_KEY, action=ControlEnm.GET2.value) as instance: - assert instance.params.rucaptcha_key == self.RUCAPTCHA_KEY - assert instance.params.action == ControlEnm.GET2.value - - @pytest.mark.asyncio - async def test_aio_get_cost(self): - instance = Control(rucaptcha_key=self.RUCAPTCHA_KEY, action=ControlEnm.GET2.value) - assert instance.params.rucaptcha_key == self.RUCAPTCHA_KEY - assert instance.params.action == ControlEnm.GET2.value - - result = await instance.aio_additional_methods(ids=f"{self.get_random_string(5)},{self.get_random_string(5)}") - - assert isinstance(result, dict) is True - assert result["error"] is False - assert result["taskId"] is None - assert result["errorBody"] is None - assert isinstance(result["captchaSolve"], str) is True - assert result["captchaSolve"] == "ERROR_NO_SUCH_CAPCHA_ID|ERROR_NO_SUCH_CAPCHA_ID" - assert result.keys() == ResponseSer().dict().keys() - - @pytest.mark.asyncio - async def test_aio_context_get_cost(self): - async with Control(rucaptcha_key=self.RUCAPTCHA_KEY, action=ControlEnm.GET2.value) as instance: - assert instance.params.rucaptcha_key == self.RUCAPTCHA_KEY - assert instance.params.action == ControlEnm.GET2.value - - def test_domains_clean(self): - instance = Control(rucaptcha_key=self.RUCAPTCHA_KEY, action=ControlEnm.DEL_PINGBACK.value) - assert instance.params.rucaptcha_key == self.RUCAPTCHA_KEY - assert instance.params.action == ControlEnm.DEL_PINGBACK.value - - result = instance.domain_control(addr="all") - - assert isinstance(result, dict) is True - assert result["error"] is False - assert result["taskId"] is None - assert result["errorBody"] is None - assert result["captchaSolve"] == "OK" - assert result.keys() == ResponseSer().dict().keys() - - def test_context_domains_clean(self): - with Control(rucaptcha_key=self.RUCAPTCHA_KEY, action=ControlEnm.DEL_PINGBACK.value) as instance: - assert instance.params.rucaptcha_key == self.RUCAPTCHA_KEY - assert instance.params.action == ControlEnm.DEL_PINGBACK.value - - @pytest.mark.asyncio - async def test_aio_domains_clean(self): - instance = Control(rucaptcha_key=self.RUCAPTCHA_KEY, action=ControlEnm.DEL_PINGBACK.value) - assert instance.params.rucaptcha_key == self.RUCAPTCHA_KEY - assert instance.params.action == ControlEnm.DEL_PINGBACK.value - - result = await instance.aio_domain_control(addr="all") - - assert isinstance(result, dict) is True - assert result["error"] is False - assert result["taskId"] is None - assert result["errorBody"] is None - assert result["captchaSolve"] == "OK" - assert result.keys() == ResponseSer().dict().keys() - - @pytest.mark.asyncio - async def test_aio_context_domains_clean(self): - async with Control(rucaptcha_key=self.RUCAPTCHA_KEY, action=ControlEnm.DEL_PINGBACK.value) as instance: - assert instance.params.rucaptcha_key == self.RUCAPTCHA_KEY - assert instance.params.action == ControlEnm.DEL_PINGBACK.value + async with Control(rucaptcha_key=self.RUCAPTCHA_KEY) as instance: + assert await instance.aio_getBalance() """ Failed tests """ - def test_wrong_action(self): - with pytest.raises(ValueError): - Control(rucaptcha_key=self.RUCAPTCHA_KEY, action=self.get_random_string(5)) - - def test_context_wrong_action(self): - with pytest.raises(ValueError): - with Control(rucaptcha_key=self.RUCAPTCHA_KEY, action=self.get_random_string(5)): - pass - - @pytest.mark.asyncio - async def test_aio_context_wrong_action(self): - with pytest.raises(ValueError): - with Control(rucaptcha_key=self.RUCAPTCHA_KEY, action=self.get_random_string(5)): - pass - - @pytest.mark.asyncio - async def test_aio_wrong_action(self): - with pytest.raises(ValueError): - Control(rucaptcha_key=self.RUCAPTCHA_KEY, action=self.get_random_string(5)) - def test_report_bad(self): - instance = Control(rucaptcha_key=self.RUCAPTCHA_KEY, action=ControlEnm.REPORTBAD.value) - assert instance.params.rucaptcha_key == self.RUCAPTCHA_KEY - assert instance.params.action == ControlEnm.REPORTBAD.value - - result = instance.report(id=self.get_random_string(5)) - + instance = Control(rucaptcha_key=self.RUCAPTCHA_KEY) + result = instance.reportIncorrect(id=random.randint(20, 50)) assert isinstance(result, dict) is True - assert result["error"] is True - assert result["taskId"] is None - assert result["errorBody"] == "ERROR_WRONG_CAPTCHA_ID" - assert isinstance(result["captchaSolve"], dict) is True - assert result.keys() == ResponseSer().dict().keys() + assert result.keys() == GetTaskResultResponseSer().to_dict().keys() def test_context_report_bad(self): - with Control(rucaptcha_key=self.RUCAPTCHA_KEY, action=ControlEnm.REPORTBAD.value) as instance: - assert instance.params.rucaptcha_key == self.RUCAPTCHA_KEY - assert instance.params.action == ControlEnm.REPORTBAD.value + with Control(rucaptcha_key=self.RUCAPTCHA_KEY) as instance: + assert instance.reportIncorrect(id=random.randint(20, 50)) - @pytest.mark.asyncio async def test_aio_report_bad(self): - instance = Control(rucaptcha_key=self.RUCAPTCHA_KEY, action=ControlEnm.REPORTBAD.value) - assert instance.params.rucaptcha_key == self.RUCAPTCHA_KEY - assert instance.params.action == ControlEnm.REPORTBAD.value - - result = await instance.aio_report(id=self.get_random_string(5)) - + instance = Control(rucaptcha_key=self.RUCAPTCHA_KEY) + result = await instance.aio_reportIncorrect(id=random.randint(20, 50)) assert isinstance(result, dict) is True - assert result["error"] is True - assert result["taskId"] is None - assert result["errorBody"] == "ERROR_WRONG_CAPTCHA_ID" - assert isinstance(result["captchaSolve"], dict) is True - assert result.keys() == ResponseSer().dict().keys() + assert result.keys() == GetTaskResultResponseSer().to_dict().keys() - @pytest.mark.asyncio async def test_aio_context_report_bad(self): - async with Control(rucaptcha_key=self.RUCAPTCHA_KEY, action=ControlEnm.REPORTBAD.value) as instance: - assert instance.params.rucaptcha_key == self.RUCAPTCHA_KEY - assert instance.params.action == ControlEnm.REPORTBAD.value + async with Control(rucaptcha_key=self.RUCAPTCHA_KEY) as instance: + assert await instance.aio_reportIncorrect(id=random.randint(20, 50)) def test_report_good(self): - instance = Control(rucaptcha_key=self.RUCAPTCHA_KEY, action=ControlEnm.REPORTGOOD.value) - assert instance.params.rucaptcha_key == self.RUCAPTCHA_KEY - assert instance.params.action == ControlEnm.REPORTGOOD.value - - result = instance.report(id=self.get_random_string(5)) - + instance = Control(rucaptcha_key=self.RUCAPTCHA_KEY) + result = instance.reportCorrect(id=random.randint(20, 50)) assert isinstance(result, dict) is True - assert result["error"] is True - assert result["taskId"] is None - assert result["errorBody"] == "ERROR_WRONG_CAPTCHA_ID" - assert isinstance(result["captchaSolve"], dict) is True - assert result.keys() == ResponseSer().dict().keys() + assert result.keys() == GetTaskResultResponseSer().to_dict().keys() def test_context_report_good(self): - with Control(rucaptcha_key=self.RUCAPTCHA_KEY, action=ControlEnm.REPORTGOOD.value) as instance: - assert instance.params.rucaptcha_key == self.RUCAPTCHA_KEY - assert instance.params.action == ControlEnm.REPORTGOOD.value + with Control(rucaptcha_key=self.RUCAPTCHA_KEY) as instance: + assert instance.reportCorrect(id=random.randint(20, 50)) - @pytest.mark.asyncio async def test_aio_report_good(self): - instance = Control(rucaptcha_key=self.RUCAPTCHA_KEY, action=ControlEnm.REPORTGOOD.value) - assert instance.params.rucaptcha_key == self.RUCAPTCHA_KEY - assert instance.params.action == ControlEnm.REPORTGOOD.value + instance = Control(rucaptcha_key=self.RUCAPTCHA_KEY) - result = await instance.aio_report(id=self.get_random_string(5)) + result = await instance.aio_reportCorrect(id=random.randint(20, 50)) assert isinstance(result, dict) is True - assert result["error"] is True - assert result["taskId"] is None - assert result["errorBody"] == "ERROR_WRONG_CAPTCHA_ID" - assert isinstance(result["captchaSolve"], dict) is True - assert result.keys() == ResponseSer().dict().keys() + assert result.keys() == GetTaskResultResponseSer().to_dict().keys() - @pytest.mark.asyncio async def test_aio_context_report_good(self): - async with Control(rucaptcha_key=self.RUCAPTCHA_KEY, action=ControlEnm.REPORTGOOD.value) as instance: - assert instance.params.rucaptcha_key == self.RUCAPTCHA_KEY - assert instance.params.action == ControlEnm.REPORTGOOD.value + async with Control(rucaptcha_key=self.RUCAPTCHA_KEY) as instance: + assert await instance.aio_reportCorrect(id=random.randint(20, 50)) diff --git a/tests/test_core.py b/tests/test_core.py index edd4bbed..4038cc94 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -4,9 +4,8 @@ from tests.conftest import BaseTest from python_rucaptcha.core.base import BaseCaptcha -from python_rucaptcha.core.enums import MyEnum, GeetestEnm -from python_rucaptcha.core.config import APP_KEY, RETRIES, ASYNC_RETRIES, attempts_generator -from python_rucaptcha.core.serializer import PostRequestSer +from python_rucaptcha.core.enums import MyEnum, ControlEnm +from python_rucaptcha.core.config import RETRIES, ASYNC_RETRIES, attempts_generator class TestMain(BaseTest): @@ -21,28 +20,27 @@ def test_async_reties(self): assert isinstance(ASYNC_RETRIES, AsyncRetrying) def test_context_class_create(self): - with BaseCaptcha(rucaptcha_key=self.RUCAPTCHA_KEY, method=GeetestEnm.GEETEST.value) as bc: + with BaseCaptcha(rucaptcha_key=self.RUCAPTCHA_KEY, method=ControlEnm.control.value) as bc: pass def test_class_create(self): - bc = BaseCaptcha(rucaptcha_key=self.RUCAPTCHA_KEY, method=GeetestEnm.GEETEST.value) + bc = BaseCaptcha(rucaptcha_key=self.RUCAPTCHA_KEY, method=ControlEnm.control.value) - @pytest.mark.asyncio async def test_aio_context_class_create(self): - async with BaseCaptcha(rucaptcha_key=self.RUCAPTCHA_KEY, method=GeetestEnm.GEETEST.value) as bc: + async with BaseCaptcha(rucaptcha_key=self.RUCAPTCHA_KEY, method=ControlEnm.control.value) as bc: pass def test_custom_service(self): bc = BaseCaptcha( rucaptcha_key=self.RUCAPTCHA_KEY, - method=GeetestEnm.GEETEST.value, + method=ControlEnm.control.value, service_type=self.get_random_string(length=10), ) def test_context_custom_service(self): with BaseCaptcha( rucaptcha_key=self.RUCAPTCHA_KEY, - method=GeetestEnm.GEETEST.value, + method=ControlEnm.control.value, service_type=self.get_random_string(length=10), ) as bc: pass @@ -51,7 +49,7 @@ def test_context_custom_service(self): def test_context_custom_service_api_key(self, elements): with BaseCaptcha( rucaptcha_key=self.get_random_string(elements), - method=GeetestEnm.GEETEST.value, + method=ControlEnm.control.value, service_type=self.get_random_string(length=10), ): pass @@ -60,16 +58,15 @@ def test_context_custom_service_api_key(self, elements): def test_custom_service_api_key(self, elements): BaseCaptcha( rucaptcha_key=self.get_random_string(elements), - method=GeetestEnm.GEETEST.value, + method=ControlEnm.control.value, service_type=self.get_random_string(length=10), ) - @pytest.mark.asyncio @pytest.mark.parametrize("elements", [31, 33]) async def test_aio_context_custom_service_api_key(self, elements): async with BaseCaptcha( rucaptcha_key=self.get_random_string(elements), - method=GeetestEnm.GEETEST.value, + method=ControlEnm.control.value, service_type=self.get_random_string(length=10), ): pass @@ -83,30 +80,11 @@ def test_context_err(self): with BaseCaptcha(rucaptcha_key=self.RUCAPTCHA_KEY, method="some_method") as instance: raise ValueError - @pytest.mark.asyncio async def test_aio_context_err(self): with pytest.raises(ValueError): async with BaseCaptcha(rucaptcha_key=self.RUCAPTCHA_KEY, method="some_method") as instance: raise ValueError - @pytest.mark.parametrize("elements", [31, 33]) - def test_context_failed_api_key(self, elements): - with pytest.raises(ValueError): - with BaseCaptcha(rucaptcha_key=self.get_random_string(elements), method=GeetestEnm.GEETEST.value): - pass - - @pytest.mark.parametrize("elements", [31, 33]) - def test_failed_api_key(self, elements): - with pytest.raises(ValueError): - BaseCaptcha(rucaptcha_key=self.get_random_string(elements), method=GeetestEnm.GEETEST.value) - - @pytest.mark.asyncio - @pytest.mark.parametrize("elements", [31, 33]) - async def test_aio_context_failed_api_key(self, elements): - with pytest.raises(ValueError): - async with BaseCaptcha(rucaptcha_key=self.get_random_string(elements), method=GeetestEnm.GEETEST.value): - pass - class TestEnum(BaseTest): def test_enum_list(self): @@ -126,14 +104,3 @@ def test_attempts_generator(self): for attempt in attempts: assert isinstance(attempt, int) assert attempt == 4 - - -class TestSer(BaseTest): - def test_soft_id(self): - instance = PostRequestSer(key=self.get_random_string(length=5), method=self.get_random_string(length=5)) - assert instance.soft_id == APP_KEY - - def test_soft_id_change(self): - with pytest.raises(ValueError): - instance = PostRequestSer(key=self.get_random_string(length=5), method=self.get_random_string(length=5)) - instance.soft_id = self.get_random_string(length=5) diff --git a/tests/test_funcaptcha.py b/tests/test_funcaptcha.py index b18c3728..c136fa7c 100644 --- a/tests/test_funcaptcha.py +++ b/tests/test_funcaptcha.py @@ -3,7 +3,7 @@ from tests.conftest import BaseTest from python_rucaptcha.core.enums import FunCaptchaEnm from python_rucaptcha.fun_captcha import FunCaptcha -from python_rucaptcha.core.serializer import ResponseSer +from python_rucaptcha.core.serializer import GetTaskResultResponseSer class TestFunCaptcha(BaseTest): @@ -12,102 +12,105 @@ class TestFunCaptcha(BaseTest): "https://api.funcaptcha.com/tile-game-lite-mode/fc/api/nojs/?pkey=69A21A01-CC7B-B9C6-0F9A-E7FA06677FFC&lang=en" ) surl = "https://client-api.arkoselabs.com" - - """ - Success tests - """ + kwargs_params = { + "funcaptchaApiJSSubdomain": "sample-api.arkoselabs.com", + "userAgent": "Some specific user agent", + "proxyType": "socks5", + "proxyAddress": BaseTest.proxyAddress, + "proxyPort": BaseTest.proxyPort, + } def test_methods_exists(self): assert "captcha_handler" in FunCaptcha.__dict__.keys() assert "aio_captcha_handler" in FunCaptcha.__dict__.keys() + @pytest.mark.parametrize("method", FunCaptchaEnm.list_values()) + def test_args(self, method: str): + instance = FunCaptcha( + rucaptcha_key=self.RUCAPTCHA_KEY, + websiteURL=self.pageurl, + websitePublicKey=self.publickey, + method=method, + ) + assert instance.create_task_payload["clientKey"] == self.RUCAPTCHA_KEY + assert instance.create_task_payload["task"]["type"] == method + assert instance.create_task_payload["task"]["websiteURL"] == self.pageurl + assert instance.create_task_payload["task"]["websitePublicKey"] == self.publickey + + def test_kwargs(self): + instance = FunCaptcha( + rucaptcha_key=self.RUCAPTCHA_KEY, + websiteURL=self.pageurl, + websitePublicKey=self.publickey, + method=FunCaptchaEnm.FunCaptchaTaskProxyless, + **self.kwargs_params, + ) + assert set(self.kwargs_params.keys()).issubset(set(instance.create_task_payload["task"].keys())) + assert set(self.kwargs_params.values()).issubset(set(instance.create_task_payload["task"].values())) + + """ + Success tests + """ + def test_basic_data(self): instance = FunCaptcha( rucaptcha_key=self.RUCAPTCHA_KEY, - pageurl=self.pageurl, - publickey=self.publickey, - surl=self.surl, - method=FunCaptchaEnm.FUNCAPTCHA.value, + websiteURL=self.pageurl, + websitePublicKey=self.publickey, + method=FunCaptchaEnm.FunCaptchaTaskProxyless.value, ) - assert instance.params.rucaptcha_key == self.RUCAPTCHA_KEY - assert instance.post_payload["method"] == FunCaptchaEnm.FUNCAPTCHA.value - assert instance.post_payload["pageurl"] == self.pageurl - assert instance.post_payload["publickey"] == self.publickey - assert instance.post_payload["surl"] == self.surl result = instance.captcha_handler() assert isinstance(result, dict) is True - if result["error"] is False: - assert result["error"] is False + if not result["errorId"]: + assert result["status"] == "ready" + assert isinstance(result["solution"]["text"], str) is True assert isinstance(result["taskId"], int) is True - assert result["errorBody"] is None - assert isinstance(result["captchaSolve"], str) is True else: - assert result["error"] is True - assert isinstance(result["taskId"], int) is True - assert result["errorBody"] == "ERROR_CAPTCHA_UNSOLVABLE" + assert result["errorId"] in (1, 12) + assert result["errorCode"] == "ERROR_CAPTCHA_UNSOLVABLE" - assert result.keys() == ResponseSer().dict().keys() + assert result.keys() == GetTaskResultResponseSer().to_dict().keys() - @pytest.mark.asyncio async def test_aio_basic_data(self): instance = FunCaptcha( rucaptcha_key=self.RUCAPTCHA_KEY, - pageurl=self.pageurl, - publickey=self.publickey, - surl=self.surl, - method=FunCaptchaEnm.FUNCAPTCHA.value, + websiteURL=self.pageurl, + websitePublicKey=self.publickey, + method=FunCaptchaEnm.FunCaptchaTaskProxyless.value, ) - assert instance.params.rucaptcha_key == self.RUCAPTCHA_KEY - assert instance.post_payload["method"] == FunCaptchaEnm.FUNCAPTCHA.value - assert instance.post_payload["pageurl"] == self.pageurl - assert instance.post_payload["publickey"] == self.publickey - assert instance.post_payload["surl"] == self.surl result = await instance.aio_captcha_handler() assert isinstance(result, dict) is True - if result["error"] is False: - assert result["error"] is False + if not result["errorId"]: + assert result["status"] == "ready" + assert isinstance(result["solution"]["text"], str) is True assert isinstance(result["taskId"], int) is True - assert result["errorBody"] is None - assert isinstance(result["captchaSolve"], str) is True else: - assert result["error"] is True - assert isinstance(result["taskId"], int) is True - assert result["errorBody"] == "ERROR_CAPTCHA_UNSOLVABLE" + assert result["errorId"] in (1, 12) + assert result["errorCode"] == "ERROR_CAPTCHA_UNSOLVABLE" - assert result.keys() == ResponseSer().dict().keys() + assert result.keys() == GetTaskResultResponseSer().to_dict().keys() def test_context_basic_data(self): with FunCaptcha( rucaptcha_key=self.RUCAPTCHA_KEY, - pageurl=self.pageurl, - publickey=self.publickey, - surl=self.surl, - method=FunCaptchaEnm.FUNCAPTCHA.value, + websiteURL=self.pageurl, + websitePublicKey=self.publickey, + method=FunCaptchaEnm.FunCaptchaTaskProxyless.value, ) as instance: - assert instance.params.rucaptcha_key == self.RUCAPTCHA_KEY - assert instance.post_payload["method"] == FunCaptchaEnm.FUNCAPTCHA.value - assert instance.post_payload["pageurl"] == self.pageurl - assert instance.post_payload["publickey"] == self.publickey - assert instance.post_payload["surl"] == self.surl + assert instance.captcha_handler() - @pytest.mark.asyncio async def test_context_aio_basic_data(self): async with FunCaptcha( rucaptcha_key=self.RUCAPTCHA_KEY, - pageurl=self.pageurl, - publickey=self.publickey, - surl=self.surl, - method=FunCaptchaEnm.FUNCAPTCHA.value, + websiteURL=self.pageurl, + websitePublicKey=self.publickey, + method=FunCaptchaEnm.FunCaptchaTaskProxyless.value, ) as instance: - assert instance.params.rucaptcha_key == self.RUCAPTCHA_KEY - assert instance.post_payload["method"] == FunCaptchaEnm.FUNCAPTCHA.value - assert instance.post_payload["pageurl"] == self.pageurl - assert instance.post_payload["publickey"] == self.publickey - assert instance.post_payload["surl"] == self.surl + assert await instance.aio_captcha_handler() """ Fail tests @@ -117,8 +120,7 @@ def test_wrong_method(self): with pytest.raises(ValueError): FunCaptcha( rucaptcha_key=self.RUCAPTCHA_KEY, - pageurl=self.pageurl, - publickey=self.publickey, - surl=self.surl, + websiteURL=self.pageurl, + websitePublicKey=self.publickey, method=self.get_random_string(length=5), ) diff --git a/tests/test_geetest.py b/tests/test_geetest.py index 497f1a3c..9de7667f 100644 --- a/tests/test_geetest.py +++ b/tests/test_geetest.py @@ -1,24 +1,32 @@ import pytest +import requests from tests.conftest import BaseTest from python_rucaptcha.gee_test import GeeTest from python_rucaptcha.core.enums import GeetestEnm -from python_rucaptcha.core.serializer import ResponseSer +from python_rucaptcha.core.serializer import GetTaskResultResponseSer class TestGeeTestBase(BaseTest): pageurl = "https://www.geetest.com/en/demo" - challenge = "1ad03db8aff920037fb8117827eab171" gt = "022397c99c9f646f6477822485f30404" api_server = "api.geetest.com" + initParameters = {"captcha_id": "e392e1d7fd421dc63325744d5a2b9c73"} + @property + def challenge(self): + return requests.get("https://www.geetest.com/demo/gt/register-enFullpage-official").json()["challenge"] -class TestGeeTestCore(TestGeeTestBase): - pageurl = "https://www.geetest.com/en/demo" - challenge = "1ad03db8aff920037fb8117827eab171" - gt = "022397c99c9f646f6477822485f30404" - api_server = "api.geetest.com" +class TestGeeTestCore(TestGeeTestBase): + kwargs_params = { + "geetestApiServerSubdomain": "api-na.geetest.com", + "userAgent": "Some specific user agent", + "proxyType": "socks5", + "proxyAddress": BaseTest.proxyAddress, + "proxyPort": BaseTest.proxyPort, + "version": 4, + } """ Success tests """ @@ -27,6 +35,40 @@ def test_methods_exists(self): assert "captcha_handler" in GeeTest.__dict__.keys() assert "aio_captcha_handler" in GeeTest.__dict__.keys() + @pytest.mark.parametrize("method", GeetestEnm.list_values()) + def test_args(self, method: str): + instance = GeeTest( + rucaptcha_key=self.RUCAPTCHA_KEY, + websiteURL=self.pageurl, + method=method, + gt=self.gt, + ) + assert instance.create_task_payload["clientKey"] == self.RUCAPTCHA_KEY + assert instance.create_task_payload["task"]["type"] == method + assert instance.create_task_payload["task"]["websiteURL"] == self.pageurl + assert instance.create_task_payload["task"]["gt"] == self.gt + + def test_kwargs(self): + instance = GeeTest( + rucaptcha_key=self.RUCAPTCHA_KEY, + websiteURL=self.pageurl, + method=GeetestEnm.GeeTestTaskProxyless.value, + gt=self.gt, + **self.kwargs_params, + ) + assert set(self.kwargs_params.keys()).issubset(set(instance.create_task_payload["task"].keys())) + assert set(self.kwargs_params.values()).issubset(set(instance.create_task_payload["task"].values())) + + def test_arg_initParameters(self): + instance = GeeTest( + rucaptcha_key=self.RUCAPTCHA_KEY, + websiteURL=self.pageurl, + method=GeetestEnm.GeeTestTaskProxyless.value, + gt=self.gt, + initParameters=self.initParameters, + ) + assert self.initParameters == instance.create_task_payload["task"]["initParameters"] + class TestGeeTest(TestGeeTestBase): """ @@ -36,86 +78,44 @@ class TestGeeTest(TestGeeTestBase): def test_basic_data(self): instance = GeeTest( rucaptcha_key=self.RUCAPTCHA_KEY, + websiteURL=self.pageurl, + method=GeetestEnm.GeeTestTaskProxyless.value, gt=self.gt, - method=GeetestEnm.GEETEST.value, - pageurl=self.pageurl, - api_server=self.api_server, - new_captcha=1, ) - assert instance.params.rucaptcha_key == self.RUCAPTCHA_KEY - assert instance.post_payload["method"] == GeetestEnm.GEETEST.value - assert instance.post_payload["pageurl"] == self.pageurl - assert instance.post_payload["api_server"] == self.api_server - assert instance.post_payload["gt"] == self.gt - assert instance.post_payload["new_captcha"] == 1 result = instance.captcha_handler(challenge=self.challenge) - assert isinstance(result, dict) is True - assert result["error"] is True - assert isinstance(result["taskId"], int) is True - assert isinstance(result["errorBody"], str) is True - assert result["errorBody"] == "ERROR_CAPTCHA_UNSOLVABLE" - assert result.keys() == ResponseSer().dict().keys() + assert result.keys() == GetTaskResultResponseSer().to_dict().keys() - @pytest.mark.asyncio async def test_aio_basic_data(self): instance = GeeTest( rucaptcha_key=self.RUCAPTCHA_KEY, + websiteURL=self.pageurl, + method=GeetestEnm.GeeTestTaskProxyless.value, gt=self.gt, - method=GeetestEnm.GEETEST.value, - pageurl=self.pageurl, - api_server=self.api_server, - new_captcha=1, ) - assert instance.params.rucaptcha_key == self.RUCAPTCHA_KEY - assert instance.post_payload["method"] == GeetestEnm.GEETEST.value - assert instance.post_payload["pageurl"] == self.pageurl - assert instance.post_payload["api_server"] == self.api_server - assert instance.post_payload["gt"] == self.gt - assert instance.post_payload["new_captcha"] == 1 result = await instance.aio_captcha_handler(challenge=self.challenge) - assert isinstance(result, dict) is True - assert result["error"] is True - assert isinstance(result["taskId"], int) is True - assert isinstance(result["errorBody"], str) is True - assert result["errorBody"] == "ERROR_CAPTCHA_UNSOLVABLE" - assert result.keys() == ResponseSer().dict().keys() + assert result.keys() == GetTaskResultResponseSer().to_dict().keys() def test_context_basic_data(self): with GeeTest( rucaptcha_key=self.RUCAPTCHA_KEY, + websiteURL=self.pageurl, + method=GeetestEnm.GeeTestTaskProxyless.value, gt=self.gt, - method=GeetestEnm.GEETEST.value, - pageurl=self.pageurl, - api_server=self.api_server, - new_captcha=1, ) as instance: - assert instance.params.rucaptcha_key == self.RUCAPTCHA_KEY - assert instance.post_payload["method"] == GeetestEnm.GEETEST.value - assert instance.post_payload["pageurl"] == self.pageurl - assert instance.post_payload["api_server"] == self.api_server - assert instance.post_payload["gt"] == self.gt - assert instance.post_payload["new_captcha"] == 1 - - @pytest.mark.asyncio + assert instance.captcha_handler(challenge=self.challenge) + async def test_context_aio_basic_data(self): async with GeeTest( rucaptcha_key=self.RUCAPTCHA_KEY, + websiteURL=self.pageurl, + method=GeetestEnm.GeeTestTaskProxyless.value, gt=self.gt, - method=GeetestEnm.GEETEST.value, - pageurl=self.pageurl, - api_server=self.api_server, - new_captcha=1, ) as instance: - assert instance.params.rucaptcha_key == self.RUCAPTCHA_KEY - assert instance.post_payload["method"] == GeetestEnm.GEETEST.value - assert instance.post_payload["pageurl"] == self.pageurl - assert instance.post_payload["api_server"] == self.api_server - assert instance.post_payload["gt"] == self.gt - assert instance.post_payload["new_captcha"] == 1 + assert await instance.aio_captcha_handler(challenge=self.challenge) """ Fail tests @@ -126,39 +126,38 @@ def test_wrong_method(self): GeeTest( rucaptcha_key=self.RUCAPTCHA_KEY, gt=self.gt, - pageurl=self.pageurl, + websiteURL=self.pageurl, api_server=self.api_server, method=self.get_random_string(length=5), ) def test_wrong_method_arg(self): - with pytest.raises(ValueError): + with pytest.raises(TypeError): GeeTest( rucaptcha_key=self.RUCAPTCHA_KEY, - pageurl=self.pageurl, + websiteURL=self.pageurl, api_server=self.api_server, - method=GeetestEnm.GEETEST.value, + method=GeetestEnm.GeeTestTaskProxyless.value, ) def test_empty_challenge(self): - with pytest.raises(ValueError): + with pytest.raises(TypeError): GeeTest( rucaptcha_key=self.RUCAPTCHA_KEY, gt=self.gt, - pageurl=self.pageurl, + websiteURL=self.pageurl, api_server=self.api_server, - method=GeetestEnm.GEETEST.value, + method=GeetestEnm.GeeTestTaskProxyless.value, ).captcha_handler() - @pytest.mark.asyncio - async def test_empty_challenge_aio(self): - with pytest.raises(ValueError): + async def test_aio_empty_challenge(self): + with pytest.raises(TypeError): await GeeTest( rucaptcha_key=self.RUCAPTCHA_KEY, gt=self.gt, - pageurl=self.pageurl, + websiteURL=self.pageurl, api_server=self.api_server, - method=GeetestEnm.GEETEST.value, + method=GeetestEnm.GeeTestTaskProxyless.value, ).aio_captcha_handler() @@ -167,85 +166,53 @@ def test_basic_data(self): instance = GeeTest( rucaptcha_key=self.RUCAPTCHA_KEY, gt=self.gt, - method=GeetestEnm.GEETEST.value, - pageurl=self.pageurl, + websiteURL=self.pageurl, api_server=self.api_server, - new_captcha=1, + method=GeetestEnm.GeeTestTaskProxyless.value, + version=4, + initParameters=self.initParameters, ) - assert instance.params.rucaptcha_key == self.RUCAPTCHA_KEY - assert instance.post_payload["method"] == GeetestEnm.GEETEST.value - assert instance.post_payload["pageurl"] == self.pageurl - assert instance.post_payload["api_server"] == self.api_server - assert instance.post_payload["gt"] == self.gt - assert instance.post_payload["new_captcha"] == 1 - result = instance.captcha_handler(challenge=self.challenge) - assert isinstance(result, dict) is True - assert result["error"] is True - assert isinstance(result["taskId"], int) is True - assert isinstance(result["errorBody"], str) is True - assert result["errorBody"] == "ERROR_CAPTCHA_UNSOLVABLE" - assert result.keys() == ResponseSer().dict().keys() + assert result.keys() == GetTaskResultResponseSer().to_dict().keys() - @pytest.mark.asyncio async def test_aio_basic_data(self): instance = GeeTest( rucaptcha_key=self.RUCAPTCHA_KEY, gt=self.gt, - method=GeetestEnm.GEETEST.value, - pageurl=self.pageurl, + websiteURL=self.pageurl, api_server=self.api_server, - new_captcha=1, + method=GeetestEnm.GeeTestTaskProxyless.value, + version=4, + initParameters=self.initParameters, ) - assert instance.params.rucaptcha_key == self.RUCAPTCHA_KEY - assert instance.post_payload["method"] == GeetestEnm.GEETEST.value - assert instance.post_payload["pageurl"] == self.pageurl - assert instance.post_payload["api_server"] == self.api_server - assert instance.post_payload["gt"] == self.gt - assert instance.post_payload["new_captcha"] == 1 - result = await instance.aio_captcha_handler(challenge=self.challenge) - assert isinstance(result, dict) is True - assert result["error"] is True - assert isinstance(result["taskId"], int) is True - assert isinstance(result["errorBody"], str) is True - assert result["errorBody"] == "ERROR_CAPTCHA_UNSOLVABLE" - assert result.keys() == ResponseSer().dict().keys() + assert result.keys() == GetTaskResultResponseSer().to_dict().keys() def test_context_basic_data(self): with GeeTest( rucaptcha_key=self.RUCAPTCHA_KEY, gt=self.gt, - method=GeetestEnm.GEETEST.value, - pageurl=self.pageurl, + websiteURL=self.pageurl, api_server=self.api_server, - new_captcha=1, + method=GeetestEnm.GeeTestTaskProxyless.value, + version=4, + initParameters=self.initParameters, ) as instance: - assert instance.params.rucaptcha_key == self.RUCAPTCHA_KEY - assert instance.post_payload["method"] == GeetestEnm.GEETEST.value - assert instance.post_payload["pageurl"] == self.pageurl - assert instance.post_payload["api_server"] == self.api_server - assert instance.post_payload["gt"] == self.gt - assert instance.post_payload["new_captcha"] == 1 - - @pytest.mark.asyncio + assert instance.captcha_handler(challenge=self.challenge) + async def test_context_aio_basic_data(self): async with GeeTest( rucaptcha_key=self.RUCAPTCHA_KEY, gt=self.gt, - method=GeetestEnm.GEETEST.value, - pageurl=self.pageurl, + websiteURL=self.pageurl, api_server=self.api_server, - new_captcha=1, + method=GeetestEnm.GeeTestTaskProxyless.value, + version=4, + initParameters=self.initParameters, ) as instance: - assert instance.params.rucaptcha_key == self.RUCAPTCHA_KEY - assert instance.post_payload["method"] == GeetestEnm.GEETEST.value - assert instance.post_payload["pageurl"] == self.pageurl - assert instance.post_payload["api_server"] == self.api_server - assert instance.post_payload["gt"] == self.gt - assert instance.post_payload["new_captcha"] == 1 + assert await instance.aio_captcha_handler(challenge=self.challenge) """ Fail tests @@ -255,17 +222,21 @@ def test_wrong_method(self): with pytest.raises(ValueError): GeeTest( rucaptcha_key=self.RUCAPTCHA_KEY, - captcha_id=self.get_random_string(length=5), - pageurl=self.pageurl, + gt=self.gt, + websiteURL=self.pageurl, api_server=self.api_server, method=self.get_random_string(length=5), + version=4, + initParameters=self.initParameters, ) def test_wrong_method_arg(self): - with pytest.raises(ValueError): + with pytest.raises(TypeError): GeeTest( rucaptcha_key=self.RUCAPTCHA_KEY, - pageurl=self.pageurl, + websiteURL=self.pageurl, api_server=self.api_server, - method=GeetestEnm.GEETEST_V4.value, + method=GeetestEnm.GeeTestTaskProxyless.value, + version=4, + initParameters=self.initParameters, ) diff --git a/tests/test_hcaptcha.py b/tests/test_hcaptcha.py index aa6e4f81..ca722bb2 100644 --- a/tests/test_hcaptcha.py +++ b/tests/test_hcaptcha.py @@ -1,120 +1,50 @@ import pytest -from tests.conftest import BaseTest, DeathByTest +from tests.conftest import BaseTest from python_rucaptcha.hcaptcha import HCaptcha -from python_rucaptcha.core.enums import ServiceEnm, HCaptchaEnm -from python_rucaptcha.core.serializer import ResponseSer +from python_rucaptcha.core.enums import HCaptchaEnm +from python_rucaptcha.core.serializer import GetTaskResultResponseSer -class BaseHCaptcha(BaseTest): +class TestHCaptcha(BaseTest): sitekey = "3ceb8624-1970-4e6b-91d5-70317b70b651" pageurl = "https://rucaptcha.com/demo/hcaptcha" - - -class TestHCaptcha(BaseHCaptcha): - """ - Success tests - """ + kwargs_params = { + "isInvisible": False, + "userAgent": "Some specific user agent", + "proxyType": "socks5", + "proxyAddress": BaseTest.proxyAddress, + "proxyPort": BaseTest.proxyPort, + } def test_methods_exists(self): assert "captcha_handler" in HCaptcha.__dict__.keys() assert "aio_captcha_handler" in HCaptcha.__dict__.keys() - def test_basic_data(self): + @pytest.mark.parametrize("method", HCaptchaEnm.list_values()) + def test_args(self, method: str): instance = HCaptcha( rucaptcha_key=self.RUCAPTCHA_KEY, - sitekey=self.sitekey, - pageurl=self.pageurl, - method=HCaptchaEnm.HCAPTCHA.value, + websiteURL=self.pageurl, + websiteKey=self.sitekey, + method=method, ) - assert instance.params.rucaptcha_key == self.RUCAPTCHA_KEY - assert instance.post_payload["method"] == HCaptchaEnm.HCAPTCHA.value - assert instance.post_payload["pageurl"] == self.pageurl - assert instance.post_payload["sitekey"] == self.sitekey - - result = instance.captcha_handler() + assert instance.create_task_payload["clientKey"] == self.RUCAPTCHA_KEY + assert instance.create_task_payload["task"]["type"] == method + assert instance.create_task_payload["task"]["websiteURL"] == self.pageurl + assert instance.create_task_payload["task"]["websiteKey"] == self.sitekey - assert isinstance(result, dict) is True - if result["error"] is False: - assert result["error"] is False - assert isinstance(result["taskId"], int) is True - assert result["errorBody"] is None - assert isinstance(result["captchaSolve"], str) is True - else: - assert result["error"] is True - assert isinstance(result["taskId"], int) is True - assert result["errorBody"] == "ERROR_CAPTCHA_UNSOLVABLE" - - assert result.keys() == ResponseSer().dict().keys() - - @pytest.mark.asyncio - async def test_aio_basic_data(self): + def test_kwargs(self): instance = HCaptcha( rucaptcha_key=self.RUCAPTCHA_KEY, - sitekey=self.sitekey, - pageurl=self.pageurl, - method=HCaptchaEnm.HCAPTCHA.value, + websiteURL=self.pageurl, + websiteKey=self.sitekey, + method=HCaptchaEnm.HCaptchaTaskProxyless, + **self.kwargs_params, ) - assert instance.params.rucaptcha_key == self.RUCAPTCHA_KEY - assert instance.post_payload["method"] == HCaptchaEnm.HCAPTCHA.value - assert instance.post_payload["pageurl"] == self.pageurl - assert instance.post_payload["sitekey"] == self.sitekey - - result = await instance.aio_captcha_handler() - - assert isinstance(result, dict) is True - if result["error"] is False: - assert result["error"] is False - assert isinstance(result["taskId"], int) is True - assert result["errorBody"] is None - assert isinstance(result["captchaSolve"], str) is True - else: - assert result["error"] is True - assert isinstance(result["taskId"], int) is True - assert result["errorBody"] == "ERROR_CAPTCHA_UNSOLVABLE" - - assert result.keys() == ResponseSer().dict().keys() - - def test_context_basic_data(self): - with HCaptcha( - rucaptcha_key=self.RUCAPTCHA_KEY, - sitekey=self.sitekey, - pageurl=self.pageurl, - method=HCaptchaEnm.HCAPTCHA.value, - ) as instance: - assert instance.params.rucaptcha_key == self.RUCAPTCHA_KEY - assert instance.post_payload["method"] == HCaptchaEnm.HCAPTCHA.value - assert instance.post_payload["pageurl"] == self.pageurl - assert instance.post_payload["sitekey"] == self.sitekey - - @pytest.mark.asyncio - async def test_context_aio_basic_data(self): - async with HCaptcha( - rucaptcha_key=self.RUCAPTCHA_KEY, - sitekey=self.sitekey, - pageurl=self.pageurl, - method=HCaptchaEnm.HCAPTCHA.value, - ) as instance: - assert instance.params.rucaptcha_key == self.RUCAPTCHA_KEY - assert instance.post_payload["method"] == HCaptchaEnm.HCAPTCHA.value - assert instance.post_payload["pageurl"] == self.pageurl - assert instance.post_payload["sitekey"] == self.sitekey + assert set(self.kwargs_params.keys()).issubset(set(instance.create_task_payload["task"].keys())) + assert set(self.kwargs_params.values()).issubset(set(instance.create_task_payload["task"].values())) - """ - Fail tests - """ - - def test_wrong_method(self): - with pytest.raises(ValueError): - HCaptcha( - rucaptcha_key=self.RUCAPTCHA_KEY, - sitekey=self.sitekey, - pageurl=self.pageurl, - method=self.get_random_string(length=5), - ) - - -class TestDeathByHCaptcha(BaseHCaptcha, DeathByTest): """ Success tests """ @@ -122,87 +52,72 @@ class TestDeathByHCaptcha(BaseHCaptcha, DeathByTest): def test_basic_data(self): instance = HCaptcha( rucaptcha_key=self.RUCAPTCHA_KEY, - service_type="deathbycaptcha", - sitekey=self.sitekey, - pageurl=self.pageurl, - method=HCaptchaEnm.HCAPTCHA.value, + websiteURL=self.pageurl, + websiteKey=self.sitekey, + method=HCaptchaEnm.HCaptchaTaskProxyless.value, ) - assert instance.params.service_type == ServiceEnm.DEATHBYCAPTCHA - assert instance.params.rucaptcha_key == self.RUCAPTCHA_KEY - assert instance.post_payload["method"] == HCaptchaEnm.HCAPTCHA.value - assert instance.post_payload["pageurl"] == self.pageurl - assert instance.post_payload["sitekey"] == self.sitekey result = instance.captcha_handler() assert isinstance(result, dict) is True - if result["error"] is False: - assert result["error"] is False + if not result["errorId"]: + assert result["status"] == "ready" + assert isinstance(result["solution"], dict) is True assert isinstance(result["taskId"], int) is True - assert result["errorBody"] is None - assert isinstance(result["captchaSolve"], str) is True else: - assert result["error"] is True - assert isinstance(result["taskId"], int) is True - assert result["errorBody"] == "ERROR_CAPTCHA_UNSOLVABLE" + assert result["errorId"] in (1, 12) + assert result["errorCode"] == "ERROR_CAPTCHA_UNSOLVABLE" - assert result.keys() == ResponseSer().dict().keys() + assert result.keys() == GetTaskResultResponseSer().to_dict().keys() - @pytest.mark.asyncio async def test_aio_basic_data(self): instance = HCaptcha( rucaptcha_key=self.RUCAPTCHA_KEY, - service_type="deathbycaptcha", - sitekey=self.sitekey, - pageurl=self.pageurl, - method=HCaptchaEnm.HCAPTCHA.value, + websiteURL=self.pageurl, + websiteKey=self.sitekey, + method=HCaptchaEnm.HCaptchaTaskProxyless.value, ) - assert instance.params.service_type == ServiceEnm.DEATHBYCAPTCHA - assert instance.params.rucaptcha_key == self.RUCAPTCHA_KEY - assert instance.post_payload["method"] == HCaptchaEnm.HCAPTCHA.value - assert instance.post_payload["pageurl"] == self.pageurl - assert instance.post_payload["sitekey"] == self.sitekey result = await instance.aio_captcha_handler() assert isinstance(result, dict) is True - if result["error"] is False: - assert result["error"] is False + if not result["errorId"]: + assert result["status"] == "ready" + assert isinstance(result["solution"], dict) is True assert isinstance(result["taskId"], int) is True - assert result["errorBody"] is None - assert isinstance(result["captchaSolve"], str) is True else: - assert result["error"] is True - assert isinstance(result["taskId"], int) is True - assert result["errorBody"] == "ERROR_CAPTCHA_UNSOLVABLE" + assert result["errorId"] in (1, 12) + assert result["errorCode"] == "ERROR_CAPTCHA_UNSOLVABLE" - assert result.keys() == ResponseSer().dict().keys() + assert result.keys() == GetTaskResultResponseSer().to_dict().keys() def test_context_basic_data(self): with HCaptcha( rucaptcha_key=self.RUCAPTCHA_KEY, - service_type="deathbycaptcha", - sitekey=self.sitekey, - pageurl=self.pageurl, - method=HCaptchaEnm.HCAPTCHA.value, + websiteURL=self.pageurl, + websiteKey=self.sitekey, + method=HCaptchaEnm.HCaptchaTaskProxyless.value, ) as instance: - assert instance.params.service_type == ServiceEnm.DEATHBYCAPTCHA - assert instance.params.rucaptcha_key == self.RUCAPTCHA_KEY - assert instance.post_payload["method"] == HCaptchaEnm.HCAPTCHA.value - assert instance.post_payload["pageurl"] == self.pageurl - assert instance.post_payload["sitekey"] == self.sitekey + assert instance.captcha_handler() - @pytest.mark.asyncio async def test_context_aio_basic_data(self): async with HCaptcha( rucaptcha_key=self.RUCAPTCHA_KEY, - service_type="deathbycaptcha", - sitekey=self.sitekey, - pageurl=self.pageurl, - method=HCaptchaEnm.HCAPTCHA.value, + websiteURL=self.pageurl, + websiteKey=self.sitekey, + method=HCaptchaEnm.HCaptchaTaskProxyless.value, ) as instance: - assert instance.params.service_type == ServiceEnm.DEATHBYCAPTCHA - assert instance.params.rucaptcha_key == self.RUCAPTCHA_KEY - assert instance.post_payload["method"] == HCaptchaEnm.HCAPTCHA.value - assert instance.post_payload["pageurl"] == self.pageurl - assert instance.post_payload["sitekey"] == self.sitekey + assert await instance.aio_captcha_handler() + + """ + Fail tests + """ + + def test_wrong_method(self): + with pytest.raises(ValueError): + HCaptcha( + rucaptcha_key=self.RUCAPTCHA_KEY, + websiteURL=self.pageurl, + websiteKey=self.sitekey, + method=self.get_random_string(length=5), + ) diff --git a/tests/test_image.py b/tests/test_image.py index 76bc9da3..a9bbcc38 100644 --- a/tests/test_image.py +++ b/tests/test_image.py @@ -1,9 +1,9 @@ import pytest -from tests.conftest import BaseTest, DeathByTest -from python_rucaptcha.core.enums import ServiceEnm, SaveFormatsEnm +from tests.conftest import BaseTest +from python_rucaptcha.core.enums import SaveFormatsEnm from python_rucaptcha.image_captcha import ImageCaptcha -from python_rucaptcha.core.serializer import ResponseSer +from python_rucaptcha.core.serializer import GetTaskResultResponseSer class BaseImageCaptcha(BaseTest): @@ -12,6 +12,16 @@ class BaseImageCaptcha(BaseTest): class TestImageCaptcha(BaseImageCaptcha): + kwargs_params = { + "phrase": False, + "case": True, + "numeric": 0, + "math": False, + "minLength": 0, + "maxLength": 0, + "comment": "None", + "imgInstructions": "None", + } """ Success tests """ @@ -19,112 +29,113 @@ class TestImageCaptcha(BaseImageCaptcha): def test_methods_exists(self): assert "captcha_handler" in ImageCaptcha.__dict__.keys() assert "aio_captcha_handler" in ImageCaptcha.__dict__.keys() + instance = ImageCaptcha(rucaptcha_key=self.RUCAPTCHA_KEY) + assert instance.create_task_payload["clientKey"] == self.RUCAPTCHA_KEY + + def test_args(self): + instance = ImageCaptcha(rucaptcha_key=self.RUCAPTCHA_KEY) + assert instance.create_task_payload["clientKey"] == self.RUCAPTCHA_KEY + + def test_kwargs(self): + instance = ImageCaptcha(rucaptcha_key=self.RUCAPTCHA_KEY, **self.kwargs_params) + assert set(self.kwargs_params.keys()).issubset(set(instance.create_task_payload["task"].keys())) + assert set(self.kwargs_params.values()).issubset(set(instance.create_task_payload["task"].values())) - @pytest.mark.parametrize("save_format", [SaveFormatsEnm.TEMP, SaveFormatsEnm.CONST]) - def test_basic_data_link(self, save_format): + @pytest.mark.parametrize("save_format", SaveFormatsEnm.list_values()) + def test_basic_link(self, save_format): instance = ImageCaptcha(rucaptcha_key=self.RUCAPTCHA_KEY, save_format=save_format) - assert instance.params.rucaptcha_key == self.RUCAPTCHA_KEY result = instance.captcha_handler(captcha_link=self.captcha_url) + assert isinstance(result, dict) is True - if result["error"] is False: - assert result["error"] is False + if not result["errorId"]: + assert result["status"] == "ready" + assert isinstance(result["solution"]["text"], str) is True assert isinstance(result["taskId"], int) is True - assert result["errorBody"] is None - assert isinstance(result["captchaSolve"], str) is True else: - assert result["error"] is True - assert result["errorBody"] == "ERROR_CAPTCHA_UNSOLVABLE" - assert result.keys() == ResponseSer().dict().keys() + assert result["errorId"] in (1, 12) + assert result["errorCode"] == "ERROR_CAPTCHA_UNSOLVABLE" - @pytest.mark.parametrize("save_format", [SaveFormatsEnm.TEMP, SaveFormatsEnm.CONST]) - def test_basic_data_file(self, save_format): + @pytest.mark.parametrize("save_format", SaveFormatsEnm.list_values()) + def test_basic_file(self, save_format): instance = ImageCaptcha(rucaptcha_key=self.RUCAPTCHA_KEY, save_format=save_format) - assert instance.params.rucaptcha_key == self.RUCAPTCHA_KEY result = instance.captcha_handler(captcha_file=self.captcha_file) + assert isinstance(result, dict) is True - if result["error"] is False: - assert result["error"] is False + + if not result["errorId"]: + assert result["status"] == "ready" + assert isinstance(result["solution"]["text"], str) is True assert isinstance(result["taskId"], int) is True - assert result["errorBody"] is None - assert isinstance(result["captchaSolve"], str) is True else: - assert result["error"] is True - assert result["errorBody"] == "ERROR_CAPTCHA_UNSOLVABLE" - assert result.keys() == ResponseSer().dict().keys() + assert result["errorId"] in (1, 12) + assert result["errorCode"] == "ERROR_CAPTCHA_UNSOLVABLE" - @pytest.mark.parametrize("save_format", [SaveFormatsEnm.TEMP, SaveFormatsEnm.CONST]) - def test_basic_data_base64(self, save_format): + @pytest.mark.parametrize("save_format", SaveFormatsEnm.list_values()) + def test_basic_base64(self, save_format): instance = ImageCaptcha(rucaptcha_key=self.RUCAPTCHA_KEY, save_format=save_format) - assert instance.params.rucaptcha_key == self.RUCAPTCHA_KEY - with open(self.captcha_file, "rb") as f: result = instance.captcha_handler(captcha_base64=f.read()) assert isinstance(result, dict) is True - if result["error"] is False: - assert result["error"] is False + + if not result["errorId"]: + assert result["status"] == "ready" + assert isinstance(result["solution"]["text"], str) is True assert isinstance(result["taskId"], int) is True - assert result["errorBody"] is None - assert isinstance(result["captchaSolve"], str) is True else: - assert result["error"] is True - assert result["errorBody"] == "ERROR_CAPTCHA_UNSOLVABLE" - assert result.keys() == ResponseSer().dict().keys() + assert result["errorId"] in (1, 12) + assert result["errorCode"] == "ERROR_CAPTCHA_UNSOLVABLE" + assert result.keys() == GetTaskResultResponseSer().to_dict().keys() - @pytest.mark.asyncio - @pytest.mark.parametrize("save_format", [SaveFormatsEnm.TEMP, SaveFormatsEnm.CONST]) - async def test_aio_basic_data_link(self, save_format): + @pytest.mark.parametrize("save_format", SaveFormatsEnm.list_values()) + async def test_aio_basic_link(self, save_format): instance = ImageCaptcha(rucaptcha_key=self.RUCAPTCHA_KEY, save_format=save_format) - assert instance.params.rucaptcha_key == self.RUCAPTCHA_KEY + result = await instance.aio_captcha_handler(captcha_link=self.captcha_url) assert isinstance(result, dict) is True - if result["error"] is False: - assert result["error"] is False + + if not result["errorId"]: + assert result["status"] == "ready" + assert isinstance(result["solution"]["text"], str) is True assert isinstance(result["taskId"], int) is True - assert result["errorBody"] is None - assert isinstance(result["captchaSolve"], str) is True else: - assert result["error"] is True - assert result["errorBody"] == "ERROR_CAPTCHA_UNSOLVABLE" - assert result.keys() == ResponseSer().dict().keys() + assert result["errorId"] in (1, 12) + assert result["errorCode"] == "ERROR_CAPTCHA_UNSOLVABLE" + assert result.keys() == GetTaskResultResponseSer().to_dict().keys() - @pytest.mark.asyncio - @pytest.mark.parametrize("save_format", [SaveFormatsEnm.TEMP, SaveFormatsEnm.CONST]) - async def test_aio_basic_data_file(self, save_format): + @pytest.mark.parametrize("save_format", SaveFormatsEnm.list_values()) + async def test_aio_basic_file(self, save_format): instance = ImageCaptcha(rucaptcha_key=self.RUCAPTCHA_KEY, save_format=save_format) - assert instance.params.rucaptcha_key == self.RUCAPTCHA_KEY + result = await instance.aio_captcha_handler(captcha_file=self.captcha_file) assert isinstance(result, dict) is True - if result["error"] is False: - assert result["error"] is False + + if not result["errorId"]: + assert result["status"] == "ready" + assert isinstance(result["solution"]["text"], str) is True assert isinstance(result["taskId"], int) is True - assert result["errorBody"] is None - assert isinstance(result["captchaSolve"], str) is True else: - assert result["error"] is True - assert result["errorBody"] == "ERROR_CAPTCHA_UNSOLVABLE" - assert result.keys() == ResponseSer().dict().keys() + assert result["errorId"] in (1, 12) + assert result["errorCode"] == "ERROR_CAPTCHA_UNSOLVABLE" + assert result.keys() == GetTaskResultResponseSer().to_dict().keys() - @pytest.mark.asyncio - @pytest.mark.parametrize("save_format", [SaveFormatsEnm.TEMP, SaveFormatsEnm.CONST]) - async def test_aio_basic_data_base64(self, save_format): + @pytest.mark.parametrize("save_format", SaveFormatsEnm.list_values()) + async def test_aio_basic_base64(self, save_format): instance = ImageCaptcha(rucaptcha_key=self.RUCAPTCHA_KEY, save_format=save_format) - assert instance.params.rucaptcha_key == self.RUCAPTCHA_KEY - with open(self.captcha_file, "rb") as f: result = await instance.aio_captcha_handler(captcha_base64=f.read()) + assert isinstance(result, dict) is True - if result["error"] is False: - assert result["error"] is False + if not result["errorId"]: + assert result["status"] == "ready" + assert isinstance(result["solution"]["text"], str) is True assert isinstance(result["taskId"], int) is True - assert result["errorBody"] is None - assert isinstance(result["captchaSolve"], str) is True else: - assert result["error"] is True - assert result["errorBody"] == "ERROR_CAPTCHA_UNSOLVABLE" - assert result.keys() == ResponseSer().dict().keys() + assert result["errorId"] in (1, 12) + assert result["errorCode"] == "ERROR_CAPTCHA_UNSOLVABLE" + assert result.keys() == GetTaskResultResponseSer().to_dict().keys() """ Fail tests @@ -132,232 +143,48 @@ async def test_aio_basic_data_base64(self, save_format): def test_no_captcha(self): instance = ImageCaptcha(rucaptcha_key=self.RUCAPTCHA_KEY) - assert instance.params.rucaptcha_key == self.RUCAPTCHA_KEY result = instance.captcha_handler() assert isinstance(result, dict) is True - assert result["error"] is True - assert result["taskId"] is None - assert result["errorBody"] == ImageCaptcha.NO_CAPTCHA_ERR - assert result["captchaSolve"] == {} - assert result.keys() == ResponseSer().dict().keys() + assert result["errorId"] == 12 + assert isinstance(result["errorCode"], str) is True + assert result.keys() == GetTaskResultResponseSer().to_dict().keys() - @pytest.mark.asyncio async def test_aio_no_captcha(self): instance = ImageCaptcha(rucaptcha_key=self.RUCAPTCHA_KEY) - assert instance.params.rucaptcha_key == self.RUCAPTCHA_KEY result = await instance.aio_captcha_handler() assert isinstance(result, dict) is True - assert result["error"] is True - assert result["taskId"] is None - assert result["errorBody"] == ImageCaptcha.NO_CAPTCHA_ERR - assert result["captchaSolve"] == {} - assert result.keys() == ResponseSer().dict().keys() + assert result["errorId"] == 12 + assert isinstance(result["errorCode"], str) is True + assert result.keys() == GetTaskResultResponseSer().to_dict().keys() def test_wrong_link(self): instance = ImageCaptcha(rucaptcha_key=self.RUCAPTCHA_KEY) - assert instance.params.rucaptcha_key == self.RUCAPTCHA_KEY result = instance.captcha_handler(captcha_link=self.get_random_string(length=50)) assert isinstance(result, dict) is True - assert result["error"] is True - assert result["taskId"] is None - assert result["captchaSolve"] == {} - assert result.keys() == ResponseSer().dict().keys() + assert result["errorId"] == 12 + assert isinstance(result["errorCode"], str) is True + assert result.keys() == GetTaskResultResponseSer().to_dict().keys() def test_wrong_base64(self): instance = ImageCaptcha(rucaptcha_key=self.RUCAPTCHA_KEY) - assert instance.params.rucaptcha_key == self.RUCAPTCHA_KEY result = instance.captcha_handler(captcha_base64=self.get_random_string(length=50).encode(encoding="UTF-8")) assert isinstance(result, dict) is True - assert result["error"] is True + assert result["errorId"] == 15 assert result["taskId"] is None - assert result["captchaSolve"] == {} - assert result.keys() == ResponseSer().dict().keys() - @pytest.mark.asyncio async def test_aio_wrong_link(self): instance = ImageCaptcha(rucaptcha_key=self.RUCAPTCHA_KEY) - assert instance.params.rucaptcha_key == self.RUCAPTCHA_KEY result = await instance.aio_captcha_handler(captcha_link=self.get_random_string(length=50)) assert isinstance(result, dict) is True - assert result["error"] is True - assert result["taskId"] is None - assert result["captchaSolve"] == {} - assert result.keys() == ResponseSer().dict().keys() + assert result["errorId"] == 12 + assert isinstance(result["errorCode"], str) is True + assert result.keys() == GetTaskResultResponseSer().to_dict().keys() - @pytest.mark.asyncio async def test_aio_wrong_base64(self): instance = ImageCaptcha(rucaptcha_key=self.RUCAPTCHA_KEY) - assert instance.params.rucaptcha_key == self.RUCAPTCHA_KEY result = await instance.aio_captcha_handler( captcha_base64=self.get_random_string(length=50).encode(encoding="UTF-8") ) assert isinstance(result, dict) is True - assert result["error"] is True - assert result["taskId"] is None - assert result["captchaSolve"] == {} - assert result.keys() == ResponseSer().dict().keys() - - -class TestDeathByImageCaptcha(BaseImageCaptcha, DeathByTest): - """ - Success tests - """ - - @pytest.mark.parametrize("save_format", [SaveFormatsEnm.TEMP, SaveFormatsEnm.CONST]) - def test_basic_data_link(self, save_format): - instance = ImageCaptcha( - rucaptcha_key=self.RUCAPTCHA_KEY, service_type="deathbycaptcha", save_format=save_format - ) - - assert instance.params.service_type == ServiceEnm.DEATHBYCAPTCHA - assert instance.params.rucaptcha_key == self.RUCAPTCHA_KEY - - result = instance.captcha_handler(captcha_link=self.captcha_url) - - assert isinstance(result, dict) is True - if result["error"] is False: - assert result["error"] is False - assert isinstance(result["taskId"], int) is True - assert result["errorBody"] is None - assert isinstance(result["captchaSolve"], str) is True - else: - assert result["error"] is True - assert result["errorBody"] == "ERROR_NO_SLOT_AVAILABLE" - - assert result.keys() == ResponseSer().dict().keys() - - @pytest.mark.parametrize("save_format", [SaveFormatsEnm.TEMP, SaveFormatsEnm.CONST]) - def test_basic_data_file(self, save_format): - instance = ImageCaptcha( - rucaptcha_key=self.RUCAPTCHA_KEY, service_type="deathbycaptcha", save_format=save_format - ) - - assert instance.params.service_type == ServiceEnm.DEATHBYCAPTCHA - assert instance.params.rucaptcha_key == self.RUCAPTCHA_KEY - - result = instance.captcha_handler(captcha_file=self.captcha_file) - - assert isinstance(result, dict) is True - if result["error"] is False: - assert result["error"] is False - assert isinstance(result["taskId"], int) is True - assert result["errorBody"] is None - assert isinstance(result["captchaSolve"], str) is True - else: - assert result["error"] is True - assert result["errorBody"] == "ERROR_NO_SLOT_AVAILABLE" - - assert result.keys() == ResponseSer().dict().keys() - - @pytest.mark.asyncio - @pytest.mark.parametrize("save_format", [SaveFormatsEnm.TEMP, SaveFormatsEnm.CONST]) - async def test_aio_basic_data_link(self, save_format): - instance = ImageCaptcha( - rucaptcha_key=self.RUCAPTCHA_KEY, service_type="deathbycaptcha", save_format=save_format - ) - - assert instance.params.service_type == ServiceEnm.DEATHBYCAPTCHA - assert instance.params.rucaptcha_key == self.RUCAPTCHA_KEY - - result = await instance.aio_captcha_handler(captcha_link=self.captcha_url) - - assert isinstance(result, dict) is True - if result["error"] is False: - assert result["error"] is False - assert isinstance(result["taskId"], int) is True - assert result["errorBody"] is None - assert isinstance(result["captchaSolve"], str) is True - else: - assert result["error"] is True - assert result["errorBody"] == "ERROR_NO_SLOT_AVAILABLE" - - assert result.keys() == ResponseSer().dict().keys() - - @pytest.mark.asyncio - @pytest.mark.parametrize("save_format", [SaveFormatsEnm.TEMP, SaveFormatsEnm.CONST]) - async def test_aio_basic_data_file(self, save_format): - instance = ImageCaptcha( - rucaptcha_key=self.RUCAPTCHA_KEY, service_type="deathbycaptcha", save_format=save_format - ) - - assert instance.params.service_type == ServiceEnm.DEATHBYCAPTCHA - assert instance.params.rucaptcha_key == self.RUCAPTCHA_KEY - - result = await instance.aio_captcha_handler(captcha_file=self.captcha_file) - - assert isinstance(result, dict) is True - if result["error"] is False: - assert result["error"] is False - assert isinstance(result["taskId"], int) is True - assert result["errorBody"] is None - assert isinstance(result["captchaSolve"], str) is True - else: - assert result["error"] is True - assert result["errorBody"] == "ERROR_NO_SLOT_AVAILABLE" - - assert result.keys() == ResponseSer().dict().keys() - - """ - Fail tests - """ - - def test_no_captcha(self): - instance = ImageCaptcha(rucaptcha_key=self.RUCAPTCHA_KEY, service_type="deathbycaptcha") - - assert instance.params.service_type == ServiceEnm.DEATHBYCAPTCHA - assert instance.params.rucaptcha_key == self.RUCAPTCHA_KEY - - result = instance.captcha_handler() - - assert isinstance(result, dict) is True - assert result["error"] is True - assert result["taskId"] is None - assert result["errorBody"] == ImageCaptcha.NO_CAPTCHA_ERR - assert result["captchaSolve"] == {} - - assert result.keys() == ResponseSer().dict().keys() - - @pytest.mark.asyncio - async def test_aio_no_captcha(self): - instance = ImageCaptcha(rucaptcha_key=self.RUCAPTCHA_KEY, service_type="deathbycaptcha") - - assert instance.params.service_type == ServiceEnm.DEATHBYCAPTCHA - assert instance.params.rucaptcha_key == self.RUCAPTCHA_KEY - - result = await instance.aio_captcha_handler() - - assert isinstance(result, dict) is True - assert result["error"] is True - assert result["taskId"] is None - assert result["errorBody"] == ImageCaptcha.NO_CAPTCHA_ERR - assert result["captchaSolve"] == {} - assert result.keys() == ResponseSer().dict().keys() - - def test_wrong_link(self): - instance = ImageCaptcha(rucaptcha_key=self.RUCAPTCHA_KEY, service_type="deathbycaptcha") - - assert instance.params.service_type == ServiceEnm.DEATHBYCAPTCHA - assert instance.params.rucaptcha_key == self.RUCAPTCHA_KEY - - result = instance.captcha_handler(captcha_link=self.get_random_string(length=50)) - - assert isinstance(result, dict) is True - assert result["error"] is True - assert result["taskId"] is None - assert result["captchaSolve"] == {} - assert result.keys() == ResponseSer().dict().keys() - - @pytest.mark.asyncio - async def test_aio_wrong_link(self): - instance = ImageCaptcha(rucaptcha_key=self.RUCAPTCHA_KEY, service_type="deathbycaptcha") - - assert instance.params.service_type == ServiceEnm.DEATHBYCAPTCHA - assert instance.params.rucaptcha_key == self.RUCAPTCHA_KEY - - result = await instance.aio_captcha_handler(captcha_link=self.get_random_string(length=50)) - - assert isinstance(result, dict) is True - assert result["error"] is True + assert result["errorId"] == 15 assert result["taskId"] is None - assert result["captchaSolve"] == {} - assert result.keys() == ResponseSer().dict().keys() diff --git a/tests/test_key_captcha.py b/tests/test_key_captcha.py index f512bd1f..220e53cb 100644 --- a/tests/test_key_captcha.py +++ b/tests/test_key_captcha.py @@ -3,7 +3,7 @@ from tests.conftest import BaseTest from python_rucaptcha.core.enums import KeyCaptchaEnm from python_rucaptcha.key_captcha import KeyCaptcha -from python_rucaptcha.core.serializer import ResponseSer +from python_rucaptcha.core.serializer import GetTaskResultResponseSer class TestKeyCaptcha(BaseTest): @@ -12,7 +12,13 @@ class TestKeyCaptcha(BaseTest): s_s_c_web_server_sign = "02f7f9669f1269595c4c69bcd4a3c52e" s_s_c_web_server_sign2 = "d888700f6f324ec0f32b44c32c50bde1" pageurl = "https://rucaptcha.com/demo/keycaptcha" - + kwargs_params = { + "funcaptchaApiJSSubdomain": "sample-api.arkoselabs.com", + "userAgent": "Some specific user agent", + "proxyType": "socks5", + "proxyAddress": BaseTest.proxyAddress, + "proxyPort": BaseTest.proxyPort, + } """ Success tests """ @@ -21,107 +27,92 @@ def test_methods_exists(self): assert "captcha_handler" in KeyCaptcha.__dict__.keys() assert "aio_captcha_handler" in KeyCaptcha.__dict__.keys() + @pytest.mark.parametrize("method", KeyCaptchaEnm.list_values()) + def test_args(self, method: str): + instance = KeyCaptcha( + rucaptcha_key=self.RUCAPTCHA_KEY, + websiteURL=self.pageurl, + s_s_c_user_id=self.s_s_c_user_id, + s_s_c_session_id=self.s_s_c_session_id, + s_s_c_web_server_sign=self.s_s_c_web_server_sign, + s_s_c_web_server_sign2=self.s_s_c_web_server_sign2, + method=method, + ) + assert instance.create_task_payload["clientKey"] == self.RUCAPTCHA_KEY + assert instance.create_task_payload["task"]["type"] == method + assert instance.create_task_payload["task"]["websiteURL"] == self.pageurl + assert instance.create_task_payload["task"]["s_s_c_user_id"] == self.s_s_c_user_id + assert instance.create_task_payload["task"]["s_s_c_session_id"] == self.s_s_c_session_id + assert instance.create_task_payload["task"]["s_s_c_web_server_sign"] == self.s_s_c_web_server_sign + assert instance.create_task_payload["task"]["s_s_c_web_server_sign2"] == self.s_s_c_web_server_sign2 + + def test_kwargs(self): + instance = KeyCaptcha( + rucaptcha_key=self.RUCAPTCHA_KEY, + websiteURL=self.pageurl, + s_s_c_user_id=self.s_s_c_user_id, + s_s_c_session_id=self.s_s_c_session_id, + s_s_c_web_server_sign=self.s_s_c_web_server_sign, + s_s_c_web_server_sign2=self.s_s_c_web_server_sign2, + method=KeyCaptchaEnm.KeyCaptchaTaskProxyless, + **self.kwargs_params, + ) + assert set(self.kwargs_params.keys()).issubset(set(instance.create_task_payload["task"].keys())) + assert set(self.kwargs_params.values()).issubset(set(instance.create_task_payload["task"].values())) + def test_basic_data(self): instance = KeyCaptcha( rucaptcha_key=self.RUCAPTCHA_KEY, - pageurl=self.pageurl, + websiteURL=self.pageurl, s_s_c_user_id=self.s_s_c_user_id, s_s_c_session_id=self.s_s_c_session_id, s_s_c_web_server_sign=self.s_s_c_web_server_sign, s_s_c_web_server_sign2=self.s_s_c_web_server_sign2, - method=KeyCaptchaEnm.KEYCAPTCHA.value, + method=KeyCaptchaEnm.KeyCaptchaTaskProxyless.value, ) - assert instance.params.rucaptcha_key == self.RUCAPTCHA_KEY - assert instance.post_payload["method"] == KeyCaptchaEnm.KEYCAPTCHA.value - assert instance.post_payload["pageurl"] == self.pageurl - assert instance.post_payload["s_s_c_user_id"] == self.s_s_c_user_id - assert instance.post_payload["s_s_c_session_id"] == self.s_s_c_session_id - assert instance.post_payload["s_s_c_web_server_sign"] == self.s_s_c_web_server_sign - assert instance.post_payload["s_s_c_web_server_sign2"] == self.s_s_c_web_server_sign2 result = instance.captcha_handler() - assert isinstance(result, dict) is True - if result["error"] is False: - assert result["error"] is False - assert isinstance(result["taskId"], int) is True - assert result["errorBody"] is None - assert isinstance(result["captchaSolve"], str) is True - else: - assert result["error"] is True - assert result["errorBody"] == "ERROR_CAPTCHA_UNSOLVABLE" + assert result.keys() == GetTaskResultResponseSer().to_dict().keys() - assert result.keys() == ResponseSer().dict().keys() - - @pytest.mark.asyncio async def test_aio_basic_data(self): instance = KeyCaptcha( rucaptcha_key=self.RUCAPTCHA_KEY, - pageurl=self.pageurl, + websiteURL=self.pageurl, s_s_c_user_id=self.s_s_c_user_id, s_s_c_session_id=self.s_s_c_session_id, s_s_c_web_server_sign=self.s_s_c_web_server_sign, s_s_c_web_server_sign2=self.s_s_c_web_server_sign2, - method=KeyCaptchaEnm.KEYCAPTCHA.value, + method=KeyCaptchaEnm.KeyCaptchaTaskProxyless.value, ) - assert instance.params.rucaptcha_key == self.RUCAPTCHA_KEY - assert instance.post_payload["method"] == KeyCaptchaEnm.KEYCAPTCHA.value - assert instance.post_payload["pageurl"] == self.pageurl - assert instance.post_payload["s_s_c_user_id"] == self.s_s_c_user_id - assert instance.post_payload["s_s_c_session_id"] == self.s_s_c_session_id - assert instance.post_payload["s_s_c_web_server_sign"] == self.s_s_c_web_server_sign - assert instance.post_payload["s_s_c_web_server_sign2"] == self.s_s_c_web_server_sign2 - - result = await instance.aio_captcha_handler() - - assert isinstance(result, dict) is True - if result["error"] is False: - assert result["error"] is False - assert isinstance(result["taskId"], int) is True - assert result["errorBody"] is None - assert isinstance(result["captchaSolve"], str) is True - else: - assert result["error"] is True - assert result["errorBody"] == "ERROR_CAPTCHA_UNSOLVABLE" - - assert result.keys() == ResponseSer().dict().keys() + + result = instance.captcha_handler() + + assert result.keys() == GetTaskResultResponseSer().to_dict().keys() def test_context_basic_data(self): with KeyCaptcha( rucaptcha_key=self.RUCAPTCHA_KEY, - pageurl=self.pageurl, + websiteURL=self.pageurl, s_s_c_user_id=self.s_s_c_user_id, s_s_c_session_id=self.s_s_c_session_id, s_s_c_web_server_sign=self.s_s_c_web_server_sign, s_s_c_web_server_sign2=self.s_s_c_web_server_sign2, - method=KeyCaptchaEnm.KEYCAPTCHA.value, + method=KeyCaptchaEnm.KeyCaptchaTaskProxyless.value, ) as instance: - assert instance.params.rucaptcha_key == self.RUCAPTCHA_KEY - assert instance.post_payload["method"] == KeyCaptchaEnm.KEYCAPTCHA.value - assert instance.post_payload["pageurl"] == self.pageurl - assert instance.post_payload["s_s_c_user_id"] == self.s_s_c_user_id - assert instance.post_payload["s_s_c_session_id"] == self.s_s_c_session_id - assert instance.post_payload["s_s_c_web_server_sign"] == self.s_s_c_web_server_sign - assert instance.post_payload["s_s_c_web_server_sign2"] == self.s_s_c_web_server_sign2 - - @pytest.mark.asyncio + assert instance.captcha_handler() + async def test_context_aio_basic_data(self): async with KeyCaptcha( rucaptcha_key=self.RUCAPTCHA_KEY, - pageurl=self.pageurl, + websiteURL=self.pageurl, s_s_c_user_id=self.s_s_c_user_id, s_s_c_session_id=self.s_s_c_session_id, s_s_c_web_server_sign=self.s_s_c_web_server_sign, s_s_c_web_server_sign2=self.s_s_c_web_server_sign2, - method=KeyCaptchaEnm.KEYCAPTCHA.value, + method=KeyCaptchaEnm.KeyCaptchaTaskProxyless.value, ) as instance: - assert instance.params.rucaptcha_key == self.RUCAPTCHA_KEY - assert instance.post_payload["method"] == KeyCaptchaEnm.KEYCAPTCHA.value - assert instance.post_payload["pageurl"] == self.pageurl - assert instance.post_payload["s_s_c_user_id"] == self.s_s_c_user_id - assert instance.post_payload["s_s_c_session_id"] == self.s_s_c_session_id - assert instance.post_payload["s_s_c_web_server_sign"] == self.s_s_c_web_server_sign - assert instance.post_payload["s_s_c_web_server_sign2"] == self.s_s_c_web_server_sign2 + assert await instance.aio_captcha_handler() """ Fail tests @@ -131,7 +122,7 @@ def test_wrong_method(self): with pytest.raises(ValueError): KeyCaptcha( rucaptcha_key=self.RUCAPTCHA_KEY, - pageurl=self.pageurl, + websiteURL=self.pageurl, s_s_c_user_id=self.s_s_c_user_id, s_s_c_session_id=self.s_s_c_session_id, s_s_c_web_server_sign=self.s_s_c_web_server_sign, @@ -139,7 +130,8 @@ def test_wrong_method(self): method=self.get_random_string(length=5), ) - def test_no_pageurl(self): + @pytest.mark.parametrize("method", KeyCaptchaEnm.list_values()) + def test_no_websiteURL(self, method): with pytest.raises(TypeError): KeyCaptcha( rucaptcha_key=self.RUCAPTCHA_KEY, @@ -147,38 +139,41 @@ def test_no_pageurl(self): s_s_c_session_id=self.s_s_c_session_id, s_s_c_web_server_sign=self.s_s_c_web_server_sign, s_s_c_web_server_sign2=self.s_s_c_web_server_sign2, - method=KeyCaptchaEnm.KEYCAPTCHA.value, + method=method, ) - def test_no_s_s_c_user_id(self): + @pytest.mark.parametrize("method", KeyCaptchaEnm.list_values()) + def test_no_s_s_c_user_id(self, method: str): with pytest.raises(TypeError): KeyCaptcha( rucaptcha_key=self.RUCAPTCHA_KEY, - pageurl=self.pageurl, + websiteURL=self.pageurl, s_s_c_session_id=self.s_s_c_session_id, s_s_c_web_server_sign=self.s_s_c_web_server_sign, s_s_c_web_server_sign2=self.s_s_c_web_server_sign2, - method=KeyCaptchaEnm.KEYCAPTCHA.value, + method=method, ) - def test_no_s_s_c_web_server_sign(self): + @pytest.mark.parametrize("method", KeyCaptchaEnm.list_values()) + def test_no_s_s_c_web_server_sign(self, method: str): with pytest.raises(TypeError): KeyCaptcha( rucaptcha_key=self.RUCAPTCHA_KEY, - pageurl=self.pageurl, + websiteURL=self.pageurl, s_s_c_user_id=self.s_s_c_user_id, s_s_c_session_id=self.s_s_c_session_id, s_s_c_web_server_sign2=self.s_s_c_web_server_sign2, - method=KeyCaptchaEnm.KEYCAPTCHA.value, + method=method, ) - def test_no_s_s_c_web_server_sign2(self): + @pytest.mark.parametrize("method", KeyCaptchaEnm.list_values()) + def test_no_s_s_c_web_server_sign2(self, method: str): with pytest.raises(TypeError): KeyCaptcha( rucaptcha_key=self.RUCAPTCHA_KEY, - pageurl=self.pageurl, + websiteURL=self.pageurl, s_s_c_user_id=self.s_s_c_user_id, s_s_c_session_id=self.s_s_c_session_id, s_s_c_web_server_sign=self.s_s_c_web_server_sign, - method=KeyCaptchaEnm.KEYCAPTCHA.value, + method=method, ) diff --git a/tests/test_lemin.py b/tests/test_lemin.py index 85bd632c..a585b87f 100644 --- a/tests/test_lemin.py +++ b/tests/test_lemin.py @@ -1,9 +1,9 @@ import pytest from tests.conftest import BaseTest -from python_rucaptcha.core.enums import LeminCroppedCaptchaEnm -from python_rucaptcha.core.serializer import ResponseSer -from python_rucaptcha.lemin_cropped_captcha import LeminCroppedCaptcha +from python_rucaptcha.core.enums import LeminCaptchaEnm +from python_rucaptcha.lemin_captcha import LeminCaptcha +from python_rucaptcha.core.serializer import GetTaskResultResponseSer class TestLeminCroppedCaptcha(BaseTest): @@ -11,104 +11,94 @@ class TestLeminCroppedCaptcha(BaseTest): api_server = "api.leminnow.com" div_id = "lemin-cropped-captcha" captcha_id = "CROPPED_099216d_8ba061383fa24ef498115023aa7189d4" + kwargs_params = { + "leminApiServerSubdomain": "https://api.leminnow.com/", + "userAgent": "Some specific user agent", + "proxyType": "socks5", + "proxyAddress": BaseTest.proxyAddress, + "proxyPort": BaseTest.proxyPort, + } + + def test_methods_exists(self): + assert "captcha_handler" in LeminCaptcha.__dict__.keys() + assert "aio_captcha_handler" in LeminCaptcha.__dict__.keys() + + @pytest.mark.parametrize("method", LeminCaptchaEnm.list_values()) + def test_args(self, method: str): + instance = LeminCaptcha( + rucaptcha_key=self.RUCAPTCHA_KEY, + websiteURL=self.pageurl, + captchaId=self.captcha_id, + div_id=self.div_id, + method=method, + ) + assert instance.create_task_payload["clientKey"] == self.RUCAPTCHA_KEY + assert instance.create_task_payload["task"]["type"] == method + assert instance.create_task_payload["task"]["websiteURL"] == self.pageurl + + def test_kwargs(self): + instance = LeminCaptcha( + rucaptcha_key=self.RUCAPTCHA_KEY, + websiteURL=self.pageurl, + captchaId=self.captcha_id, + div_id=self.div_id, + method=LeminCaptchaEnm.LeminTaskProxyless, + **self.kwargs_params, + ) + assert set(self.kwargs_params.keys()).issubset(set(instance.create_task_payload["task"].keys())) + assert set(self.kwargs_params.values()).issubset(set(instance.create_task_payload["task"].values())) """ Success tests """ - def test_methods_exists(self): - assert "captcha_handler" in LeminCroppedCaptcha.__dict__.keys() - assert "aio_captcha_handler" in LeminCroppedCaptcha.__dict__.keys() - def test_basic_data(self): - instance = LeminCroppedCaptcha( + instance = LeminCaptcha( rucaptcha_key=self.RUCAPTCHA_KEY, - pageurl=self.pageurl, - captcha_id=self.captcha_id, + websiteURL=self.pageurl, + captchaId=self.captcha_id, div_id=self.div_id, api_server=self.api_server, - method=LeminCroppedCaptchaEnm.LEMIN.value, + method=LeminCaptchaEnm.LeminTaskProxyless.value, ) - assert instance.params.rucaptcha_key == self.RUCAPTCHA_KEY - assert instance.post_payload["method"] == LeminCroppedCaptchaEnm.LEMIN.value - assert instance.post_payload["pageurl"] == self.pageurl - assert instance.post_payload["captcha_id"] == self.captcha_id - assert instance.post_payload["div_id"] == self.div_id - assert instance.post_payload["api_server"] == self.api_server result = instance.captcha_handler() - assert isinstance(result, dict) is True - if result["error"] is False: - assert result["error"] is False - assert isinstance(result["taskId"], int) is True - assert result["errorBody"] is None - assert isinstance(result["captchaSolve"], dict) is True - else: - assert result["error"] is True - assert result["errorBody"] == "ERROR_CAPTCHA_UNSOLVABLE" - - assert result.keys() == ResponseSer().dict().keys() + assert result.keys() == GetTaskResultResponseSer().to_dict().keys() - @pytest.mark.asyncio async def test_aio_basic_data(self): - instance = LeminCroppedCaptcha( + instance = LeminCaptcha( rucaptcha_key=self.RUCAPTCHA_KEY, - pageurl=self.pageurl, - captcha_id=self.captcha_id, + websiteURL=self.pageurl, + captchaId=self.captcha_id, div_id=self.div_id, api_server=self.api_server, - method=LeminCroppedCaptchaEnm.LEMIN.value, + method=LeminCaptchaEnm.LeminTaskProxyless.value, ) - assert instance.params.rucaptcha_key == self.RUCAPTCHA_KEY - assert instance.post_payload["method"] == LeminCroppedCaptchaEnm.LEMIN.value - assert instance.post_payload["pageurl"] == self.pageurl - assert instance.post_payload["captcha_id"] == self.captcha_id - assert instance.post_payload["div_id"] == self.div_id - assert instance.post_payload["api_server"] == self.api_server result = await instance.aio_captcha_handler() - assert isinstance(result, dict) is True - if result["error"] is False: - assert result["error"] is False - assert isinstance(result["taskId"], int) is True - assert result["errorBody"] is None - assert isinstance(result["captchaSolve"], dict) is True - else: - assert result["error"] is True - assert result["errorBody"] == "ERROR_CAPTCHA_UNSOLVABLE" - - assert result.keys() == ResponseSer().dict().keys() + assert result.keys() == GetTaskResultResponseSer().to_dict().keys() def test_context_basic_data(self): - with LeminCroppedCaptcha( + with LeminCaptcha( rucaptcha_key=self.RUCAPTCHA_KEY, - pageurl=self.pageurl, - captcha_id=self.captcha_id, + websiteURL=self.pageurl, + captchaId=self.captcha_id, div_id=self.div_id, - method=LeminCroppedCaptchaEnm.LEMIN.value, + method=LeminCaptchaEnm.LeminTaskProxyless.value, ) as instance: - assert instance.params.rucaptcha_key == self.RUCAPTCHA_KEY - assert instance.post_payload["method"] == LeminCroppedCaptchaEnm.LEMIN.value - assert instance.post_payload["pageurl"] == self.pageurl - assert instance.post_payload["captcha_id"] == self.captcha_id - assert instance.post_payload["div_id"] == self.div_id + assert instance.captcha_handler() - @pytest.mark.asyncio async def test_context_aio_basic_data(self): - async with LeminCroppedCaptcha( + async with LeminCaptcha( rucaptcha_key=self.RUCAPTCHA_KEY, - pageurl=self.pageurl, - captcha_id=self.captcha_id, + websiteURL=self.pageurl, + captchaId=self.captcha_id, div_id=self.div_id, - method=LeminCroppedCaptchaEnm.LEMIN.value, + method=LeminCaptchaEnm.LeminTaskProxyless.value, ) as instance: - assert instance.params.rucaptcha_key == self.RUCAPTCHA_KEY - assert instance.post_payload["method"] == LeminCroppedCaptchaEnm.LEMIN.value - assert instance.post_payload["pageurl"] == self.pageurl - assert instance.post_payload["captcha_id"] == self.captcha_id - assert instance.post_payload["div_id"] == self.div_id + assert await instance.aio_captcha_handler() """ Fail tests @@ -116,38 +106,38 @@ async def test_context_aio_basic_data(self): def test_wrong_method(self): with pytest.raises(ValueError): - LeminCroppedCaptcha( + LeminCaptcha( rucaptcha_key=self.RUCAPTCHA_KEY, - pageurl=self.pageurl, - captcha_id=self.captcha_id, + websiteURL=self.pageurl, + captchaId=self.captcha_id, div_id=self.div_id, api_server=self.api_server, method=self.get_random_string(length=5), ) - def test_no_pageurl(self): + def test_no_websiteURL(self): with pytest.raises(TypeError): - LeminCroppedCaptcha( + LeminCaptcha( rucaptcha_key=self.RUCAPTCHA_KEY, - captcha_id=self.captcha_id, + captchaId=self.captcha_id, div_id=self.div_id, method=self.get_random_string(length=5), ) def test_no_div_id(self): with pytest.raises(TypeError): - LeminCroppedCaptcha( + LeminCaptcha( rucaptcha_key=self.RUCAPTCHA_KEY, - pageurl=self.pageurl, - captcha_id=self.captcha_id, + websiteURL=self.pageurl, + captchaId=self.captcha_id, method=self.get_random_string(length=5), ) - def test_no_captcha_id(self): + def test_no_captchaId(self): with pytest.raises(TypeError): - LeminCroppedCaptcha( + LeminCaptcha( rucaptcha_key=self.RUCAPTCHA_KEY, - pageurl=self.pageurl, + websiteURL=self.pageurl, div_id=self.div_id, method=self.get_random_string(length=5), ) diff --git a/tests/test_recaptcha.py b/tests/test_recaptcha.py index 27041832..e4a2db0a 100644 --- a/tests/test_recaptcha.py +++ b/tests/test_recaptcha.py @@ -1,17 +1,47 @@ import pytest -from tests.conftest import BaseTest, DeathByTest -from python_rucaptcha.core.enums import ServiceEnm, ReCaptchaEnm +from tests.conftest import BaseTest +from python_rucaptcha.core.enums import ReCaptchaEnm from python_rucaptcha.re_captcha import ReCaptcha -from python_rucaptcha.core.serializer import ResponseSer +from python_rucaptcha.core.serializer import GetTaskResultResponseSer -class BaseReCaptcha(BaseTest): +class TestReCaptcha(BaseTest): googlekey = "6LeIxboZAAAAAFQy7d8GPzgRZu2bV0GwKS8ue_cH" pageurl = "https://rucaptcha.com/demo/recaptcha-v2" + kwargs_params = { + "recaptchaDataSValue": "sample-recaptchaDataSValue", + "isInvisible": True, + "userAgent": "Some specific user agent", + "proxyType": "socks5", + "proxyAddress": BaseTest.proxyAddress, + "proxyPort": BaseTest.proxyPort, + } + + @pytest.mark.parametrize("method", ReCaptchaEnm.list_values()) + def test_args(self, method: str): + instance = ReCaptcha( + rucaptcha_key=self.RUCAPTCHA_KEY, + websiteURL=self.pageurl, + websiteKey=self.googlekey, + method=method, + ) + assert instance.create_task_payload["clientKey"] == self.RUCAPTCHA_KEY + assert instance.create_task_payload["task"]["type"] == method + assert instance.create_task_payload["task"]["websiteURL"] == self.pageurl + assert instance.create_task_payload["task"]["websiteKey"] == self.googlekey + def test_kwargs(self): + instance = ReCaptcha( + rucaptcha_key=self.RUCAPTCHA_KEY, + websiteURL=self.pageurl, + websiteKey=self.googlekey, + method=ReCaptchaEnm.RecaptchaV2TaskProxyless, + **self.kwargs_params, + ) + assert set(self.kwargs_params.keys()).issubset(set(instance.create_task_payload["task"].keys())) + assert set(self.kwargs_params.values()).issubset(set(instance.create_task_payload["task"].values())) -class TestReCaptcha(BaseReCaptcha): """ Success tests """ @@ -23,82 +53,62 @@ def test_methods_exists(self): def test_basic_data(self): instance = ReCaptcha( rucaptcha_key=self.RUCAPTCHA_KEY, - pageurl=self.pageurl, - googlekey=self.googlekey, - method=ReCaptchaEnm.USER_RECAPTCHA.value, + websiteURL=self.pageurl, + websiteKey=self.googlekey, + method=ReCaptchaEnm.RecaptchaV2TaskProxyless.value, ) - assert instance.params.rucaptcha_key == self.RUCAPTCHA_KEY - assert instance.post_payload["method"] == ReCaptchaEnm.USER_RECAPTCHA.value - assert instance.post_payload["pageurl"] == self.pageurl - assert instance.post_payload["googlekey"] == self.googlekey result = instance.captcha_handler() assert isinstance(result, dict) is True - if result["error"] is False: - assert result["error"] is False + if not result["errorId"]: + assert result["status"] == "ready" + assert isinstance(result["solution"], dict) is True assert isinstance(result["taskId"], int) is True - assert result["errorBody"] is None - assert isinstance(result["captchaSolve"], str) is True else: - assert result["error"] is True - assert isinstance(result["taskId"], int) is True - assert result["errorBody"] == "ERROR_CAPTCHA_UNSOLVABLE" + assert result["errorId"] in (1, 12) + assert result["errorCode"] == "ERROR_CAPTCHA_UNSOLVABLE" - assert result.keys() == ResponseSer().dict().keys() + assert result.keys() == GetTaskResultResponseSer().to_dict().keys() - @pytest.mark.asyncio async def test_aio_basic_data(self): instance = ReCaptcha( rucaptcha_key=self.RUCAPTCHA_KEY, - pageurl=self.pageurl, - googlekey=self.googlekey, - method=ReCaptchaEnm.USER_RECAPTCHA.value, + websiteURL=self.pageurl, + websiteKey=self.googlekey, + method=ReCaptchaEnm.RecaptchaV2TaskProxyless.value, ) - assert instance.params.rucaptcha_key == self.RUCAPTCHA_KEY - assert instance.post_payload["method"] == ReCaptchaEnm.USER_RECAPTCHA.value - assert instance.post_payload["pageurl"] == self.pageurl - assert instance.post_payload["googlekey"] == self.googlekey result = await instance.aio_captcha_handler() assert isinstance(result, dict) is True - if result["error"] is False: - assert result["error"] is False + if not result["errorId"]: + assert result["status"] == "ready" + assert isinstance(result["solution"], dict) is True assert isinstance(result["taskId"], int) is True - assert result["errorBody"] is None - assert isinstance(result["captchaSolve"], str) is True else: - assert result["error"] is True - assert isinstance(result["taskId"], int) is True - assert result["errorBody"] == "ERROR_CAPTCHA_UNSOLVABLE" + assert result["errorId"] in (1, 12) + assert result["errorCode"] == "ERROR_CAPTCHA_UNSOLVABLE" - assert result.keys() == ResponseSer().dict().keys() + assert result.keys() == GetTaskResultResponseSer().to_dict().keys() def test_context_basic_data(self): with ReCaptcha( rucaptcha_key=self.RUCAPTCHA_KEY, - pageurl=self.pageurl, - googlekey=self.googlekey, - method=ReCaptchaEnm.USER_RECAPTCHA.value, + websiteURL=self.pageurl, + websiteKey=self.googlekey, + method=ReCaptchaEnm.RecaptchaV2TaskProxyless.value, ) as instance: - assert instance.params.rucaptcha_key == self.RUCAPTCHA_KEY - assert instance.post_payload["method"] == ReCaptchaEnm.USER_RECAPTCHA.value - assert instance.post_payload["pageurl"] == self.pageurl - assert instance.post_payload["googlekey"] == self.googlekey + assert instance.captcha_handler() - @pytest.mark.asyncio async def test_context_aio_basic_data(self): async with ReCaptcha( rucaptcha_key=self.RUCAPTCHA_KEY, - pageurl=self.pageurl, - googlekey=self.googlekey, - method=ReCaptchaEnm.USER_RECAPTCHA.value, + websiteURL=self.pageurl, + websiteKey=self.googlekey, + method=ReCaptchaEnm.RecaptchaV2TaskProxyless.value, ) as instance: - assert instance.params.rucaptcha_key == self.RUCAPTCHA_KEY - assert instance.post_payload["method"] == ReCaptchaEnm.USER_RECAPTCHA.value - assert instance.post_payload["pageurl"] == self.pageurl - assert instance.post_payload["googlekey"] == self.googlekey + assert await instance.aio_captcha_handler() """ Fail tests @@ -108,101 +118,7 @@ def test_wrong_method(self): with pytest.raises(ValueError): ReCaptcha( rucaptcha_key=self.RUCAPTCHA_KEY, - pageurl=self.pageurl, - googlekey=self.googlekey, + websiteURL=self.pageurl, + websiteKey=self.googlekey, method=self.get_random_string(length=5), ) - - -class TestDeathByReCaptcha(BaseReCaptcha, DeathByTest): - """ - Success tests - """ - - def test_basic_data(self): - instance = ReCaptcha( - rucaptcha_key=self.RUCAPTCHA_KEY, - service_type="deathbycaptcha", - pageurl=self.pageurl, - googlekey=self.googlekey, - method=ReCaptchaEnm.USER_RECAPTCHA.value, - ) - assert instance.params.service_type == ServiceEnm.DEATHBYCAPTCHA - assert instance.params.rucaptcha_key == self.RUCAPTCHA_KEY - assert instance.post_payload["method"] == ReCaptchaEnm.USER_RECAPTCHA.value - assert instance.post_payload["pageurl"] == self.pageurl - assert instance.post_payload["googlekey"] == self.googlekey - - result = instance.captcha_handler() - - assert isinstance(result, dict) is True - if result["error"] is False: - assert result["error"] is False - assert isinstance(result["taskId"], int) is True - assert result["errorBody"] is None - assert isinstance(result["captchaSolve"], str) is True - else: - assert result["error"] is True - assert isinstance(result["taskId"], int) is True - assert result["errorBody"] == "ERROR_CAPTCHA_UNSOLVABLE" - - assert result.keys() == ResponseSer().dict().keys() - - @pytest.mark.asyncio - async def test_aio_basic_data(self): - instance = ReCaptcha( - rucaptcha_key=self.RUCAPTCHA_KEY, - service_type="deathbycaptcha", - pageurl=self.pageurl, - googlekey=self.googlekey, - method=ReCaptchaEnm.USER_RECAPTCHA.value, - ) - assert instance.params.service_type == ServiceEnm.DEATHBYCAPTCHA - assert instance.params.rucaptcha_key == self.RUCAPTCHA_KEY - assert instance.post_payload["method"] == ReCaptchaEnm.USER_RECAPTCHA.value - assert instance.post_payload["pageurl"] == self.pageurl - assert instance.post_payload["googlekey"] == self.googlekey - - result = await instance.aio_captcha_handler() - - assert isinstance(result, dict) is True - if result["error"] is False: - assert result["error"] is False - assert isinstance(result["taskId"], int) is True - assert result["errorBody"] is None - assert isinstance(result["captchaSolve"], str) is True - else: - assert result["error"] is True - assert isinstance(result["taskId"], int) is True - assert result["errorBody"] == "ERROR_CAPTCHA_UNSOLVABLE" - - assert result.keys() == ResponseSer().dict().keys() - - def test_context_basic_data(self): - with ReCaptcha( - rucaptcha_key=self.RUCAPTCHA_KEY, - service_type="deathbycaptcha", - pageurl=self.pageurl, - googlekey=self.googlekey, - method=ReCaptchaEnm.USER_RECAPTCHA.value, - ) as instance: - assert instance.params.service_type == ServiceEnm.DEATHBYCAPTCHA - assert instance.params.rucaptcha_key == self.RUCAPTCHA_KEY - assert instance.post_payload["method"] == ReCaptchaEnm.USER_RECAPTCHA.value - assert instance.post_payload["pageurl"] == self.pageurl - assert instance.post_payload["googlekey"] == self.googlekey - - @pytest.mark.asyncio - async def test_context_aio_basic_data(self): - async with ReCaptcha( - rucaptcha_key=self.RUCAPTCHA_KEY, - service_type="deathbycaptcha", - pageurl=self.pageurl, - googlekey=self.googlekey, - method=ReCaptchaEnm.USER_RECAPTCHA.value, - ) as instance: - assert instance.params.service_type == ServiceEnm.DEATHBYCAPTCHA - assert instance.params.rucaptcha_key == self.RUCAPTCHA_KEY - assert instance.post_payload["method"] == ReCaptchaEnm.USER_RECAPTCHA.value - assert instance.post_payload["pageurl"] == self.pageurl - assert instance.post_payload["googlekey"] == self.googlekey diff --git a/tests/test_rotate.py b/tests/test_rotate.py index a3f1418b..2eb4107a 100644 --- a/tests/test_rotate.py +++ b/tests/test_rotate.py @@ -1,231 +1,219 @@ import pytest from tests.conftest import BaseTest +from python_rucaptcha.core.enums import SaveFormatsEnm, RotateCaptchaEnm from python_rucaptcha.rotate_captcha import RotateCaptcha -from python_rucaptcha.core.serializer import ResponseSer +from python_rucaptcha.core.serializer import GetTaskResultResponseSer class TestRotateCaptcha(BaseTest): captcha_file = "src/examples/rotate/rotate_ex.png" captcha_url = "https://rucaptcha.com/dist/web/b771cc7c5eb0c1a811fcb91d54e4443a.png" - - """ - Success tests - """ + kwargs_params = { + "angle": 45, + "comment": "comment comm entcomm entcomment", + } def test_methods_exists(self): assert "captcha_handler" in RotateCaptcha.__dict__.keys() assert "aio_captcha_handler" in RotateCaptcha.__dict__.keys() - def test_basic_data_link(self): + def test_args(self): instance = RotateCaptcha(rucaptcha_key=self.RUCAPTCHA_KEY) + assert instance.create_task_payload["clientKey"] == self.RUCAPTCHA_KEY + assert instance.create_task_payload["task"]["type"] == RotateCaptchaEnm.RotateTask - assert instance.params.rucaptcha_key == self.RUCAPTCHA_KEY + def test_kwargs(self): + instance = RotateCaptcha( + rucaptcha_key=self.RUCAPTCHA_KEY, + **self.kwargs_params, + ) + assert set(self.kwargs_params.keys()).issubset(set(instance.create_task_payload["task"].keys())) + assert set(self.kwargs_params.values()).issubset(set(instance.create_task_payload["task"].values())) + + """ + Success tests + """ + + def test_basic_data_link(self): + instance = RotateCaptcha(rucaptcha_key=self.RUCAPTCHA_KEY) result = instance.captcha_handler(captcha_link=self.captcha_url) assert isinstance(result, dict) is True - if result["error"] is False: - assert result["error"] is False + if not result["errorId"]: + assert result["status"] == "ready" + assert isinstance(result["solution"]["rotate"], int) is True assert isinstance(result["taskId"], int) is True - assert result["errorBody"] is None - assert isinstance(result["captchaSolve"], str) is True else: - assert result["error"] is True - assert result["errorBody"] == "ERROR_CAPTCHA_UNSOLVABLE" + assert result["errorId"] in (1, 12) + assert result["errorCode"] == "ERROR_CAPTCHA_UNSOLVABLE" - assert result.keys() == ResponseSer().dict().keys() + assert result.keys() == GetTaskResultResponseSer().to_dict().keys() def test_basic_data_file(self): instance = RotateCaptcha(rucaptcha_key=self.RUCAPTCHA_KEY) - assert instance.params.rucaptcha_key == self.RUCAPTCHA_KEY - result = instance.captcha_handler(captcha_file=self.captcha_file) assert isinstance(result, dict) is True - if result["error"] is False: - assert result["error"] is False + if not result["errorId"]: + assert result["status"] == "ready" + assert isinstance(result["solution"]["rotate"], int) is True assert isinstance(result["taskId"], int) is True - assert result["errorBody"] is None - assert isinstance(result["captchaSolve"], str) is True else: - assert result["error"] is True - assert result["errorBody"] == "ERROR_CAPTCHA_UNSOLVABLE" + assert result["errorId"] in (1, 12) + assert result["errorCode"] == "ERROR_CAPTCHA_UNSOLVABLE" - assert result.keys() == ResponseSer().dict().keys() + assert result.keys() == GetTaskResultResponseSer().to_dict().keys() def test_basic_data_base64(self): instance = RotateCaptcha(rucaptcha_key=self.RUCAPTCHA_KEY) - assert instance.params.rucaptcha_key == self.RUCAPTCHA_KEY - with open(self.captcha_file, "rb") as f: result = instance.captcha_handler(captcha_base64=f.read()) assert isinstance(result, dict) is True - if result["error"] is False: - assert result["error"] is False + if not result["errorId"]: + assert result["status"] == "ready" + assert isinstance(result["solution"]["rotate"], int) is True assert isinstance(result["taskId"], int) is True - assert result["errorBody"] is None - assert isinstance(result["captchaSolve"], str) is True else: - assert result["error"] is True - assert result["errorBody"] == "ERROR_CAPTCHA_UNSOLVABLE" + assert result["errorId"] in (1, 12) + assert result["errorCode"] == "ERROR_CAPTCHA_UNSOLVABLE" - assert result.keys() == ResponseSer().dict().keys() + assert result.keys() == GetTaskResultResponseSer().to_dict().keys() - @pytest.mark.asyncio async def test_aio_basic_data_link(self): instance = RotateCaptcha(rucaptcha_key=self.RUCAPTCHA_KEY) - assert instance.params.rucaptcha_key == self.RUCAPTCHA_KEY - result = await instance.aio_captcha_handler(captcha_link=self.captcha_url) assert isinstance(result, dict) is True - if result["error"] is False: - assert result["error"] is False + if not result["errorId"]: + assert result["status"] == "ready" + assert isinstance(result["solution"]["rotate"], int) is True assert isinstance(result["taskId"], int) is True - assert result["errorBody"] is None - assert isinstance(result["captchaSolve"], str) is True else: - assert result["error"] is True - assert result["errorBody"] == "ERROR_CAPTCHA_UNSOLVABLE" + assert result["errorId"] in (1, 12) + assert result["errorCode"] == "ERROR_CAPTCHA_UNSOLVABLE" - assert result.keys() == ResponseSer().dict().keys() + assert result.keys() == GetTaskResultResponseSer().to_dict().keys() - @pytest.mark.asyncio async def test_aio_basic_data_file(self): instance = RotateCaptcha(rucaptcha_key=self.RUCAPTCHA_KEY) - assert instance.params.rucaptcha_key == self.RUCAPTCHA_KEY - result = await instance.aio_captcha_handler(captcha_file=self.captcha_file) assert isinstance(result, dict) is True - if result["error"] is False: - assert result["error"] is False + if not result["errorId"]: + assert result["status"] == "ready" + assert isinstance(result["solution"]["rotate"], int) is True assert isinstance(result["taskId"], int) is True - assert result["errorBody"] is None - assert isinstance(result["captchaSolve"], str) is True else: - assert result["error"] is True - assert result["errorBody"] == "ERROR_CAPTCHA_UNSOLVABLE" + assert result["errorId"] in (1, 12) + assert result["errorCode"] == "ERROR_CAPTCHA_UNSOLVABLE" - assert result.keys() == ResponseSer().dict().keys() + assert result.keys() == GetTaskResultResponseSer().to_dict().keys() - @pytest.mark.asyncio async def test_aio_basic_data_base64(self): instance = RotateCaptcha(rucaptcha_key=self.RUCAPTCHA_KEY) - assert instance.params.rucaptcha_key == self.RUCAPTCHA_KEY - with open(self.captcha_file, "rb") as f: result = await instance.aio_captcha_handler(captcha_base64=f.read()) assert isinstance(result, dict) is True - if result["error"] is False: - assert result["error"] is False + if not result["errorId"]: + assert result["status"] == "ready" + assert isinstance(result["solution"]["rotate"], int) is True assert isinstance(result["taskId"], int) is True - assert result["errorBody"] is None - assert isinstance(result["captchaSolve"], str) is True else: - assert result["error"] is True - assert result["errorBody"] == "ERROR_CAPTCHA_UNSOLVABLE" + assert result["errorId"] in (1, 12) + assert result["errorCode"] == "ERROR_CAPTCHA_UNSOLVABLE" + + assert result.keys() == GetTaskResultResponseSer().to_dict().keys() - assert result.keys() == ResponseSer().dict().keys() + @pytest.mark.parametrize("save_format", SaveFormatsEnm.list_values()) + @pytest.mark.parametrize("img_clearing", (True, False)) + def test_const_data_link(self, save_format: str, img_clearing: bool): + instance = RotateCaptcha(rucaptcha_key=self.RUCAPTCHA_KEY, save_format=save_format, img_clearing=img_clearing) + + result = instance.captcha_handler(captcha_link=self.captcha_url) + + assert isinstance(result, dict) is True + if not result["errorId"]: + assert result["status"] == "ready" + assert isinstance(result["solution"]["rotate"], int) is True + assert isinstance(result["taskId"], int) is True + else: + assert result["errorId"] in (1, 12) + assert result["errorCode"] == "ERROR_CAPTCHA_UNSOLVABLE" + + assert result.keys() == GetTaskResultResponseSer().to_dict().keys() """ Fail tests """ - def test_wrong_method(self): - with pytest.raises(ValueError): - RotateCaptcha(rucaptcha_key=self.RUCAPTCHA_KEY, method=self.get_random_string(length=5)) - def test_no_captcha(self): instance = RotateCaptcha(rucaptcha_key=self.RUCAPTCHA_KEY) - assert instance.params.rucaptcha_key == self.RUCAPTCHA_KEY - result = instance.captcha_handler() assert isinstance(result, dict) is True - assert result["error"] is True + assert result["errorId"] != 0 assert result["taskId"] is None - assert result["errorBody"] == RotateCaptcha.NO_CAPTCHA_ERR - assert result["captchaSolve"] == {} - assert result.keys() == ResponseSer().dict().keys() + assert result.keys() == GetTaskResultResponseSer().to_dict().keys() - @pytest.mark.asyncio async def test_aio_no_captcha(self): instance = RotateCaptcha(rucaptcha_key=self.RUCAPTCHA_KEY) - assert instance.params.rucaptcha_key == self.RUCAPTCHA_KEY - result = await instance.aio_captcha_handler() assert isinstance(result, dict) is True - assert result["error"] is True + assert result["errorId"] != 0 assert result["taskId"] is None - assert result["errorBody"] == RotateCaptcha.NO_CAPTCHA_ERR - assert result["captchaSolve"] == {} - assert result.keys() == ResponseSer().dict().keys() + assert result.keys() == GetTaskResultResponseSer().to_dict().keys() def test_wrong_link(self): instance = RotateCaptcha(rucaptcha_key=self.RUCAPTCHA_KEY) - assert instance.params.rucaptcha_key == self.RUCAPTCHA_KEY - result = instance.captcha_handler(captcha_link=self.get_random_string(length=50)) assert isinstance(result, dict) is True - assert result["error"] is True + assert result["errorId"] != 0 assert result["taskId"] is None - assert result["captchaSolve"] == {} - assert result.keys() == ResponseSer().dict().keys() + assert result.keys() == GetTaskResultResponseSer().to_dict().keys() - def test_wrong_base64(self): + async def test_aio_wrong_link(self): instance = RotateCaptcha(rucaptcha_key=self.RUCAPTCHA_KEY) - assert instance.params.rucaptcha_key == self.RUCAPTCHA_KEY - - result = instance.captcha_handler(captcha_base64=self.get_random_string(length=50).encode(encoding="UTF-8")) + result = await instance.aio_captcha_handler(captcha_link=self.get_random_string(length=50)) assert isinstance(result, dict) is True - assert result["error"] is True + assert result["errorId"] != 0 assert result["taskId"] is None - assert result["captchaSolve"] == {} - assert result.keys() == ResponseSer().dict().keys() + assert result.keys() == GetTaskResultResponseSer().to_dict().keys() - @pytest.mark.asyncio - async def test_aio_wrong_link(self): + def test_wrong_base64(self): instance = RotateCaptcha(rucaptcha_key=self.RUCAPTCHA_KEY) - assert instance.params.rucaptcha_key == self.RUCAPTCHA_KEY - - result = await instance.aio_captcha_handler(captcha_link=self.get_random_string(length=50)) + result = instance.captcha_handler(captcha_base64=self.get_random_string(length=50).encode(encoding="UTF-8")) assert isinstance(result, dict) is True - assert result["error"] is True + assert result["errorId"] != 0 assert result["taskId"] is None - assert result["captchaSolve"] == {} - assert result.keys() == ResponseSer().dict().keys() + assert result.keys() == GetTaskResultResponseSer().to_dict().keys() - @pytest.mark.asyncio async def test_aio_wrong_base64(self): instance = RotateCaptcha(rucaptcha_key=self.RUCAPTCHA_KEY) - assert instance.params.rucaptcha_key == self.RUCAPTCHA_KEY - result = await instance.aio_captcha_handler( captcha_base64=self.get_random_string(length=50).encode(encoding="UTF-8") ) assert isinstance(result, dict) is True - assert result["error"] is True + assert result["errorId"] != 0 assert result["taskId"] is None - assert result["captchaSolve"] == {} - assert result.keys() == ResponseSer().dict().keys() + assert result.keys() == GetTaskResultResponseSer().to_dict().keys() diff --git a/tests/test_text.py b/tests/test_text.py index 75bd16df..03a89d3f 100644 --- a/tests/test_text.py +++ b/tests/test_text.py @@ -2,11 +2,11 @@ from tests.conftest import BaseTest from python_rucaptcha.text_captcha import TextCaptcha -from python_rucaptcha.core.serializer import ResponseSer +from python_rucaptcha.core.serializer import GetTaskResultResponseSer class TestTextCaptcha(BaseTest): - questions = ((0, "Our planet name?"), (1, "Название нашей планеты?"), (2, "Our planet name?")) + questions = (("en", "Our planet name?"), ("rn", "Название нашей планеты?")) """ Success tests @@ -16,46 +16,47 @@ def test_methods_exists(self): assert "captcha_handler" in TextCaptcha.__dict__.keys() assert "aio_captcha_handler" in TextCaptcha.__dict__.keys() + def test_args(self): + instance = TextCaptcha(rucaptcha_key=self.RUCAPTCHA_KEY) + assert instance.create_task_payload["clientKey"] == self.RUCAPTCHA_KEY + @pytest.mark.parametrize("lang_code, question", questions) - def test_basic_data(self, lang_code, question): - instance = TextCaptcha(rucaptcha_key=self.RUCAPTCHA_KEY, language=lang_code) + def test_basic(self, lang_code: str, question: str): + instance = TextCaptcha(rucaptcha_key=self.RUCAPTCHA_KEY, languagePool=lang_code) - assert instance.params.rucaptcha_key == self.RUCAPTCHA_KEY + assert instance.create_task_payload["clientKey"] == self.RUCAPTCHA_KEY result = instance.captcha_handler(textcaptcha=question) assert isinstance(result, dict) is True - if result["error"] is False: - assert result["error"] is False + + if not result["errorId"]: + assert result["status"] == "ready" + assert isinstance(result["solution"]["text"], str) is True assert isinstance(result["taskId"], int) is True - assert result["errorBody"] is None - assert isinstance(result["captchaSolve"], str) is True else: - assert result["error"] is True - assert result["errorBody"] == "ERROR_CAPTCHA_UNSOLVABLE" + assert result["errorId"] in (1, 12) + assert result["errorCode"] == "ERROR_CAPTCHA_UNSOLVABLE" - assert result.keys() == ResponseSer().dict().keys() + assert result.keys() == GetTaskResultResponseSer().to_dict().keys() - @pytest.mark.asyncio @pytest.mark.parametrize("lang_code, question", questions) - async def test_aio_basic_data(self, lang_code, question): - instance = TextCaptcha(rucaptcha_key=self.RUCAPTCHA_KEY, language=lang_code) - - assert instance.params.rucaptcha_key == self.RUCAPTCHA_KEY + async def test_aio_basic(self, lang_code, question): + instance = TextCaptcha(rucaptcha_key=self.RUCAPTCHA_KEY, languagePool=lang_code) result = await instance.aio_captcha_handler(textcaptcha=question) assert isinstance(result, dict) is True - if result["error"] is False: - assert result["error"] is False + + if not result["errorId"]: + assert result["status"] == "ready" + assert isinstance(result["solution"]["text"], str) is True assert isinstance(result["taskId"], int) is True - assert result["errorBody"] is None - assert isinstance(result["captchaSolve"], str) is True else: - assert result["error"] is True - assert result["errorBody"] == "ERROR_CAPTCHA_UNSOLVABLE" + assert result["errorId"] in (1, 12) + assert result["errorCode"] == "ERROR_CAPTCHA_UNSOLVABLE" - assert result.keys() == ResponseSer().dict().keys() + assert result.keys() == GetTaskResultResponseSer().to_dict().keys() """ Fail tests diff --git a/tests/test_turnstile.py b/tests/test_turnstile.py index e3013c78..a1c8badd 100644 --- a/tests/test_turnstile.py +++ b/tests/test_turnstile.py @@ -3,100 +3,117 @@ from tests.conftest import BaseTest from python_rucaptcha.turnstile import Turnstile from python_rucaptcha.core.enums import TurnstileCaptchaEnm -from python_rucaptcha.core.serializer import ResponseSer +from python_rucaptcha.core.serializer import GetTaskResultResponseSer class TestTurnstile(BaseTest): pageurl = "https://rucaptcha.com/demo/cloudflare-turnstile" sitekey = "0x4AAAAAAAC3DHQFLr1GavRN" - - """ - Success tests - """ + useragent = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36" + kwargs_params = { + "proxyType": "socks5", + "proxyAddress": BaseTest.proxyAddress, + "proxyPort": BaseTest.proxyPort, + } def test_methods_exists(self): assert "captcha_handler" in Turnstile.__dict__.keys() assert "aio_captcha_handler" in Turnstile.__dict__.keys() + @pytest.mark.parametrize("method", TurnstileCaptchaEnm.list_values()) + def test_args(self, method: str): + instance = Turnstile( + rucaptcha_key=self.RUCAPTCHA_KEY, + websiteURL=self.pageurl, + websiteKey=self.sitekey, + userAgent=self.useragent, + method=method, + ) + assert instance.create_task_payload["clientKey"] == self.RUCAPTCHA_KEY + assert instance.create_task_payload["task"]["type"] == method + assert instance.create_task_payload["task"]["websiteURL"] == self.pageurl + assert instance.create_task_payload["task"]["websiteKey"] == self.sitekey + assert instance.create_task_payload["task"]["userAgent"] == self.useragent + + def test_kwargs(self): + instance = Turnstile( + rucaptcha_key=self.RUCAPTCHA_KEY, + websiteURL=self.pageurl, + websiteKey=self.sitekey, + userAgent=self.useragent, + method=TurnstileCaptchaEnm.TurnstileTaskProxyless, + **self.kwargs_params, + ) + assert set(self.kwargs_params.keys()).issubset(set(instance.create_task_payload["task"].keys())) + assert set(self.kwargs_params.values()).issubset(set(instance.create_task_payload["task"].values())) + + """ + Success tests + """ + def test_basic_data(self): instance = Turnstile( rucaptcha_key=self.RUCAPTCHA_KEY, - pageurl=self.pageurl, - sitekey=self.sitekey, - method=TurnstileCaptchaEnm.TURNSTILE.value, + websiteURL=self.pageurl, + websiteKey=self.sitekey, + userAgent=self.useragent, + method=TurnstileCaptchaEnm.TurnstileTaskProxyless.value, ) - assert instance.params.rucaptcha_key == self.RUCAPTCHA_KEY - assert instance.post_payload["method"] == TurnstileCaptchaEnm.TURNSTILE.value - assert instance.post_payload["pageurl"] == self.pageurl - assert instance.post_payload["sitekey"] == self.sitekey result = instance.captcha_handler() assert isinstance(result, dict) is True - if result["error"] is False: - assert result["error"] is False + if not result["errorId"]: + assert result["status"] == "ready" + assert isinstance(result["solution"], dict) is True assert isinstance(result["taskId"], int) is True - assert result["errorBody"] is None - assert isinstance(result["captchaSolve"], str) is True else: - assert result["error"] is True - assert isinstance(result["taskId"], int) is True - assert result["errorBody"] == "ERROR_CAPTCHA_UNSOLVABLE" + assert result["errorId"] in (1, 12) + assert result["errorCode"] == "ERROR_CAPTCHA_UNSOLVABLE" - assert result.keys() == ResponseSer().dict().keys() + assert result.keys() == GetTaskResultResponseSer().to_dict().keys() - @pytest.mark.asyncio async def test_aio_basic_data(self): instance = Turnstile( rucaptcha_key=self.RUCAPTCHA_KEY, - pageurl=self.pageurl, - sitekey=self.sitekey, - method=TurnstileCaptchaEnm.TURNSTILE.value, + websiteURL=self.pageurl, + websiteKey=self.sitekey, + userAgent=self.useragent, + method=TurnstileCaptchaEnm.TurnstileTaskProxyless.value, ) - assert instance.params.rucaptcha_key == self.RUCAPTCHA_KEY - assert instance.post_payload["method"] == TurnstileCaptchaEnm.TURNSTILE.value - assert instance.post_payload["pageurl"] == self.pageurl - assert instance.post_payload["sitekey"] == self.sitekey result = await instance.aio_captcha_handler() assert isinstance(result, dict) is True - if result["error"] is False: - assert result["error"] is False + if not result["errorId"]: + assert result["status"] == "ready" + assert isinstance(result["solution"], dict) is True assert isinstance(result["taskId"], int) is True - assert result["errorBody"] is None - assert isinstance(result["captchaSolve"], str) is True else: - assert result["error"] is True - assert isinstance(result["taskId"], int) is True - assert result["errorBody"] == "ERROR_CAPTCHA_UNSOLVABLE" + assert result["errorId"] in (1, 12) + assert result["errorCode"] == "ERROR_CAPTCHA_UNSOLVABLE" - assert result.keys() == ResponseSer().dict().keys() + assert result.keys() == GetTaskResultResponseSer().to_dict().keys() def test_context_basic_data(self): with Turnstile( rucaptcha_key=self.RUCAPTCHA_KEY, - pageurl=self.pageurl, - sitekey=self.sitekey, - method=TurnstileCaptchaEnm.TURNSTILE.value, + websiteURL=self.pageurl, + websiteKey=self.sitekey, + userAgent=self.useragent, + method=TurnstileCaptchaEnm.TurnstileTaskProxyless.value, ) as instance: - assert instance.params.rucaptcha_key == self.RUCAPTCHA_KEY - assert instance.post_payload["method"] == TurnstileCaptchaEnm.TURNSTILE.value - assert instance.post_payload["pageurl"] == self.pageurl - assert instance.post_payload["sitekey"] == self.sitekey + assert instance.captcha_handler() - @pytest.mark.asyncio async def test_context_aio_basic_data(self): async with Turnstile( rucaptcha_key=self.RUCAPTCHA_KEY, - pageurl=self.pageurl, - sitekey=self.sitekey, - method=TurnstileCaptchaEnm.TURNSTILE.value, + websiteURL=self.pageurl, + websiteKey=self.sitekey, + userAgent=self.useragent, + method=TurnstileCaptchaEnm.TurnstileTaskProxyless.value, ) as instance: - assert instance.params.rucaptcha_key == self.RUCAPTCHA_KEY - assert instance.post_payload["method"] == TurnstileCaptchaEnm.TURNSTILE.value - assert instance.post_payload["pageurl"] == self.pageurl - assert instance.post_payload["sitekey"] == self.sitekey + assert await instance.aio_captcha_handler() """ Fail tests @@ -106,7 +123,8 @@ def test_wrong_method(self): with pytest.raises(ValueError): Turnstile( rucaptcha_key=self.RUCAPTCHA_KEY, - pageurl=self.pageurl, - sitekey=self.sitekey, + websiteURL=self.pageurl, + websiteKey=self.sitekey, + userAgent=self.useragent, method=self.get_random_string(5), ) diff --git a/tests/test_yandex.py b/tests/test_yandex.py deleted file mode 100644 index 9016ddd2..00000000 --- a/tests/test_yandex.py +++ /dev/null @@ -1,112 +0,0 @@ -import pytest - -from tests.conftest import BaseTest -from python_rucaptcha.core.enums import YandexSmartCaptchaEnm -from python_rucaptcha.core.serializer import ResponseSer -from python_rucaptcha.yandex_smart_captcha import YandexSmartCaptcha - - -class TestYandexSmartCaptcha(BaseTest): - pageurl = "https://captcha-api.yandex.ru/demo" - sitekey = "FEXfAbHQsToo97VidNVk3j4dC74nGW1DgdxjtNB9" - - """ - Success tests - """ - - def test_methods_exists(self): - assert "captcha_handler" in YandexSmartCaptcha.__dict__.keys() - assert "aio_captcha_handler" in YandexSmartCaptcha.__dict__.keys() - - def test_basic_data(self): - instance = YandexSmartCaptcha( - rucaptcha_key=self.RUCAPTCHA_KEY, - pageurl=self.pageurl, - sitekey=self.sitekey, - method=YandexSmartCaptchaEnm.YANDEX.value, - ) - assert instance.params.rucaptcha_key == self.RUCAPTCHA_KEY - assert instance.post_payload["method"] == YandexSmartCaptchaEnm.YANDEX.value - assert instance.post_payload["pageurl"] == self.pageurl - assert instance.post_payload["sitekey"] == self.sitekey - - result = instance.captcha_handler() - - assert isinstance(result, dict) is True - if result["error"] is False: - assert result["error"] is False - assert isinstance(result["taskId"], int) is True - assert result["errorBody"] is None - assert isinstance(result["captchaSolve"], str) is True - else: - assert result["error"] is True - assert isinstance(result["taskId"], int) is True - assert result["errorBody"] == "ERROR_CAPTCHA_UNSOLVABLE" - - assert result.keys() == ResponseSer().dict().keys() - - @pytest.mark.asyncio - async def test_aio_basic_data(self): - instance = YandexSmartCaptcha( - rucaptcha_key=self.RUCAPTCHA_KEY, - pageurl=self.pageurl, - sitekey=self.sitekey, - method=YandexSmartCaptchaEnm.YANDEX.value, - ) - assert instance.params.rucaptcha_key == self.RUCAPTCHA_KEY - assert instance.post_payload["method"] == YandexSmartCaptchaEnm.YANDEX.value - assert instance.post_payload["pageurl"] == self.pageurl - assert instance.post_payload["sitekey"] == self.sitekey - - result = await instance.aio_captcha_handler() - - assert isinstance(result, dict) is True - if result["error"] is False: - assert result["error"] is False - assert isinstance(result["taskId"], int) is True - assert result["errorBody"] is None - assert isinstance(result["captchaSolve"], str) is True - else: - assert result["error"] is True - assert isinstance(result["taskId"], int) is True - assert result["errorBody"] == "ERROR_CAPTCHA_UNSOLVABLE" - - assert result.keys() == ResponseSer().dict().keys() - - def test_context_basic_data(self): - with YandexSmartCaptcha( - rucaptcha_key=self.RUCAPTCHA_KEY, - pageurl=self.pageurl, - sitekey=self.sitekey, - method=YandexSmartCaptchaEnm.YANDEX.value, - ) as instance: - assert instance.params.rucaptcha_key == self.RUCAPTCHA_KEY - assert instance.post_payload["method"] == YandexSmartCaptchaEnm.YANDEX.value - assert instance.post_payload["pageurl"] == self.pageurl - assert instance.post_payload["sitekey"] == self.sitekey - - @pytest.mark.asyncio - async def test_context_aio_basic_data(self): - async with YandexSmartCaptcha( - rucaptcha_key=self.RUCAPTCHA_KEY, - pageurl=self.pageurl, - sitekey=self.sitekey, - method=YandexSmartCaptchaEnm.YANDEX.value, - ) as instance: - assert instance.params.rucaptcha_key == self.RUCAPTCHA_KEY - assert instance.post_payload["method"] == YandexSmartCaptchaEnm.YANDEX.value - assert instance.post_payload["pageurl"] == self.pageurl - assert instance.post_payload["sitekey"] == self.sitekey - - """ - Fail tests - """ - - def test_wrong_method(self): - with pytest.raises(ValueError): - YandexSmartCaptcha( - rucaptcha_key=self.RUCAPTCHA_KEY, - pageurl=self.pageurl, - sitekey=self.sitekey, - method=self.get_random_string(5), - )