Skip to content

Commit

Permalink
Merge pull request #103 from Xewdy444/solve-detection-fix
Browse files Browse the repository at this point in the history
Fix solve detection issue
  • Loading branch information
Xewdy444 authored Jun 6, 2024
2 parents 67f2b36 + a8e3da4 commit 7bc13d5
Show file tree
Hide file tree
Showing 3 changed files with 117 additions and 53 deletions.
29 changes: 21 additions & 8 deletions playwright_recaptcha/recaptchav2/async_solver.py
Original file line number Diff line number Diff line change
Expand Up @@ -334,13 +334,13 @@ async def _click_checkbox(self, recaptcha_box: AsyncRecaptchaBox) -> None:
RecaptchaRateLimitError
If the reCAPTCHA rate limit has been exceeded.
"""
await recaptcha_box.checkbox.click(force=True)
await recaptcha_box.checkbox.click()

while recaptcha_box.frames_are_attached() and self._token is None:
if await recaptcha_box.rate_limit_is_visible():
raise RecaptchaRateLimitError

if await recaptcha_box.challenge_is_visible():
if await recaptcha_box.any_challenge_is_visible():
return

await self._page.wait_for_timeout(250)
Expand Down Expand Up @@ -405,7 +405,7 @@ async def _submit_audio_text(
raise RecaptchaRateLimitError

if (
not await recaptcha_box.challenge_is_visible()
not await recaptcha_box.audio_challenge_is_visible()
or await recaptcha_box.solve_failure_is_visible()
or await recaptcha_box.challenge_is_solved()
):
Expand Down Expand Up @@ -629,18 +629,31 @@ async def solve_recaptcha(
else:
recaptcha_box = await AsyncRecaptchaBox.from_frames(self._page.frames)

if await recaptcha_box.rate_limit_is_visible():
raise RecaptchaRateLimitError

if await recaptcha_box.checkbox.is_visible():
await self._click_checkbox(recaptcha_box)

if self._token is not None:
return self._token
elif await recaptcha_box.rate_limit_is_visible():
raise RecaptchaRateLimitError

if (
recaptcha_box.frames_are_detached()
or not await recaptcha_box.any_challenge_is_visible()
or await recaptcha_box.challenge_is_solved()
):
while self._token is None:
await self._page.wait_for_timeout(250)

return self._token

while not await recaptcha_box.any_challenge_is_visible():
await self._page.wait_for_timeout(250)

if image_challenge and await recaptcha_box.image_challenge_button.is_visible():
await recaptcha_box.image_challenge_button.click()

if (
elif (
not image_challenge
and await recaptcha_box.audio_challenge_button.is_visible()
):
Expand All @@ -661,7 +674,7 @@ async def solve_recaptcha(

if (
recaptcha_box.frames_are_detached()
or not await recaptcha_box.challenge_is_visible()
or not await recaptcha_box.any_challenge_is_visible()
or await recaptcha_box.challenge_is_solved()
):
while self._token is None:
Expand Down
112 changes: 75 additions & 37 deletions playwright_recaptcha/recaptchav2/recaptcha_box.py
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,17 @@ def solve_failure_is_visible(self) -> bool:
True if the reCAPTCHA solve failure message is visible, False otherwise.
"""

@abstractmethod
def image_challenge_is_visible(self) -> bool:
"""
Check if the reCAPTCHA image challenge is visible.
Returns
-------
bool
True if the reCAPTCHA challenge is visible, False otherwise.
"""

@abstractmethod
def audio_challenge_is_visible(self) -> bool:
"""
Expand All @@ -292,6 +303,17 @@ def audio_challenge_is_visible(self) -> bool:
True if the reCAPTCHA audio challenge is visible, False otherwise.
"""

@abstractmethod
def any_challenge_is_visible(self) -> bool:
"""
Check if any reCAPTCHA challenge is visible.
Returns
-------
bool
True if any reCAPTCHA challenge is visible, False otherwise.
"""

@abstractmethod
def try_again_is_visible(self) -> bool:
"""
Expand Down Expand Up @@ -326,17 +348,6 @@ def select_all_matching_is_visible(self) -> bool:
False otherwise.
"""

@abstractmethod
def challenge_is_visible(self) -> bool:
"""
Check if the reCAPTCHA challenge is visible.
Returns
-------
bool
True if the reCAPTCHA challenge is visible, False otherwise.
"""

@abstractmethod
def challenge_is_solved(self) -> bool:
"""
Expand Down Expand Up @@ -461,6 +472,19 @@ def solve_failure_is_visible(self) -> bool:
)
).is_visible()

@_check_if_attached
def image_challenge_is_visible(self) -> bool:
"""
Check if the reCAPTCHA image challenge is visible.
Returns
-------
bool
True if the reCAPTCHA challenge is visible, False otherwise.
"""
button = self.skip_button.or_(self.next_button).or_(self.verify_button)
return button.is_enabled()

@_check_if_attached
def audio_challenge_is_visible(self) -> bool:
"""
Expand All @@ -481,6 +505,18 @@ def audio_challenge_is_visible(self) -> bool:
and self.new_challenge_button.is_enabled()
)

