diff --git a/requirements.txt b/requirements.txt index 7819c8a0dc3..319eb75ab15 100755 --- a/requirements.txt +++ b/requirements.txt @@ -68,6 +68,7 @@ python-xlib==0.33;platform_system=="Linux" markdown-it-py==3.0.0 mdurl==0.1.2 rich>=14.0.0,<15 +opencv-python>=4.11.0.86 # --- Testing Requirements --- # # ("pip install -r requirements.txt" also installs this, but "pip install -e ." won't.) diff --git a/seleniumbase/undetected/cdp_driver/cdp_util.py b/seleniumbase/undetected/cdp_driver/cdp_util.py index 8013b340645..121531955e6 100644 --- a/seleniumbase/undetected/cdp_driver/cdp_util.py +++ b/seleniumbase/undetected/cdp_driver/cdp_util.py @@ -655,3 +655,1117 @@ def cdp_get_module(domain: Union[str, types.ModuleType]): "Could not find cdp module from input '%s'" % domain ) return domain_mod + +def get_cf_template() -> bytearray: + """ + this returns a 36x36 px image of a cf checkbox + """ + return bytearray( + [ + 255, + 216, + 255, + 224, + 0, + 16, + 74, + 70, + 73, + 70, + 0, + 1, + 1, + 1, + 0, + 96, + 0, + 96, + 0, + 0, + 255, + 219, + 0, + 67, + 0, + 2, + 1, + 1, + 2, + 1, + 1, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 3, + 5, + 3, + 3, + 3, + 3, + 3, + 6, + 4, + 4, + 3, + 5, + 7, + 6, + 7, + 7, + 7, + 6, + 7, + 7, + 8, + 9, + 11, + 9, + 8, + 8, + 10, + 8, + 7, + 7, + 10, + 13, + 10, + 10, + 11, + 12, + 12, + 12, + 12, + 7, + 9, + 14, + 15, + 13, + 12, + 14, + 11, + 12, + 12, + 12, + 255, + 219, + 0, + 67, + 1, + 2, + 2, + 2, + 3, + 3, + 3, + 6, + 3, + 3, + 6, + 12, + 8, + 7, + 8, + 12, + 12, + 12, + 12, + 12, + 12, + 12, + 12, + 12, + 12, + 12, + 12, + 12, + 12, + 12, + 12, + 12, + 12, + 12, + 12, + 12, + 12, + 12, + 12, + 12, + 12, + 12, + 12, + 12, + 12, + 12, + 12, + 12, + 12, + 12, + 12, + 12, + 12, + 12, + 12, + 12, + 12, + 12, + 12, + 12, + 12, + 12, + 12, + 12, + 12, + 255, + 192, + 0, + 17, + 8, + 0, + 61, + 0, + 43, + 3, + 1, + 34, + 0, + 2, + 17, + 1, + 3, + 17, + 1, + 255, + 196, + 0, + 31, + 0, + 0, + 1, + 5, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 255, + 196, + 0, + 181, + 16, + 0, + 2, + 1, + 3, + 3, + 2, + 4, + 3, + 5, + 5, + 4, + 4, + 0, + 0, + 1, + 125, + 1, + 2, + 3, + 0, + 4, + 17, + 5, + 18, + 33, + 49, + 65, + 6, + 19, + 81, + 97, + 7, + 34, + 113, + 20, + 50, + 129, + 145, + 161, + 8, + 35, + 66, + 177, + 193, + 21, + 82, + 209, + 240, + 36, + 51, + 98, + 114, + 130, + 9, + 10, + 22, + 23, + 24, + 25, + 26, + 37, + 38, + 39, + 40, + 41, + 42, + 52, + 53, + 54, + 55, + 56, + 57, + 58, + 67, + 68, + 69, + 70, + 71, + 72, + 73, + 74, + 83, + 84, + 85, + 86, + 87, + 88, + 89, + 90, + 99, + 100, + 101, + 102, + 103, + 104, + 105, + 106, + 115, + 116, + 117, + 118, + 119, + 120, + 121, + 122, + 131, + 132, + 133, + 134, + 135, + 136, + 137, + 138, + 146, + 147, + 148, + 149, + 150, + 151, + 152, + 153, + 154, + 162, + 163, + 164, + 165, + 166, + 167, + 168, + 169, + 170, + 178, + 179, + 180, + 181, + 182, + 183, + 184, + 185, + 186, + 194, + 195, + 196, + 197, + 198, + 199, + 200, + 201, + 202, + 210, + 211, + 212, + 213, + 214, + 215, + 216, + 217, + 218, + 225, + 226, + 227, + 228, + 229, + 230, + 231, + 232, + 233, + 234, + 241, + 242, + 243, + 244, + 245, + 246, + 247, + 248, + 249, + 250, + 255, + 196, + 0, + 31, + 1, + 0, + 3, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 255, + 196, + 0, + 181, + 17, + 0, + 2, + 1, + 2, + 4, + 4, + 3, + 4, + 7, + 5, + 4, + 4, + 0, + 1, + 2, + 119, + 0, + 1, + 2, + 3, + 17, + 4, + 5, + 33, + 49, + 6, + 18, + 65, + 81, + 7, + 97, + 113, + 19, + 34, + 50, + 129, + 8, + 20, + 66, + 145, + 161, + 177, + 193, + 9, + 35, + 51, + 82, + 240, + 21, + 98, + 114, + 209, + 10, + 22, + 36, + 52, + 225, + 37, + 241, + 23, + 24, + 25, + 26, + 38, + 39, + 40, + 41, + 42, + 53, + 54, + 55, + 56, + 57, + 58, + 67, + 68, + 69, + 70, + 71, + 72, + 73, + 74, + 83, + 84, + 85, + 86, + 87, + 88, + 89, + 90, + 99, + 100, + 101, + 102, + 103, + 104, + 105, + 106, + 115, + 116, + 117, + 118, + 119, + 120, + 121, + 122, + 130, + 131, + 132, + 133, + 134, + 135, + 136, + 137, + 138, + 146, + 147, + 148, + 149, + 150, + 151, + 152, + 153, + 154, + 162, + 163, + 164, + 165, + 166, + 167, + 168, + 169, + 170, + 178, + 179, + 180, + 181, + 182, + 183, + 184, + 185, + 186, + 194, + 195, + 196, + 197, + 198, + 199, + 200, + 201, + 202, + 210, + 211, + 212, + 213, + 214, + 215, + 216, + 217, + 218, + 226, + 227, + 228, + 229, + 230, + 231, + 232, + 233, + 234, + 242, + 243, + 244, + 245, + 246, + 247, + 248, + 249, + 250, + 255, + 218, + 0, + 12, + 3, + 1, + 0, + 2, + 17, + 3, + 17, + 0, + 63, + 0, + 253, + 233, + 223, + 245, + 252, + 205, + 27, + 254, + 191, + 153, + 164, + 162, + 128, + 23, + 127, + 215, + 243, + 52, + 111, + 250, + 254, + 102, + 146, + 138, + 0, + 93, + 255, + 0, + 95, + 204, + 209, + 191, + 235, + 249, + 154, + 74, + 40, + 0, + 81, + 184, + 226, + 188, + 151, + 246, + 190, + 248, + 249, + 172, + 252, + 8, + 240, + 47, + 135, + 191, + 225, + 27, + 211, + 244, + 221, + 67, + 196, + 222, + 50, + 241, + 21, + 143, + 134, + 116, + 149, + 212, + 93, + 214, + 206, + 11, + 155, + 166, + 125, + 173, + 48, + 79, + 156, + 162, + 132, + 109, + 219, + 78, + 125, + 187, + 87, + 173, + 117, + 175, + 157, + 127, + 224, + 161, + 169, + 153, + 126, + 4, + 252, + 199, + 254, + 74, + 255, + 0, + 135, + 207, + 65, + 235, + 56, + 253, + 122, + 253, + 104, + 1, + 194, + 211, + 246, + 186, + 56, + 255, + 0, + 147, + 114, + 92, + 246, + 39, + 89, + 227, + 219, + 173, + 13, + 101, + 251, + 94, + 227, + 129, + 251, + 55, + 231, + 182, + 91, + 90, + 255, + 0, + 10, + 250, + 112, + 46, + 40, + 52, + 1, + 243, + 135, + 192, + 159, + 143, + 63, + 17, + 227, + 253, + 163, + 245, + 47, + 133, + 255, + 0, + 20, + 52, + 239, + 5, + 255, + 0, + 109, + 47, + 135, + 19, + 197, + 54, + 55, + 222, + 23, + 146, + 228, + 90, + 27, + 111, + 180, + 155, + 102, + 138, + 65, + 113, + 243, + 25, + 4, + 152, + 228, + 96, + 99, + 181, + 123, + 207, + 217, + 238, + 38, + 1, + 163, + 41, + 180, + 129, + 214, + 50, + 121, + 239, + 220, + 119, + 205, + 124, + 243, + 122, + 79, + 252, + 61, + 209, + 121, + 111, + 249, + 36, + 28, + 115, + 235, + 173, + 100, + 254, + 120, + 175, + 122, + 190, + 138, + 75, + 139, + 157, + 227, + 31, + 50, + 169, + 253, + 5, + 76, + 164, + 146, + 187, + 42, + 49, + 230, + 118, + 69, + 225, + 244, + 207, + 183, + 173, + 124, + 231, + 255, + 0, + 5, + 13, + 98, + 37, + 248, + 19, + 207, + 252, + 213, + 255, + 0, + 15, + 243, + 183, + 140, + 127, + 164, + 115, + 159, + 114, + 56, + 246, + 175, + 163, + 1, + 193, + 174, + 31, + 227, + 223, + 192, + 13, + 11, + 246, + 138, + 240, + 36, + 122, + 14, + 185, + 38, + 165, + 106, + 182, + 183, + 112, + 223, + 216, + 223, + 105, + 215, + 31, + 103, + 189, + 211, + 110, + 97, + 109, + 209, + 77, + 12, + 152, + 33, + 93, + 50, + 64, + 56, + 56, + 201, + 239, + 205, + 81, + 39, + 165, + 111, + 250, + 143, + 194, + 130, + 192, + 142, + 162, + 190, + 97, + 31, + 240, + 78, + 221, + 189, + 62, + 59, + 126, + 209, + 139, + 129, + 129, + 143, + 25, + 244, + 31, + 247, + 230, + 134, + 255, + 0, + 130, + 118, + 179, + 46, + 63, + 225, + 124, + 126, + 210, + 60, + 250, + 120, + 220, + 255, + 0, + 241, + 154, + 0, + 146, + 236, + 19, + 255, + 0, + 5, + 115, + 94, + 159, + 242, + 72, + 14, + 125, + 71, + 252, + 78, + 128, + 233, + 239, + 95, + 68, + 21, + 205, + 121, + 55, + 192, + 111, + 216, + 251, + 67, + 248, + 19, + 227, + 77, + 75, + 196, + 191, + 240, + 144, + 120, + 211, + 198, + 94, + 36, + 212, + 173, + 19, + 79, + 58, + 175, + 138, + 53, + 95, + 237, + 27, + 171, + 123, + 85, + 98, + 226, + 8, + 219, + 106, + 225, + 55, + 157, + 220, + 130, + 114, + 58, + 215, + 172, + 209, + 107, + 134, + 250, + 133, + 20, + 81, + 64, + 5, + 20, + 81, + 64, + 5, + 20, + 81, + 64, + 31, + 255, + 217, + ] + ) diff --git a/seleniumbase/undetected/cdp_driver/tab.py b/seleniumbase/undetected/cdp_driver/tab.py index 95f6f77ab75..70b797bd215 100644 --- a/seleniumbase/undetected/cdp_driver/tab.py +++ b/seleniumbase/undetected/cdp_driver/tab.py @@ -1,9 +1,12 @@ from __future__ import annotations import asyncio import base64 +import cv2 import datetime import logging +import os import pathlib +import uuid import urllib.parse import warnings from seleniumbase import config as sb_config @@ -137,6 +140,7 @@ def __init__( self.browser = browser self._dom = None self._window_id = None + self._window_uuid = uuid.uuid4() async def __aenter__(self): return self @@ -1283,19 +1287,146 @@ async def get_all_urls(self, absolute=True) -> List[str]: res.append(abs_url) return res - async def verify_cf(self): - """(An attempt)""" - checkbox = None - checkbox_sibling = await self.wait_for(text="verify you are human") - if checkbox_sibling: - parent = checkbox_sibling.parent - while parent: - checkbox = await parent.query_selector("input[type=checkbox]") - if checkbox: - break - parent = parent.parent - await checkbox.mouse_move() - await checkbox.mouse_click() + async def mouse_click( + self, + x: float, + y: float, + button: str = "left", + buttons: Optional[int] = 1, + modifiers: Optional[int] = 0, + _until_event: Optional[type] = None, + ): + """native click on position x,y + :param y: + :type y: + :param x: + :type x: + :param button: str (default = "left") + :param buttons: which button (default 1 = left) + :param modifiers: *(Optional)* Bit field representing pressed modifier keys. + Alt=1, Ctrl=2, Meta/Command=4, Shift=8 (default: 0). + :param _until_event: internal. event to wait for before returning + :return: + """ + + await self.send( + cdp.input_.dispatch_mouse_event( + "mousePressed", + x=x, + y=y, + modifiers=modifiers, + button=cdp.input_.MouseButton(button), + buttons=buttons, + click_count=1, + ) + ) + + await self.send( + cdp.input_.dispatch_mouse_event( + "mouseReleased", + x=x, + y=y, + modifiers=modifiers, + button=cdp.input_.MouseButton(button), + buttons=buttons, + click_count=1, + ) + ) + + async def verify_checkbox(self, checkbox_template_path: str = None): + """ + convenience function to click on a checkbox simulating a mouse click + + :param checkbox_template: + checkbox_template can be custom (for example your language, included is english only), + but you need to create the checkbox_template yourself, which is just a cropped + image of the area, where the target is exactly in the center. see example on + (https://ultrafunkamsterdam.github.io/nodriver/nodriver/classes/tab.html#example-111x71), + + :type template_image: + :param flash: whether to show an indicator where the mouse is clicking. + :type flash: + :return: + :rtype: + """ + if self.browser and self.browser.config and self.browser.config.expert: + raise Exception( + """ + this function is useless in expert mode, since it disables site-isolation-trials. + while this is a useful future to have access to all elements (also in iframes), + it is also being detected. + """ + ) + x, y = await self.get_checkbox_coords( + checkbox_template_path=checkbox_template_path + ) + await self.mouse_click(x, y) + + async def get_checkbox_coords( + self, checkbox_template_path: PathLike = None + ) -> Union[Tuple[int, int], None]: + """ + attempts to find the location of given checkbox image in the current viewport + the only real use case for this is bot-detection systems. + you can find for example the location of a 'verify'-checkbox, + which are hidden from dom using shadow-root's or workers. + + checkbox_template can be custom, but you need to create the checkbox_template yourself, + which is just a cropped image of the area, where the checkbox is exactly in the center. + + :param checkbox_template: + :type checkbox_template: + :return: + :rtype: + """ + try: + + if checkbox_template_path: + checkbox_template = pathlib.Path(checkbox_template_path) + if not checkbox_template.exists(): + raise FileNotFoundError( + "%s was not found in the current location : %s" + % (checkbox_template, os.getcwd()) + ) + + await self.save_screenshot(f"auto_tab_screenshot_{self._window_uuid}.jpg") + await self.sleep(0.05) + im = cv2.imread(f"auto_tab_screenshot_{self._window_uuid}.jpg") + im_gray = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY) + if checkbox_template: + checkbox = cv2.imread(str(checkbox_template)) + else: + with open(f"checkbox_template_{self._window_uuid}.png", "w+b") as fh: + fh.write(util.get_cf_template()) + checkbox = cv2.imread(f"checkbox_template_{self._window_uuid}.png") + template_gray = cv2.cvtColor(checkbox, cv2.COLOR_BGR2GRAY) + match = cv2.matchTemplate(im_gray, template_gray, cv2.TM_CCOEFF_NORMED) + (min_v, max_v, min_l, max_l) = cv2.minMaxLoc(match) + (xs, ys) = max_l + tmp_h, tmp_w = template_gray.shape[:2] + xe = xs + tmp_w + ye = ys + tmp_h + cx = (xs + xe) // 2 + cy = (ys + ye) // 2 + return cx, cy + except (TypeError, OSError, PermissionError): + pass # ignore these exceptions + except: # noqa - don't ignore other exceptions + raise + finally: + try: + os.unlink(f"auto_tab_screenshot_{self._window_uuid}.jpg") + except (FileNotFoundError, PermissionError) as e: + logger.warning(f"Could not unlink temporary screenshot: {e}") + if checkbox_template: + pass + else: + try: + os.unlink(f"checkbox_template_{self._window_uuid}.png") + except: # noqa + logger.warning( + f"could not unlink template file checkbox_template_{self._window_uuid}.png" + ) async def get_document(self): return await self.send(cdp.dom.get_document())

AltStyle によって変換されたページ (->オリジナル) /