From 948bc167f4d69a95db5481f04b437c6d7cb068bc Mon Sep 17 00:00:00 2001 From: ultrafunkamsterdam Date: Sun, 14 Jul 2024 17:16:23 +0200 Subject: [PATCH] added options and . when those are both provided, nodriver will attempt to connect an existing debuggable session instead of launching a local browser --- _update_changes.py | 8 ++++--- nodriver/core/browser.py | 48 +++++++++++++++++++++---------------- nodriver/core/config.py | 13 +++++----- nodriver/core/connection.py | 2 +- nodriver/core/util.py | 14 +++++++++++ pyproject.toml | 4 ++-- 6 files changed, 57 insertions(+), 32 deletions(-) diff --git a/_update_changes.py b/_update_changes.py index 42fbb41..71b7881 100644 --- a/_update_changes.py +++ b/_update_changes.py @@ -77,16 +77,18 @@ def get_version(project_file: Path): subprocess.run("make.bat html", shell=True, cwd="./docs") subprocess.run("make.bat markdown", shell=True, cwd="./docs") subprocess.run("copy docs\\_build\\markdown\\README.md .", shell=True) + +subprocess.run("black nodriver/core/*.py") change_version() -subprocess.run("black nodriver/core *.py") modified_files = list( m[1] for m in re.finditer("modified:\s+(.+)", subprocess.getoutput("git status")) ) subprocess.run("git add " + " ".join(modified_files), shell=True) subprocess.run("git status") - -commit = input("commit message (use no quotes) :") +commit = None +if modified_files: + commit = input("commit message (use no quotes) :") if commit: subprocess.run(f'git commit -m "{commit}"') diff --git a/nodriver/core/browser.py b/nodriver/core/browser.py index e8157b7..db92988 100644 --- a/nodriver/core/browser.py +++ b/nodriver/core/browser.py @@ -69,6 +69,8 @@ async def create( browser_executable_path: PathLike = None, browser_args: List[str] = None, sandbox: bool = True, + host: str = None, + port: int = None, **kwargs, ) -> Browser: """ @@ -81,6 +83,8 @@ async def create( browser_executable_path=browser_executable_path, browser_args=browser_args or [], sandbox=sandbox, + host=host, + port=port, **kwargs, ) instance = cls(config) @@ -272,28 +276,32 @@ async def start(self=None) -> Browser: # self.config.update(kwargs) connect_existing = False - if self.config.host and self.config.port: + if self.config.host is not None and self.config.port is not None: connect_existing = True - self.config.host = self.config.host or "127.0.0.1" - self.config.port = self.config.port or util.free_port() + else: + self.config.host = "127.0.0.1" + self.config.port = util.free_port() - logger.debug("BROWSER EXECUTABLE PATH: %s", self.config.browser_executable_path) - if not pathlib.Path(self.config.browser_executable_path).exists(): - raise FileNotFoundError( - ( - """ - --------------------- - Could not determine browser executable. - --------------------- - Make sure your browser is installed in the default location (path). - If you are sure about the browser executable, you can specify it using - the `browser_executable_path='{}` parameter.""" - ).format( - "/path/to/browser/executable" - if is_posix - else "c:/path/to/your/browser.exe" - ) + if not connect_existing: + logger.debug( + "BROWSER EXECUTABLE PATH: %s", self.config.browser_executable_path ) + if not pathlib.Path(self.config.browser_executable_path).exists(): + raise FileNotFoundError( + ( + """ + --------------------- + Could not determine browser executable. + --------------------- + Make sure your browser is installed in the default location (path). + If you are sure about the browser executable, you can specify it using + the `browser_executable_path='{}` parameter.""" + ).format( + "/path/to/browser/executable" + if is_posix + else "c:/path/to/your/browser.exe" + ) + ) if getattr(self.config, "_extensions", None): # noqa self.config.add_argument( @@ -810,7 +818,7 @@ async def _request(self, endpoint, method: str = "get", data: dict = None): request.data = json.dumps(data).encode("utf-8") response = await asyncio.get_running_loop().run_in_executor( - None, urllib.request.urlopen, request + None, lambda: urllib.request.urlopen(request, timeout=10) ) return json.loads(response.read()) diff --git a/nodriver/core/config.py b/nodriver/core/config.py index 8a83b00..d202727 100644 --- a/nodriver/core/config.py +++ b/nodriver/core/config.py @@ -39,6 +39,8 @@ def __init__( browser_args: Optional[List[str]] = AUTO, sandbox: Optional[bool] = True, lang: Optional[str] = "en-US", + host: str = AUTO, + port: int = AUTO, **kwargs: dict, ): """ @@ -87,8 +89,8 @@ def __init__( self.browser_executable_path = browser_executable_path self.headless = headless self.sandbox = sandbox - self.host = None - self.port = None + self.host = host + self.port = port self._extensions = [] # when using posix-ish operating system and running as root # you must use no_sandbox = True, which in case is corrected here @@ -164,15 +166,14 @@ def add_extension(self, extension_path: PathLike): path = item.parent self._extensions.append(path) - def __getattr__(self, item): - if item not in self.__dict__: - return + # def __getattr__(self, item): + # if item not in self.__dict__: def __call__(self): # the host and port will be added when starting # the browser, as by the time it starts, the port # is probably already taken - args = self._default_browser_args + args = self._default_browser_args.copy() args += ["--user-data-dir=%s" % self.user_data_dir] args += ["--disable-features=IsolateOrigins,site-per-process"] args += ["--disable-session-crashed-bubble"] diff --git a/nodriver/core/connection.py b/nodriver/core/connection.py index 4dbba5c..104f848 100644 --- a/nodriver/core/connection.py +++ b/nodriver/core/connection.py @@ -556,7 +556,7 @@ async def listener_loop(self): # pop to prevent memory leaks tx = self.connection.mapper.pop(message["id"]) - logger.debug("got answer for %s", tx) + logger.debug("got answer for %s (message_id:%d)", tx, message["id"]) # complete the transaction, which is a Future object # and thus will return to anyone awaiting it. diff --git a/nodriver/core/util.py b/nodriver/core/util.py index 8bf94de..f8f8a35 100644 --- a/nodriver/core/util.py +++ b/nodriver/core/util.py @@ -31,6 +31,8 @@ async def start( browser_args: Optional[List[str]] = None, sandbox: Optional[bool] = True, lang: Optional[str] = None, + host: Optional[str] = None, + port: Optional[int] = None, **kwargs: Optional[dict], ) -> Browser: """ @@ -39,6 +41,7 @@ async def start( with best practice defaults. note: this should be called ```await start()``` + :param user_data_dir: :type user_data_dir: PathLike @@ -57,9 +60,18 @@ async def start( :param lang: language string :type lang: str + + :param port: if you connect to an existing debuggable session, you can specify the port here + if both host and port are provided, nodriver will not start a local chrome browser! + :type port: int + + :param host: if you connect to an existing debuggable session, you can specify the host here + if both host and port are provided, nodriver will not start a local chrome browser! + :type host: str :return: """ if not config: + config = Config( user_data_dir, headless, @@ -67,6 +79,8 @@ async def start( browser_args, sandbox, lang, + host=host, + port=port, **kwargs, ) from .browser import Browser diff --git a/pyproject.toml b/pyproject.toml index 0fbcb2f..1f56a8e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,7 +1,7 @@ [project] name = "nodriver" # Required -version = "0.33" # Required +version = "0.34" # Required description = """ @@ -84,7 +84,7 @@ dependencies = [ [tool.setuptools] include-package-data = true -packages = ["nodriver"] +packages = ["nodriver", "nodriver.core", "nodriver.cdp"] [build-system] requires = ["setuptools>=43.0.0", "wheel"]