Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

v6.0.3 - DataDome CAPTCHA #195

Merged
merged 8 commits into from
Dec 10, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
image_captcha,
lemin_captcha,
rotate_captcha,
datadome_captcha,
)
from python_rucaptcha.__version__ import __version__

Expand Down
1 change: 1 addition & 0 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ Check our other projects here - `RedPandaDev group <https://red-panda-dev.xyz/bl
modules/image/example.rst
modules/audio/example.rst
modules/cut-captcha/example.rst
modules/datadome-captcha/example.rst
modules/control/example.rst

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

To import this module:

.. code-block:: python

from python_rucaptcha.datadome_captcha import DataDomeCaptcha


.. autoclass:: python_rucaptcha.datadome_captcha.DataDomeCaptcha
:members:
4 changes: 4 additions & 0 deletions docs/modules/enum/info.rst
Original file line number Diff line number Diff line change
Expand Up @@ -71,3 +71,7 @@ To import this module:
.. autoclass:: python_rucaptcha.core.enums.CutCaptchaEnm
:members:
:undoc-members:

.. autoclass:: python_rucaptcha.core.enums.DataDomeSliderEnm
:members:
:undoc-members:
2 changes: 1 addition & 1 deletion src/python_rucaptcha/__version__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = "6.0.2"
__version__ = "6.0.3"
4 changes: 4 additions & 0 deletions src/python_rucaptcha/core/enums.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,3 +114,7 @@ class AudioCaptchaEnm(str, MyEnum):
class CutCaptchaEnm(str, MyEnum):
CutCaptchaTask = "CutCaptchaTask"
CutCaptchaTaskProxyless = "CutCaptchaTaskProxyless"


class DataDomeSliderEnm(str, MyEnum):
DataDomeSliderTask = "DataDomeSliderTask"
121 changes: 121 additions & 0 deletions src/python_rucaptcha/datadome_captcha.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
from .core.base import BaseCaptcha
from .core.enums import DataDomeSliderEnm


class DataDomeCaptcha(BaseCaptcha):
def __init__(
self,
websiteURL: str,
captchaUrl: str,
userAgent: str,
proxyType: str,
proxyAddress: str,
proxyPort: str,
*args,
**kwargs,
):
"""
The class is used to work with HCaptcha.

Args:
rucaptcha_key: User API key
websiteURL: Full URL of the captcha page
captchaUrl: The value of the `src` parameter for the `iframe` element containing the captcha on the page.
userAgent: User-Agent of your browser will be used to load the captcha. Use only modern browser's User-Agents
proxyType: Proxy type - `http`, `socks4`, `socks5`
proxyAddress: Proxy IP address or hostname
proxyPort: Proxy port
method: Captcha type
kwargs: Not required params for task creation request

Examples:
>>> DataDomeCaptcha(rucaptcha_key="aa9011f31111181111168611f1151122",
... websiteURL="3ceb8624-1970-4e6b-91d5-70317b70b651",
... captchaUrl="https://rucaptcha.com/demo/hcaptcha",
... userAgent="https://rucaptcha.com/demo/hcaptcha",
... proxyType="socks5",
... proxyAddress="1.2.3.4",
... proxyPort="445",
... ).captcha_handler()
{
"errorId":0,
"status":"ready",
"solution":{
"cookie": "datadome=4ZXwCBlyHx9ktZhSnycMF...; Path=/; Secure; SameSite=Lax"
},
"cost":"0.00299",
"ip":"1.2.3.4",
"createTime":1692863536,
"endTime":1692863556,
"solveCount":1,
"taskId": 73243152973,
}

>>> await DataDomeCaptcha(rucaptcha_key="aa9011f31111181111168611f1151122",
... websiteURL="3ceb8624-1970-4e6b-91d5-70317b70b651",
... captchaUrl="https://rucaptcha.com/demo/hcaptcha",
... userAgent="https://rucaptcha.com/demo/hcaptcha",
... proxyType="socks5",
... proxyAddress="1.2.3.4",
... proxyPort="445",
... ).aio_captcha_handler()
{
"errorId":0,
"status":"ready",
"solution":{
"cookie": "datadome=4ZXwCBlyHx9ktZhSnycMF...; Path=/; Secure; SameSite=Lax"
},
"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/datadome-slider-captcha
"""
super().__init__(method=DataDomeSliderEnm.DataDomeSliderTask, *args, **kwargs)

self.create_task_payload["task"].update(
{
"websiteURL": websiteURL,
"captchaUrl": captchaUrl,
"userAgent": userAgent,
"proxyType": proxyType,
"proxyAddress": proxyAddress,
"proxyPort": proxyPort,
}
)

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()
122 changes: 122 additions & 0 deletions tests/test_datadome.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
import pytest

from tests.conftest import BaseTest
from python_rucaptcha.core.enums import DataDomeSliderEnm
from python_rucaptcha.datadome_captcha import DataDomeCaptcha


class TestHCaptcha(BaseTest):
websiteURL = "https://www.pokemoncenter.com/"
captchaUrl = "https://geo.captcha-delivery.com/captcha/?initialCid=AHrlqAAAAAMAlk-FmAyNOW8AUyTH_g%3D%3D&hash=5B45875B653A484CC79E57036CE9FC&cid=noJuZstmvINksqOxaXWQogbPBd01y3VaH3r-CZ4eqK4roZuelJMHVhO2rR0IySRieoAivkg74B4UpJ.xj.jVNB6-aLaW.Bwvik7__EncryD6COavwx8RmOqgZ7DK_3v&t=fe&referer=https%3A%2F%2Fwww.pokemoncenter.com%2F&s=9817&e=2b1d5a78107ded0dcdc8317aa879979ed5083a2b3a95b734dbe7871679e1403"
userAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/115.0.0.0 Safari/537.36"
proxyType = "http"
proxyAddress = "1.2.3.4"
proxyPort = "8080"
kwargs_params = {"proxyLogin": "user23", "proxyPassword": "p4$$w0rd"}

def test_methods_exists(self):
assert "captcha_handler" in DataDomeCaptcha.__dict__.keys()
assert "aio_captcha_handler" in DataDomeCaptcha.__dict__.keys()

def test_args(self):
instance = DataDomeCaptcha(
rucaptcha_key=self.RUCAPTCHA_KEY,
websiteURL=self.websiteURL,
captchaUrl=self.captchaUrl,
userAgent=self.userAgent,
proxyType=self.proxyType,
proxyAddress=self.proxyAddress,
proxyPort=self.proxyPort,
)
assert instance.create_task_payload["clientKey"] == self.RUCAPTCHA_KEY
assert instance.create_task_payload["task"]["type"] == DataDomeSliderEnm.DataDomeSliderTask
assert instance.create_task_payload["task"]["websiteURL"] == self.websiteURL
assert instance.create_task_payload["task"]["captchaUrl"] == self.captchaUrl
assert instance.create_task_payload["task"]["userAgent"] == self.userAgent
assert instance.create_task_payload["task"]["proxyType"] == self.proxyType
assert instance.create_task_payload["task"]["proxyAddress"] == self.proxyAddress
assert instance.create_task_payload["task"]["proxyPort"] == self.proxyPort

def test_kwargs(self):
instance = DataDomeCaptcha(
rucaptcha_key=self.RUCAPTCHA_KEY,
websiteURL=self.websiteURL,
captchaUrl=self.captchaUrl,
userAgent=self.userAgent,
proxyType=self.proxyType,
proxyAddress=self.proxyAddress,
proxyPort=self.proxyPort,
**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()))

"""
Fail tests
"""

def test_no_websiteURL(self):
with pytest.raises(TypeError):
DataDomeCaptcha(
rucaptcha_key=self.RUCAPTCHA_KEY,
captchaUrl=self.captchaUrl,
userAgent=self.userAgent,
proxyType=self.proxyType,
proxyAddress=self.proxyAddress,
proxyPort=self.proxyPort,
)

def test_no_captchaUrl(self):
with pytest.raises(TypeError):
DataDomeCaptcha(
rucaptcha_key=self.RUCAPTCHA_KEY,
websiteURL=self.websiteURL,
userAgent=self.userAgent,
proxyType=self.proxyType,
proxyAddress=self.proxyAddress,
proxyPort=self.proxyPort,
)

def test_no_userAgent(self):
with pytest.raises(TypeError):
DataDomeCaptcha(
rucaptcha_key=self.RUCAPTCHA_KEY,
websiteURL=self.websiteURL,
captchaUrl=self.captchaUrl,
proxyType=self.proxyType,
proxyAddress=self.proxyAddress,
proxyPort=self.proxyPort,
)

def test_no_proxyType(self):
with pytest.raises(TypeError):
DataDomeCaptcha(
rucaptcha_key=self.RUCAPTCHA_KEY,
websiteURL=self.websiteURL,
captchaUrl=self.captchaUrl,
userAgent=self.userAgent,
proxyAddress=self.proxyAddress,
proxyPort=self.proxyPort,
)

def test_no_proxyAddress(self):
with pytest.raises(TypeError):
DataDomeCaptcha(
rucaptcha_key=self.RUCAPTCHA_KEY,
websiteURL=self.websiteURL,
captchaUrl=self.captchaUrl,
userAgent=self.userAgent,
proxyType=self.proxyType,
proxyPort=self.proxyPort,
)

def test_no_proxyPort(self):
with pytest.raises(TypeError):
DataDomeCaptcha(
rucaptcha_key=self.RUCAPTCHA_KEY,
websiteURL=self.websiteURL,
captchaUrl=self.captchaUrl,
userAgent=self.userAgent,
proxyType=self.proxyType,
proxyAddress=self.proxyAddress,
)
Loading