@_check_if_attached
def any_challenge_is_visible(self) -> bool:
"""
Check if any reCAPTCHA challenge is visible.
Returns
-------
bool
True if any reCAPTCHA challenge is visible, False otherwise.
"""
return self.image_challenge_is_visible() or self.audio_challenge_is_visible()

@_check_if_attached
def try_again_is_visible(self) -> bool:
"""
Expand Down Expand Up @@ -528,19 +564,6 @@ def select_all_matching_is_visible(self) -> bool:
)
).is_visible()

@_check_if_attached
def challenge_is_visible(self) -> bool:
"""
Check if the reCAPTCHA challenge is visible.
Returns
-------
bool
True if the reCAPTCHA challenge is visible, False otherwise.
"""
button = self.skip_button.or_(self.next_button).or_(self.verify_button)
return button.is_enabled()

@_check_if_attached
def challenge_is_solved(self) -> bool:
"""
Expand Down Expand Up @@ -666,6 +689,19 @@ async def solve_failure_is_visible(self) -> bool:
)
).is_visible()

@_check_if_attached
async def image_challenge_is_visible(self) -> bool:
"""
Check if the reCAPTCHA image challenge is visible.
Returns
-------
bool
True if the reCAPTCHA challenge is visible, False otherwise.
"""
button = self.skip_button.or_(self.next_button).or_(self.verify_button)
return await button.is_enabled()

@_check_if_attached
async def audio_challenge_is_visible(self) -> bool:
"""
Expand All @@ -686,6 +722,21 @@ async def audio_challenge_is_visible(self) -> bool:
and await self.new_challenge_button.is_enabled()
)

@_check_if_attached
async def any_challenge_is_visible(self) -> bool:
"""
Check if any reCAPTCHA challenge is visible.
Returns
-------
bool
True if any reCAPTCHA challenge is visible, False otherwise.
"""
return (
await self.image_challenge_is_visible()
or await self.audio_challenge_is_visible()
)

@_check_if_attached
async def try_again_is_visible(self) -> bool:
"""
Expand Down Expand Up @@ -733,19 +784,6 @@ async def select_all_matching_is_visible(self) -> bool:
)
).is_visible()

@_check_if_attached
async def challenge_is_visible(self) -> bool:
"""
Check if the reCAPTCHA challenge is visible.
Returns
-------
bool
True if the reCAPTCHA challenge is visible, False otherwise.
"""
button = self.skip_button.or_(self.next_button).or_(self.verify_button)
return await button.is_enabled()

@_check_if_attached
async def challenge_is_solved(self) -> bool:
"""
Expand Down
29 changes: 21 additions & 8 deletions playwright_recaptcha/recaptchav2/sync_solver.py
Original file line number Diff line number Diff line change
Expand Up @@ -281,13 +281,13 @@ def _click_checkbox(self, recaptcha_box: SyncRecaptchaBox) -> None:
RecaptchaRateLimitError
If the reCAPTCHA rate limit has been exceeded.
"""
recaptcha_box.checkbox.click(force=True)
recaptcha_box.checkbox.click()

while recaptcha_box.frames_are_attached() and self._token is None:
if recaptcha_box.rate_limit_is_visible():
raise RecaptchaRateLimitError

if recaptcha_box.challenge_is_visible():
if recaptcha_box.any_challenge_is_visible():
return

self._page.wait_for_timeout(250)
Expand Down Expand Up @@ -348,7 +348,7 @@ def _submit_audio_text(self, recaptcha_box: SyncRecaptchaBox, text: str) -> None
raise RecaptchaRateLimitError

if (
not recaptcha_box.challenge_is_visible()
not recaptcha_box.audio_challenge_is_visible()
or recaptcha_box.solve_failure_is_visible()
or recaptcha_box.challenge_is_solved()
):
Expand Down Expand Up @@ -565,18 +565,31 @@ def solve_recaptcha(
else:
recaptcha_box = SyncRecaptchaBox.from_frames(self._page.frames)

if recaptcha_box.rate_limit_is_visible():
raise RecaptchaRateLimitError

if recaptcha_box.checkbox.is_visible():
self._click_checkbox(recaptcha_box)

if self._token is not None:
return self._token
elif recaptcha_box.rate_limit_is_visible():
raise RecaptchaRateLimitError

if (
recaptcha_box.frames_are_detached()
or not recaptcha_box.any_challenge_is_visible()
or recaptcha_box.challenge_is_solved()
):
while self._token is None:
self._page.wait_for_timeout(250)

return self._token

while not recaptcha_box.any_challenge_is_visible():
self._page.wait_for_timeout(250)

if image_challenge and recaptcha_box.image_challenge_button.is_visible():
recaptcha_box.image_challenge_button.click()

if not image_challenge and recaptcha_box.audio_challenge_button.is_visible():
elif not image_challenge and recaptcha_box.audio_challenge_button.is_visible():
recaptcha_box.audio_challenge_button.click()

if image_challenge:
Expand All @@ -594,7 +607,7 @@ def solve_recaptcha(

if (
recaptcha_box.frames_are_detached()
or not recaptcha_box.challenge_is_visible()
or not recaptcha_box.any_challenge_is_visible()
or recaptcha_box.challenge_is_solved()
):
while self._token is None:
Expand Down

0 comments on commit 7bc13d5

Please sign in to comment.