I've been trying to do an information search automation, but sometimes Datadome's slidercaptcha appeared. but now, they basically always appear And the worst, I made a code with pydoll to grab and drag the slide of the datadome, the problem that it detects that it is a robot doing, but if I use it in my hand it recognizes that it is not let it continue One way to force the appearance of the Datadome Slider Captcha is to open the browser as headless on a site protected by Datadome, and then it can be opened without being headless because Datadome has already marked it as a bot (it will appear every time you open the site, thus having to solve the captchas)
To reproduce the drag method must be used for a datadome slider captch, as it is being caught
import asyncio
import traceback
from pydoll.browser import Chrome
from pydoll.browser.tab import Tab
from pydoll.browser.options import ChromiumOptions
from pydoll.interactions.mouse import MouseTimingConfig
import os
# Parâmetros de humanização do movimento (curvas, tremor, timing) —
# já embutidos no pydoll, não precisamos reinventar em Python puro.
MOUSE_CONFIG = MouseTimingConfig(
fitts_a=0.070,
fitts_b=0.150,
frame_interval=0.012,
curvature_min=0.10,
curvature_max=0.30,
tremor_amplitude=1.0,
overshoot_probability=0.70,
min_duration=0.35,
max_duration=0.65,
)
def create_full_stealth_options() -> ChromiumOptions:
"""Configura e retorna as opções do navegador Chromium."""
options = ChromiumOptions()
options.add_argument("--start-maximized")
options.prompt_for_download = False
options.set_default_download_directory(os.path.join(os.getcwd(), "downloads"))
options.browser_preferences = {
"profile": {
"default_content_setting_values": {
"automatic_downloads": 1,
"images": 1,
"notifications": 1,
"popups": 1,
"geolocation": 1,
"media_stream": 1,
"media_stream_mic": 1,
"media_stream_camera": 1,
}
},
"translate": {"enabled": False},
"credentials_enable_service": False,
"devtools": {"preferences": {"currentDockState": '"undocked"'}},
}
return options
class DataDomeSliderSolver:
"""Resolve o slider captcha do DataDome usando o mouse humanizado
NATIVO do pydoll (via CDP, coordenadas relativas ao próprio iframe).
Isso elimina toda a cadeia de conversão OS/DPI/janela que causava
imprecisão: sem PyAutoGUI, sem win32, sem devicePixelRatio, sem
posição de janela — o CDP já lida com tudo isso internamente.
"""
def __init__(
self,
browser: Chrome,
page: Tab,
timeout: int = 30,
max_attempts: int = 10,
overshoot: float = 20,
debug: bool = False,
):
self.browser = browser
self.page = page
self.timeout = timeout
self.max_attempts = max_attempts
self.overshoot = overshoot
self.debug = debug
def _log(self, *args):
if self.debug:
print("[DataDome]", *args)
# -- localização do iframe/slider ---------------------------------------
async def _find_datadome_iframe(self):
"""Procura, entre os iframes da página, o do DataDome que
contenha o slider. Retorna só o `src` (evita objectId stale)."""
for attempt in range(self.max_attempts):
iframes = await self.page.find(
tag_name="iframe",
timeout=self.timeout,
raise_exc=False,
find_all=True,
)
if not iframes:
await asyncio.sleep(0.3)
continue
for ifrm in iframes:
src = ifrm.get_attribute("src") or ""
if "https://geo.captcha-delivery.com/" not in src:
continue
slider_container = await ifrm.find(
class_name="sliderContainer",
raise_exc=False,
timeout=2,
)
if slider_container is not None:
self._log(f"iframe encontrado na tentativa {attempt + 1}: {src}")
return src
await asyncio.sleep(0.3)
return None
async def _get_fresh_iframe_by_src(self, src: str):
"""Reconsulta o iframe usando o src como chave, garantindo um
objectId válido no momento da leitura."""
iframes = await self.page.find(
tag_name="iframe",
timeout=self.timeout,
raise_exc=False,
find_all=True,
)
for ifrm in iframes or []:
if ifrm.get_attribute("src") == src:
return ifrm
return None
async def _get_bounds_with_retry(self, element, retries: int = 3, delay: float = 0.3):
"""Tenta pegar o bounding box; se der erro de CDP (objectId
stale), espera um pouco e tenta de novo."""
last_error = None
for _ in range(retries):
try:
return await element.get_bounds_using_js()
except KeyError as e:
last_error = e
await asyncio.sleep(delay)
raise last_error
async def _find_visible_element(self, iframe, class_name: str):
"""Busca TODOS os elementos com essa classe dentro do iframe e
retorna o primeiro com dimensão visível real (evita pegar
duplicatas ocultas de acessibilidade com a mesma classe)."""
candidates = await iframe.find(
class_name=class_name,
find_all=True,
raise_exc=False,
timeout=self.timeout,
)
if not candidates:
return None, None
for el in candidates:
try:
box = await self._get_bounds_with_retry(el)
except Exception:
continue
if box["width"] > 0 and box["height"] > 0:
self._log(f"'.{class_name}' visível: x={box['x']:.1f} y={box['y']:.1f} w={box['width']:.1f} h={box['height']:.1f}")
return el, box
self._log(f"'.{class_name}': nenhum candidato visível entre {len(candidates)} encontrados")
return None, None
# -- fluxo principal -------------------------------------------------------
async def solve(self) -> bool:
src = await self._find_datadome_iframe()
if not src:
self._log("iframe/slider não encontrado")
return False
iframe = await self._get_fresh_iframe_by_src(src)
if not iframe:
self._log("iframe sumiu antes de conseguir medir")
return False
slider_container, container_box = await self._find_visible_element(iframe, "sliderContainer")
slider_btn, slider_box = await self._find_visible_element(iframe, "slider")
if not slider_container or not slider_btn:
self._log("slider/container visível não encontrado")
return False
# Coordenadas RELATIVAS AO PRÓPRIO IFRAME — sem nenhuma conversão
# de tela/DPI/janela. É isso que o CDP espera quando o dispatch
# é feito através do objeto `iframe` (não da `page`).
start_x = slider_box["x"] + slider_box["width"] / 2
start_y = slider_box["y"] + slider_box["height"] / 2
end_x = (
container_box["x"]
+ container_box["width"]
- slider_box["width"] / 2
+ self.overshoot
)
end_y = start_y # o slider é horizontal, sem variação de Y
self._log(f"drag: start=({start_x:.1f}, {start_y:.1f}) end=({end_x:.1f}, {end_y:.1f})")
self.page.mouse.timing = MOUSE_CONFIG
await iframe._mouse.drag(
start_x, start_y, end_x, end_y,
humanize=True,
)
return await self._confirm_solved(iframe)
async def _confirm_solved(self, iframe, wait_seconds: int = 15) -> bool:
await asyncio.sleep(wait_seconds)
success = await iframe.find(
tag_name="div",
class_name="slider-success",
timeout=self.timeout,
find_all=True,
raise_exc=False,
)
solved = bool(success)
self._log("captcha resolvido" if solved else "não foi possível confirmar a resolução")
return solved
# ---------------------------------------------------------------------------
# Exemplo de uso
# ---------------------------------------------------------------------------
async def main():
url_alvo = "https://www.idealista.com/venta-viviendas/barcelona-provincia/"
browser = Chrome(options=create_full_stealth_options())
page = await browser.start(headless=False)
try:
await page.go_to(url_alvo, timeout=120)
await asyncio.sleep(5)
solver = DataDomeSliderSolver(browser, page, debug=True)
resolved = await solver.solve()
if resolved:
print("seguindo fluxo normal...")
else:
print("captcha não resolvido, tratar retry/erro")
await asyncio.sleep(1_000_000)
except Exception:
traceback.print_exc()
await asyncio.sleep(1_000_000)
if __name__ == "__main__":
asyncio.run(main())
Checklist before reporting
pydoll Version
2.23.1
Python Version
3.13
Operating System
Windows
Bug Description
I've been trying to do an information search automation, but sometimes Datadome's slidercaptcha appeared. but now, they basically always appear And the worst, I made a code with pydoll to grab and drag the slide of the datadome, the problem that it detects that it is a robot doing, but if I use it in my hand it recognizes that it is not let it continue One way to force the appearance of the Datadome Slider Captcha is to open the browser as headless on a site protected by Datadome, and then it can be opened without being headless because Datadome has already marked it as a bot (it will appear every time you open the site, thus having to solve the captchas)
Steps to Reproduce
To reproduce the drag method must be used for a datadome slider captch, as it is being caught
Code Example
Expected Behavior
No response
Actual Behavior
No response
Relevant Log Output
Additional Context
No response