From 923f2ed1406d65158d789a0805565dd67e57652c Mon Sep 17 00:00:00 2001 From: Xewdy444 Date: Thu, 29 Feb 2024 20:51:14 -0600 Subject: [PATCH 1/8] Fixed CapSolver GIF --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 3bca41a..82b8972 100644 --- a/README.md +++ b/README.md @@ -6,8 +6,8 @@ ---
- - + +
At the lowest price on the market, you may receive a variety of solutions, including reCAPTCHA v2, reCAPTCHA v3, hCaptcha, hCaptcha Click, FunCaptcha, picture-to-text, AWS Amazon CAPTCHA, and more. With this service, 0.1s is the slowest speed ever measured.
From 24ec266289bba6525ae2f57300c040b9cf511f00 Mon Sep 17 00:00:00 2001 From: SirFilippov Date: Sun, 3 Mar 2024 01:25:13 +0400 Subject: [PATCH 2/8] add russian language --- .../recaptchav2/recaptcha_box.py | 74 ++++++++++++------ .../recaptchav2/translations.py | 76 +++++++++++++++++++ 2 files changed, 127 insertions(+), 23 deletions(-) create mode 100644 playwright_recaptcha/recaptchav2/translations.py diff --git a/playwright_recaptcha/recaptchav2/recaptcha_box.py b/playwright_recaptcha/recaptchav2/recaptcha_box.py index a9d6f9a..bbd8426 100644 --- a/playwright_recaptcha/recaptchav2/recaptcha_box.py +++ b/playwright_recaptcha/recaptchav2/recaptcha_box.py @@ -12,6 +12,7 @@ from playwright.sync_api import Locator as SyncLocator from ..errors import RecaptchaNotFoundError +from playwright_recaptcha.recaptchav2.translations import TRANSLATIONS Locator = Union[AsyncLocator, SyncLocator] Frame = Union[AsyncFrame, SyncFrame] @@ -99,59 +100,84 @@ async def async_wrapper(self: AsyncRecaptchaBox) -> bool: @property def checkbox(self) -> Locator: """The reCAPTCHA checkbox locator.""" - return self.anchor_frame.get_by_role("checkbox", name="I'm not a robot") + return self.anchor_frame.get_by_role( + "checkbox", + name=re.compile("|".join(TRANSLATIONS["im_not_a_robot"])), + ) @property def audio_challenge_button(self) -> Locator: """The reCAPTCHA audio challenge button locator.""" - return self.bframe_frame.get_by_role("button", name="Get an audio challenge") + return self.bframe_frame.get_by_role( + "button", + name=re.compile("|".join(TRANSLATIONS["get_an_audio_challenge"])), + ) @property def image_challenge_button(self) -> Locator: """The reCAPTCHA image challenge button locator.""" - return self.bframe_frame.get_by_role("button", name="Get a visual challenge") + return self.bframe_frame.get_by_role( + "button", + name=re.compile("|".join(TRANSLATIONS["get a visual challenge"])), + ) @property def new_challenge_button(self) -> Locator: """The reCAPTCHA new challenge button locator.""" - return self.bframe_frame.get_by_role("button", name="Get a new challenge") + return self.bframe_frame.get_by_role( + "button", + name=re.compile("|".join(TRANSLATIONS["get_a_new_challenge"])), + ) @property def audio_download_button(self) -> Locator: """The reCAPTCHA audio download button locator.""" return self.bframe_frame.get_by_role( - "link", name="Alternatively, download audio as MP3" + "link", + name=re.compile("|".join(TRANSLATIONS["alternatively_download_audio_as_mp3"])), ) @property def audio_challenge_textbox(self) -> Locator: """The reCAPTCHA audio challenge textbox locator.""" - return self.bframe_frame.get_by_role("textbox", name="Enter what you hear") + return self.bframe_frame.get_by_role( + "textbox", + name=re.compile("|".join(TRANSLATIONS["enter_what_you_hear"])), + ) @property def skip_button(self) -> Locator: """The reCAPTCHA skip button locator.""" - return self.bframe_frame.get_by_role("button", name="Skip") + return self.bframe_frame.get_by_role( + "button", + name=re.compile("|".join(TRANSLATIONS["skip"])), + ) @property def next_button(self) -> Locator: """The reCAPTCHA next button locator.""" - return self.bframe_frame.get_by_role("button", name="Next") + return self.bframe_frame.get_by_role( + "button", + name=re.compile("|".join(TRANSLATIONS["next"])), + ) @property def verify_button(self) -> Locator: """The reCAPTCHA verify button locator.""" - return self.bframe_frame.get_by_role("button", name="Verify") + return self.bframe_frame.get_by_role( + "button", + name=re.compile("|".join(TRANSLATIONS["verify"])), + ) @property def tile_selector(self) -> Locator: """The reCAPTCHA tile selector locator.""" - return self.bframe_frame.locator(".rc-imageselect-tile") + # return self.bframe_frame.locator(".rc-imageselect-tile") @property def image_challenge(self) -> Locator: """The reCAPTCHA image challenge locator.""" - return self.bframe_frame.locator(".rc-imageselect-challenge") + # return self.bframe_frame.locator(".rc-imageselect-challenge") def frames_are_attached(self) -> bool: """ @@ -379,7 +405,7 @@ def rate_limit_is_visible(self) -> bool: bool True if the reCAPTCHA rate limit message is visible, False otherwise. """ - return self.bframe_frame.get_by_text("Try again later").is_visible() + return self.bframe_frame.get_by_text(re.compile("|".join(TRANSLATIONS["try_again_later"]))).is_visible() @RecaptchaBox._check_if_attached def solve_failure_is_visible(self) -> bool: @@ -392,7 +418,7 @@ def solve_failure_is_visible(self) -> bool: True if the reCAPTCHA solve failure message is visible, False otherwise. """ return self.bframe_frame.get_by_text( - "Multiple correct solutions required - please solve more." + re.compile("|".join(TRANSLATIONS["multiple_correct_solutions_required"])) ).is_visible() @RecaptchaBox._check_if_attached @@ -405,7 +431,7 @@ def audio_challenge_is_visible(self) -> bool: bool True if the reCAPTCHA audio challenge is visible, False otherwise. """ - return self.bframe_frame.get_by_text("Press PLAY to listen").is_visible() + return self.bframe_frame.get_by_text(re.compile("|".join(TRANSLATIONS["press_play_to_listen"]))).is_visible() @RecaptchaBox._check_if_attached def try_again_is_visible(self) -> bool: @@ -418,7 +444,7 @@ def try_again_is_visible(self) -> bool: True if the reCAPTCHA try again message is visible, False otherwise. """ return self.bframe_frame.get_by_text( - re.compile("Please try again") + re.compile("|".join(TRANSLATIONS["please_try_again"])) ).is_visible() @RecaptchaBox._check_if_attached @@ -432,7 +458,7 @@ def check_new_images_is_visible(self) -> bool: True if the reCAPTCHA check new images message is visible, False otherwise. """ return self.bframe_frame.get_by_text( - re.compile("Please also check the new images") + re.compile("|".join(TRANSLATIONS["please_also_check_the_new_images"])) ).is_visible() @RecaptchaBox._check_if_attached @@ -447,7 +473,7 @@ def select_all_matching_is_visible(self) -> bool: False otherwise. """ return self.bframe_frame.get_by_text( - re.compile("Please select all matching images") + re.compile("|".join(TRANSLATIONS["please_select_all_matching_images"])) ).is_visible() @RecaptchaBox._check_if_attached @@ -557,7 +583,7 @@ async def rate_limit_is_visible(self) -> bool: bool True if the reCAPTCHA rate limit message is visible, False otherwise. """ - return await self.bframe_frame.get_by_text("Try again later").is_visible() + return await self.bframe_frame.get_by_text(re.compile("|".join(TRANSLATIONS["try_again_later"]))).is_visible() @RecaptchaBox._check_if_attached async def solve_failure_is_visible(self) -> bool: @@ -570,7 +596,7 @@ async def solve_failure_is_visible(self) -> bool: True if the reCAPTCHA solve failure message is visible, False otherwise. """ return await self.bframe_frame.get_by_text( - "Multiple correct solutions required - please solve more." + re.compile("|".join(TRANSLATIONS["multiple_correct_solutions_required"])) ).is_visible() @RecaptchaBox._check_if_attached @@ -583,7 +609,9 @@ async def audio_challenge_is_visible(self) -> bool: bool True if the reCAPTCHA audio challenge is visible, False otherwise. """ - return await self.bframe_frame.get_by_text("Press PLAY to listen").is_visible() + return await self.bframe_frame.get_by_text(re.compile( + "|".join(TRANSLATIONS["press_play_to_listen"])) + ).is_visible() @RecaptchaBox._check_if_attached async def try_again_is_visible(self) -> bool: @@ -596,7 +624,7 @@ async def try_again_is_visible(self) -> bool: True if the reCAPTCHA try again message is visible, False otherwise. """ return await self.bframe_frame.get_by_text( - re.compile("Please try again") + re.compile("|".join(TRANSLATIONS["please_try_again"])) ).is_visible() @RecaptchaBox._check_if_attached @@ -610,7 +638,7 @@ async def check_new_images_is_visible(self) -> bool: True if the reCAPTCHA check new images message is visible, False otherwise. """ return await self.bframe_frame.get_by_text( - re.compile("Please also check the new images") + re.compile("|".join(TRANSLATIONS["please_also_check_the_new_images"])) ).is_visible() @RecaptchaBox._check_if_attached @@ -625,7 +653,7 @@ async def select_all_matching_is_visible(self) -> bool: False otherwise. """ return await self.bframe_frame.get_by_text( - re.compile("Please select all matching images") + re.compile("|".join(TRANSLATIONS["please_select_all_matching_images"])) ).is_visible() @RecaptchaBox._check_if_attached diff --git a/playwright_recaptcha/recaptchav2/translations.py b/playwright_recaptcha/recaptchav2/translations.py new file mode 100644 index 0000000..6ce9490 --- /dev/null +++ b/playwright_recaptcha/recaptchav2/translations.py @@ -0,0 +1,76 @@ +TRANSLATIONS = { + "im_not_a_robot": ( + "I'm not a robot", + "Я не робот" + ), + + "get_an_audio_challenge": ( + "Get an audio challenge", + "Пройти аудиотест", + ), + + "get a visual challenge": ( + "Get a visual challenge", + "Пройти визуальный тест", + ), + + "get_a_new_challenge": ( + "Get a new challenge", + "Обновить", + ), + + "alternatively_download_audio_as_mp3": ( + "Alternatively, download audio as MP3", + "Скачать MP3-файл", + ), + + "enter_what_you_hear": ( + "Enter what you hear", + "Введите прозвучавшие слова.", + ), + + "skip": ( + "Skip", + "Пропустить", + ), + + "next": ( + "Next", + "Далее", + ), + + "verify": ( + "Verify", + "Подтвердить", + ) + , + "try_again_later": ( + "Try again later", + "Повторите попытку позже", + ), + + "multiple_correct_solutions_required": ( + "Multiple correct solutions required - please solve more.", + "Вы должны выполнить несколько заданий.", + ), + + "press_play_to_listen": ( + "Press PLAY to listen", + 'Чтобы прослушать, нажмите "Воспроизвести".', + ), + + "please_try_again": ( + "Please try again", + "Повторите попытку." + ), + + "please_also_check_the_new_images": ( + "Please also check the new images", + "Просмотрите также новые изображение.", + ), + + "please_select_all_matching_images": ( + "Please select all matching images", + "Выберите все совпадающие изображения.", + ), +} \ No newline at end of file From 191986bc3898be59254155f8828e03f005134ed2 Mon Sep 17 00:00:00 2001 From: Xewdy444 Date: Sat, 2 Mar 2024 18:54:36 -0600 Subject: [PATCH 3/8] Formatting changes --- .../recaptchav2/recaptcha_box.py | 50 ++++++------ .../recaptchav2/translations.py | 76 ++++--------------- 2 files changed, 41 insertions(+), 85 deletions(-) diff --git a/playwright_recaptcha/recaptchav2/recaptcha_box.py b/playwright_recaptcha/recaptchav2/recaptcha_box.py index bbd8426..aaf39fe 100644 --- a/playwright_recaptcha/recaptchav2/recaptcha_box.py +++ b/playwright_recaptcha/recaptchav2/recaptcha_box.py @@ -12,7 +12,7 @@ from playwright.sync_api import Locator as SyncLocator from ..errors import RecaptchaNotFoundError -from playwright_recaptcha.recaptchav2.translations import TRANSLATIONS +from .translations import TRANSLATIONS Locator = Union[AsyncLocator, SyncLocator] Frame = Union[AsyncFrame, SyncFrame] @@ -101,32 +101,28 @@ async def async_wrapper(self: AsyncRecaptchaBox) -> bool: def checkbox(self) -> Locator: """The reCAPTCHA checkbox locator.""" return self.anchor_frame.get_by_role( - "checkbox", - name=re.compile("|".join(TRANSLATIONS["im_not_a_robot"])), + "checkbox", name=re.compile("|".join(TRANSLATIONS["im_not_a_robot"])) ) @property def audio_challenge_button(self) -> Locator: """The reCAPTCHA audio challenge button locator.""" return self.bframe_frame.get_by_role( - "button", - name=re.compile("|".join(TRANSLATIONS["get_an_audio_challenge"])), + "button", name=re.compile("|".join(TRANSLATIONS["get_an_audio_challenge"])) ) @property def image_challenge_button(self) -> Locator: """The reCAPTCHA image challenge button locator.""" return self.bframe_frame.get_by_role( - "button", - name=re.compile("|".join(TRANSLATIONS["get a visual challenge"])), + "button", name=re.compile("|".join(TRANSLATIONS["get_a_visual_challenge"])) ) @property def new_challenge_button(self) -> Locator: """The reCAPTCHA new challenge button locator.""" return self.bframe_frame.get_by_role( - "button", - name=re.compile("|".join(TRANSLATIONS["get_a_new_challenge"])), + "button", name=re.compile("|".join(TRANSLATIONS["get_a_new_challenge"])) ) @property @@ -134,50 +130,48 @@ def audio_download_button(self) -> Locator: """The reCAPTCHA audio download button locator.""" return self.bframe_frame.get_by_role( "link", - name=re.compile("|".join(TRANSLATIONS["alternatively_download_audio_as_mp3"])), + name=re.compile( + "|".join(TRANSLATIONS["alternatively_download_audio_as_mp3"]) + ), ) @property def audio_challenge_textbox(self) -> Locator: """The reCAPTCHA audio challenge textbox locator.""" return self.bframe_frame.get_by_role( - "textbox", - name=re.compile("|".join(TRANSLATIONS["enter_what_you_hear"])), + "textbox", name=re.compile("|".join(TRANSLATIONS["enter_what_you_hear"])) ) @property def skip_button(self) -> Locator: """The reCAPTCHA skip button locator.""" return self.bframe_frame.get_by_role( - "button", - name=re.compile("|".join(TRANSLATIONS["skip"])), + "button", name=re.compile("|".join(TRANSLATIONS["skip"])) ) @property def next_button(self) -> Locator: """The reCAPTCHA next button locator.""" return self.bframe_frame.get_by_role( - "button", - name=re.compile("|".join(TRANSLATIONS["next"])), + "button", name=re.compile("|".join(TRANSLATIONS["next"])) ) @property def verify_button(self) -> Locator: """The reCAPTCHA verify button locator.""" return self.bframe_frame.get_by_role( - "button", - name=re.compile("|".join(TRANSLATIONS["verify"])), + "button", name=re.compile("|".join(TRANSLATIONS["verify"])) ) @property def tile_selector(self) -> Locator: """The reCAPTCHA tile selector locator.""" - # return self.bframe_frame.locator(".rc-imageselect-tile") + return self.bframe_frame.locator(".rc-imageselect-tile") @property def image_challenge(self) -> Locator: """The reCAPTCHA image challenge locator.""" - # return self.bframe_frame.locator(".rc-imageselect-challenge") + return self.bframe_frame.locator(".rc-imageselect-challenge") def frames_are_attached(self) -> bool: """ @@ -405,7 +399,9 @@ def rate_limit_is_visible(self) -> bool: bool True if the reCAPTCHA rate limit message is visible, False otherwise. """ - return self.bframe_frame.get_by_text(re.compile("|".join(TRANSLATIONS["try_again_later"]))).is_visible() + return self.bframe_frame.get_by_text( + re.compile("|".join(TRANSLATIONS["try_again_later"])) + ).is_visible() @RecaptchaBox._check_if_attached def solve_failure_is_visible(self) -> bool: @@ -431,7 +427,9 @@ def audio_challenge_is_visible(self) -> bool: bool True if the reCAPTCHA audio challenge is visible, False otherwise. """ - return self.bframe_frame.get_by_text(re.compile("|".join(TRANSLATIONS["press_play_to_listen"]))).is_visible() + return self.bframe_frame.get_by_text( + re.compile("|".join(TRANSLATIONS["press_play_to_listen"])) + ).is_visible() @RecaptchaBox._check_if_attached def try_again_is_visible(self) -> bool: @@ -583,7 +581,9 @@ async def rate_limit_is_visible(self) -> bool: bool True if the reCAPTCHA rate limit message is visible, False otherwise. """ - return await self.bframe_frame.get_by_text(re.compile("|".join(TRANSLATIONS["try_again_later"]))).is_visible() + return await self.bframe_frame.get_by_text( + re.compile("|".join(TRANSLATIONS["try_again_later"])) + ).is_visible() @RecaptchaBox._check_if_attached async def solve_failure_is_visible(self) -> bool: @@ -609,8 +609,8 @@ async def audio_challenge_is_visible(self) -> bool: bool True if the reCAPTCHA audio challenge is visible, False otherwise. """ - return await self.bframe_frame.get_by_text(re.compile( - "|".join(TRANSLATIONS["press_play_to_listen"])) + return await self.bframe_frame.get_by_text( + re.compile("|".join(TRANSLATIONS["press_play_to_listen"])) ).is_visible() @RecaptchaBox._check_if_attached diff --git a/playwright_recaptcha/recaptchav2/translations.py b/playwright_recaptcha/recaptchav2/translations.py index 6ce9490..b52999b 100644 --- a/playwright_recaptcha/recaptchav2/translations.py +++ b/playwright_recaptcha/recaptchav2/translations.py @@ -1,76 +1,32 @@ TRANSLATIONS = { - "im_not_a_robot": ( - "I'm not a robot", - "Я не робот" - ), - - "get_an_audio_challenge": ( - "Get an audio challenge", - "Пройти аудиотест", - ), - - "get a visual challenge": ( - "Get a visual challenge", - "Пройти визуальный тест", - ), - - "get_a_new_challenge": ( - "Get a new challenge", - "Обновить", - ), - + "im_not_a_robot": ("I'm not a robot", "Я не робот"), + "get_an_audio_challenge": ("Get an audio challenge", "Пройти аудиотест"), + "get_a_visual_challenge": ("Get a visual challenge", "Пройти визуальный тест"), + "get_a_new_challenge": ("Get a new challenge", "Обновить"), "alternatively_download_audio_as_mp3": ( "Alternatively, download audio as MP3", "Скачать MP3-файл", ), - - "enter_what_you_hear": ( - "Enter what you hear", - "Введите прозвучавшие слова.", - ), - - "skip": ( - "Skip", - "Пропустить", - ), - - "next": ( - "Next", - "Далее", - ), - - "verify": ( - "Verify", - "Подтвердить", - ) - , - "try_again_later": ( - "Try again later", - "Повторите попытку позже", - ), - + "enter_what_you_hear": ("Enter what you hear", "Введите прозвучавшие слова"), + "skip": ("Skip", "Пропустить"), + "next": ("Next", "Далее"), + "verify": ("Verify", "Подтвердить"), + "try_again_later": ("Try again later", "Повторите попытку позже"), "multiple_correct_solutions_required": ( - "Multiple correct solutions required - please solve more.", - "Вы должны выполнить несколько заданий.", + "Multiple correct solutions required - please solve more", + "Вы должны выполнить несколько заданий", ), - "press_play_to_listen": ( "Press PLAY to listen", - 'Чтобы прослушать, нажмите "Воспроизвести".', - ), - - "please_try_again": ( - "Please try again", - "Повторите попытку." + 'Чтобы прослушать, нажмите "Воспроизвести"', ), - + "please_try_again": ("Please try again", "Повторите попытку"), "please_also_check_the_new_images": ( "Please also check the new images", - "Просмотрите также новые изображение.", + "Просмотрите также новые изображение", ), - "please_select_all_matching_images": ( "Please select all matching images", - "Выберите все совпадающие изображения.", + "Выберите все совпадающие изображения", ), -} \ No newline at end of file +} From 85bcb71ca3d69303287bee9701bb7f9e280f4eec Mon Sep 17 00:00:00 2001 From: Xewdy444 Date: Sun, 3 Mar 2024 08:47:20 -0600 Subject: [PATCH 4/8] Added translations for reCAPTCHA objects --- .../recaptchav2/async_solver.py | 39 ++++++++++--------- .../recaptchav2/sync_solver.py | 39 ++++++++++--------- .../recaptchav2/translations.py | 17 ++++++++ 3 files changed, 57 insertions(+), 38 deletions(-) diff --git a/playwright_recaptcha/recaptchav2/async_solver.py b/playwright_recaptcha/recaptchav2/async_solver.py index e90ca45..a06ea65 100644 --- a/playwright_recaptcha/recaptchav2/async_solver.py +++ b/playwright_recaptcha/recaptchav2/async_solver.py @@ -28,6 +28,7 @@ RecaptchaSolveError, ) from .recaptcha_box import AsyncRecaptchaBox +from .translations import TRANSLATIONS class AsyncAudioFile(speech_recognition.AudioFile): @@ -115,29 +116,29 @@ async def _get_task_object(recaptcha_box: AsyncRecaptchaBox) -> Optional[str]: The object ID. Returns None if the task object is not recognized. """ object_dict = { - "taxis": "/m/0pg52", - "bus": "/m/01bjv", - "school bus": "/m/02yvhj", - "motorcycles": "/m/04_sv", - "tractors": "/m/013xlm", - "chimneys": "/m/01jk_4", - "crosswalks": "/m/014xcs", - "traffic lights": "/m/015qff", - "bicycles": "/m/0199g", - "parking meters": "/m/015qbp", - "cars": "/m/0k4j", - "bridges": "/m/015kr", - "boats": "/m/019jd", - "palm trees": "/m/0cdl1", - "mountains or hills": "/m/09d_r", - "fire hydrant": "/m/01pns0", - "stairs": "/m/01lynh", + "/m/0pg52": TRANSLATIONS["taxis"], + "/m/01bjv": TRANSLATIONS["bus"], + "/m/02yvhj": TRANSLATIONS["school_bus"], + "/m/04_sv": TRANSLATIONS["motorcycles"], + "/m/013xlm": TRANSLATIONS["tractors"], + "/m/01jk_4": TRANSLATIONS["chimneys"], + "/m/014xcs": TRANSLATIONS["crosswalks"], + "/m/015qff": TRANSLATIONS["traffic_lights"], + "/m/0199g": TRANSLATIONS["bicycles"], + "/m/015qbp": TRANSLATIONS["parking_meters"], + "/m/0k4j": TRANSLATIONS["cars"], + "/m/015kr": TRANSLATIONS["bridges"], + "/m/019jd": TRANSLATIONS["boats"], + "/m/0cdl1": TRANSLATIONS["palm_trees"], + "/m/09d_r": TRANSLATIONS["mountains_or_hills"], + "/m/01pns0": TRANSLATIONS["fire_hydrant"], + "/m/01lynh": TRANSLATIONS["stairs"], } task = await recaptcha_box.bframe_frame.locator("div").all_inner_texts() - for object_name, object_id in object_dict.items(): - if object_name in task[0]: + for object_id, translations in object_dict.items(): + if any(translation in task[0] for translation in translations): return object_id return None diff --git a/playwright_recaptcha/recaptchav2/sync_solver.py b/playwright_recaptcha/recaptchav2/sync_solver.py index 06053b1..71d4487 100644 --- a/playwright_recaptcha/recaptchav2/sync_solver.py +++ b/playwright_recaptcha/recaptchav2/sync_solver.py @@ -20,6 +20,7 @@ RecaptchaSolveError, ) from .recaptcha_box import SyncRecaptchaBox +from .translations import TRANSLATIONS class SyncSolver: @@ -77,29 +78,29 @@ def _get_task_object(recaptcha_box: SyncRecaptchaBox) -> Optional[str]: The object ID. Returns None if the task object is not recognized. """ object_dict = { - "taxis": "/m/0pg52", - "bus": "/m/01bjv", - "school bus": "/m/02yvhj", - "motorcycles": "/m/04_sv", - "tractors": "/m/013xlm", - "chimneys": "/m/01jk_4", - "crosswalks": "/m/014xcs", - "traffic lights": "/m/015qff", - "bicycles": "/m/0199g", - "parking meters": "/m/015qbp", - "cars": "/m/0k4j", - "bridges": "/m/015kr", - "boats": "/m/019jd", - "palm trees": "/m/0cdl1", - "mountains or hills": "/m/09d_r", - "fire hydrant": "/m/01pns0", - "stairs": "/m/01lynh", + "/m/0pg52": TRANSLATIONS["taxis"], + "/m/01bjv": TRANSLATIONS["bus"], + "/m/02yvhj": TRANSLATIONS["school_bus"], + "/m/04_sv": TRANSLATIONS["motorcycles"], + "/m/013xlm": TRANSLATIONS["tractors"], + "/m/01jk_4": TRANSLATIONS["chimneys"], + "/m/014xcs": TRANSLATIONS["crosswalks"], + "/m/015qff": TRANSLATIONS["traffic_lights"], + "/m/0199g": TRANSLATIONS["bicycles"], + "/m/015qbp": TRANSLATIONS["parking_meters"], + "/m/0k4j": TRANSLATIONS["cars"], + "/m/015kr": TRANSLATIONS["bridges"], + "/m/019jd": TRANSLATIONS["boats"], + "/m/0cdl1": TRANSLATIONS["palm_trees"], + "/m/09d_r": TRANSLATIONS["mountains_or_hills"], + "/m/01pns0": TRANSLATIONS["fire_hydrant"], + "/m/01lynh": TRANSLATIONS["stairs"], } task = recaptcha_box.bframe_frame.locator("div").all_inner_texts() - for object_name, object_id in object_dict.items(): - if object_name in task[0]: + for object_id, translations in object_dict.items(): + if any(translation in task[0] for translation in translations): return object_id return None diff --git a/playwright_recaptcha/recaptchav2/translations.py b/playwright_recaptcha/recaptchav2/translations.py index b52999b..96581e1 100644 --- a/playwright_recaptcha/recaptchav2/translations.py +++ b/playwright_recaptcha/recaptchav2/translations.py @@ -29,4 +29,21 @@ "Please select all matching images", "Выберите все совпадающие изображения", ), + "taxis": ("taxis", "такси"), + "bus": ("bus", "автобус"), + "school_bus": ("school bus", "школьный автобус"), + "motorcycles": ("motorcycles", "мотоциклы"), + "tractors": ("tractors", "тракторы"), + "chimneys": ("chimneys", "дымоходы"), + "crosswalks": ("crosswalks", "пешеходные переходы"), + "traffic_lights": ("traffic lights", "светофоры"), + "bicycles": ("bicycles", "велосипеды"), + "parking_meters": ("parking meters", "парковочные автоматы"), + "cars": ("cars", "машины"), + "bridges": ("bridges", "мосты"), + "boats": ("boats", "лодки"), + "palm_trees": ("palm trees", "пальмы"), + "mountains_or_hills": ("mountains or hills", "горы или холмы"), + "fire_hydrant": ("fire hydrant", "пожарный гидрант"), + "stairs": ("stairs", "лестницы"), } From b5d49b9cf5e09e2ff78efbfa6b844917d0db950b Mon Sep 17 00:00:00 2001 From: SirFilippov Date: Sun, 3 Mar 2024 20:30:36 +0400 Subject: [PATCH 5/8] fix translation for few words --- playwright_recaptcha/recaptchav2/translations.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/playwright_recaptcha/recaptchav2/translations.py b/playwright_recaptcha/recaptchav2/translations.py index 96581e1..3051236 100644 --- a/playwright_recaptcha/recaptchav2/translations.py +++ b/playwright_recaptcha/recaptchav2/translations.py @@ -31,19 +31,19 @@ ), "taxis": ("taxis", "такси"), "bus": ("bus", "автобус"), - "school_bus": ("school bus", "школьный автобус"), + "school_bus": ("school bus", "автобусы"), "motorcycles": ("motorcycles", "мотоциклы"), - "tractors": ("tractors", "тракторы"), - "chimneys": ("chimneys", "дымоходы"), + "tractors": ("tractors", "трактора"), + "chimneys": ("chimneys", "дымовые трубы"), "crosswalks": ("crosswalks", "пешеходные переходы"), "traffic_lights": ("traffic lights", "светофоры"), "bicycles": ("bicycles", "велосипеды"), "parking_meters": ("parking meters", "парковочные автоматы"), - "cars": ("cars", "машины"), - "bridges": ("bridges", "мосты"), + "cars": ("cars", "автомобили"), + "bridges": ("bridges", "мостами"), "boats": ("boats", "лодки"), "palm_trees": ("palm trees", "пальмы"), "mountains_or_hills": ("mountains or hills", "горы или холмы"), - "fire_hydrant": ("fire hydrant", "пожарный гидрант"), + "fire_hydrant": ("fire hydrant", "пожарные гидранты"), "stairs": ("stairs", "лестницы"), } From 1f0284d475f7823f6aaec14c44ab23d3a261e32b Mon Sep 17 00:00:00 2001 From: Xewdy444 Date: Thu, 7 Mar 2024 16:39:23 -0600 Subject: [PATCH 6/8] Added fire hydrant translation --- playwright_recaptcha/recaptchav2/translations.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/playwright_recaptcha/recaptchav2/translations.py b/playwright_recaptcha/recaptchav2/translations.py index 3051236..4fa0683 100644 --- a/playwright_recaptcha/recaptchav2/translations.py +++ b/playwright_recaptcha/recaptchav2/translations.py @@ -44,6 +44,6 @@ "boats": ("boats", "лодки"), "palm_trees": ("palm trees", "пальмы"), "mountains_or_hills": ("mountains or hills", "горы или холмы"), - "fire_hydrant": ("fire hydrant", "пожарные гидранты"), + "fire_hydrant": ("fire hydrant", "гидрантами", "пожарные гидранты"), "stairs": ("stairs", "лестницы"), } From 4f0213dd8a8f03f650cd7338a2099e24f3ed7ddb Mon Sep 17 00:00:00 2001 From: Xewdy444 Date: Fri, 8 Mar 2024 17:24:14 -0600 Subject: [PATCH 7/8] Removed school bus from reCAPTCHA objects list The school bus object is not needed as CapSolver doesn't support it (anymore?). --- playwright_recaptcha/recaptchav2/async_solver.py | 1 - playwright_recaptcha/recaptchav2/sync_solver.py | 1 - playwright_recaptcha/recaptchav2/translations.py | 1 - 3 files changed, 3 deletions(-) diff --git a/playwright_recaptcha/recaptchav2/async_solver.py b/playwright_recaptcha/recaptchav2/async_solver.py index a06ea65..20572b5 100644 --- a/playwright_recaptcha/recaptchav2/async_solver.py +++ b/playwright_recaptcha/recaptchav2/async_solver.py @@ -118,7 +118,6 @@ async def _get_task_object(recaptcha_box: AsyncRecaptchaBox) -> Optional[str]: object_dict = { "/m/0pg52": TRANSLATIONS["taxis"], "/m/01bjv": TRANSLATIONS["bus"], - "/m/02yvhj": TRANSLATIONS["school_bus"], "/m/04_sv": TRANSLATIONS["motorcycles"], "/m/013xlm": TRANSLATIONS["tractors"], "/m/01jk_4": TRANSLATIONS["chimneys"], diff --git a/playwright_recaptcha/recaptchav2/sync_solver.py b/playwright_recaptcha/recaptchav2/sync_solver.py index 71d4487..5ba0fd0 100644 --- a/playwright_recaptcha/recaptchav2/sync_solver.py +++ b/playwright_recaptcha/recaptchav2/sync_solver.py @@ -80,7 +80,6 @@ def _get_task_object(recaptcha_box: SyncRecaptchaBox) -> Optional[str]: object_dict = { "/m/0pg52": TRANSLATIONS["taxis"], "/m/01bjv": TRANSLATIONS["bus"], - "/m/02yvhj": TRANSLATIONS["school_bus"], "/m/04_sv": TRANSLATIONS["motorcycles"], "/m/013xlm": TRANSLATIONS["tractors"], "/m/01jk_4": TRANSLATIONS["chimneys"], diff --git a/playwright_recaptcha/recaptchav2/translations.py b/playwright_recaptcha/recaptchav2/translations.py index 4fa0683..6a180ce 100644 --- a/playwright_recaptcha/recaptchav2/translations.py +++ b/playwright_recaptcha/recaptchav2/translations.py @@ -31,7 +31,6 @@ ), "taxis": ("taxis", "такси"), "bus": ("bus", "автобус"), - "school_bus": ("school bus", "автобусы"), "motorcycles": ("motorcycles", "мотоциклы"), "tractors": ("tractors", "трактора"), "chimneys": ("chimneys", "дымовые трубы"), From bf047a2d1cc8a44e2ac8ceb87a4a0b1a977eeedd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 11 Mar 2024 08:37:10 +0000 Subject: [PATCH 8/8] Bump pytest-asyncio from 0.23.5 to 0.23.5.post1 Bumps [pytest-asyncio](https://github.com/pytest-dev/pytest-asyncio) from 0.23.5 to 0.23.5.post1. - [Release notes](https://github.com/pytest-dev/pytest-asyncio/releases) - [Commits](https://github.com/pytest-dev/pytest-asyncio/compare/v0.23.5...v0.23.5.post1) --- updated-dependencies: - dependency-name: pytest-asyncio dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index e84b05b..f041ec5 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,6 +1,6 @@ playwright>=1.33.0 pydub==0.25.1 -pytest-asyncio==0.23.5 +pytest-asyncio==0.23.5.post1 setuptools==69.1.1 SpeechRecognition==3.10.1 tenacity==8.2.3