diff --git a/setup.py b/setup.py index 4ed2a93..9eccee9 100644 --- a/setup.py +++ b/setup.py @@ -16,7 +16,7 @@ from setuptools import setup setup( name="undetected-chromedriver", - version="2.0.2", + version="2.1.0", packages=["undetected_chromedriver"], install_requires=["selenium",], url="https://github.com/ultrafunkamsterdam/undetected-chromedriver", diff --git a/undetected_chromedriver/__init__.py b/undetected_chromedriver/__init__.py index a56ff4a..a735fe5 100644 --- a/undetected_chromedriver/__init__.py +++ b/undetected_chromedriver/__init__.py @@ -37,7 +37,7 @@ TARGET_VERSION = 0 class Chrome: - def __new__(cls, *args, enable_console_log=False, **kwargs): + def __new__(cls, *args, emulate_touch=False, **kwargs): if not ChromeDriverManager.installed: ChromeDriverManager(*args, **kwargs).install() @@ -61,28 +61,25 @@ class Chrome: { "source": """ - Object.defineProperty(window, 'navigator', { - value: new Proxy(navigator, { - has: (target, key) => (key === 'webdriver' ? false : key in target), - get: (target, key) => - key === 'webdriver' - ? undefined - : typeof target[key] === 'function' - ? target[key].bind(target) - : target[key] - }) - }); - """ - + ( - "console.log = console.dir = console.error = function(){};" - if not enable_console_log - else "" - ) + Object.defineProperty(window, 'navigator', { + value: new Proxy(navigator, { + has: (target, key) => (key === 'webdriver' ? false : key in target), + get: (target, key) => + key === 'webdriver' + ? undefined + : typeof target[key] === 'function' + ? target[key].bind(target) + : target[key] + }) + }); + """ }, ) return instance._orig_get(*args, **kwargs) instance.get = _get_wrapped + instance.get = _get_wrapped + instance.get = _get_wrapped original_user_agent_string = instance.execute_script( "return navigator.userAgent" @@ -91,11 +88,22 @@ class Chrome: "Network.setUserAgentOverride", {"userAgent": original_user_agent_string.replace("Headless", ""),}, ) + if emulate_touch: + instance.execute_cdp_cmd( + "Page.addScriptToEvaluateOnNewDocument", + { + "source": """ + Object.defineProperty(navigator, 'maxTouchPoints', { + get: () => 1 + })""" + }, + ) logger.info(f"starting undetected_chromedriver.Chrome({args}, {kwargs})") return instance class ChromeOptions: + def __new__(cls, *args, **kwargs): if not ChromeDriverManager.installed: ChromeDriverManager(*args, **kwargs).install() diff --git a/undetected_chromedriver/v2.py b/undetected_chromedriver/v2.py index 131c0da..86a40d6 100644 --- a/undetected_chromedriver/v2.py +++ b/undetected_chromedriver/v2.py @@ -119,8 +119,9 @@ class Chrome(selenium.webdriver.chrome.webdriver.WebDriver): keep_alive=True, debug_addr=None, user_data_dir=None, - factor=0.5, - delay=1, + factor=1, + delay=2, + emulate_touch=False, ): p = Patcher(target_path=executable_path) @@ -165,6 +166,7 @@ class Chrome(selenium.webdriver.chrome.webdriver.WebDriver): extra_args = [] if options.headless: extra_args.append("--headless") + extra_args.append("--window-size=1920,1080") self.browser_args = [ find_chrome_executable(), @@ -195,12 +197,60 @@ class Chrome(selenium.webdriver.chrome.webdriver.WebDriver): keep_alive=keep_alive, ) + if options.headless: + + orig_get = self.get + + def get_wrapped(*args, **kwargs): + if self.execute_script("return navigator.webdriver"): + self.execute_cdp_cmd( + "Page.addScriptToEvaluateOnNewDocument", + { + "source": """ + Object.defineProperty(window, 'navigator', { + value: new Proxy(navigator, { + has: (target, key) => (key === 'webdriver' ? false : key in target), + get: (target, key) => + key === 'webdriver' + ? undefined + : typeof target[key] === 'function' + ? target[key].bind(target) + : target[key] + }) + }); + """ + }, + ) + + self.execute_cdp_cmd( + "Network.setUserAgentOverride", + { + "userAgent": self.execute_script( + "return navigator.userAgent" + ).replace("Headless", "") + }, + ) + return orig_get(*args, **kwargs) + + self.get = get_wrapped + + if emulate_touch: + self.execute_cdp_cmd( + "Page.addScriptToEvaluateOnNewDocument", + { + "source": """ + Object.defineProperty(navigator, 'maxTouchPoints', { + get: () => 1 + })""" + }, + ) + def start_session(self, capabilities=None, browser_profile=None): if not capabilities: capabilities = self.options.to_capabilities() super().start_session(capabilities, browser_profile) - def get_in(self, url: str, delay=2.5, factor=1): + def get_in(self, url: str, delay=2, factor=1): """ :param url: str :param delay: int @@ -233,10 +283,11 @@ class Chrome(selenium.webdriver.chrome.webdriver.WebDriver): try: self.get(url) finally: - self.close() + self.service.stop() # threading.Timer(factor or self.factor, self.close).start() time.sleep(delay or self.delay) - self.start_session() + self.service.start() + # self.start_session() def quit(self): try: @@ -263,9 +314,10 @@ class Chrome(selenium.webdriver.chrome.webdriver.WebDriver): return self def __exit__(self, exc_type, exc_val, exc_tb): - self.close() - threading.Timer(self.factor, self.start_session).start() + self.service.stop() + #threading.Timer(self.factor, self.service.start).start() time.sleep(self.delay) + self.service.start() def __hash__(self): return hash(self.options.debugger_address) @@ -274,10 +326,9 @@ class Chrome(selenium.webdriver.chrome.webdriver.WebDriver): class Patcher(object): url_repo = "https://chromedriver.storage.googleapis.com" - def __init__(self, target_path=None, force=False, version_main: int = 0): - - if not target_path: - target_path = os.path.join(tempfile.gettempdir(), 'undetected_chromedriver', 'chromedriver') + def __init__( + self, target_path="./chromedriver", force=False, version_main: int = 0 + ): if not IS_POSIX: if not target_path[-4:] == ".exe": target_path += ".exe" @@ -446,8 +497,8 @@ class Patcher(object): linect += 1 return linect - def __del__(self): - shutil.rmtree(os.path.dirname(self.target_path), ignore_errors=True) + + class ChromeOptions(selenium.webdriver.chrome.webdriver.Options):