From 066eadc7e045a1599fd4e6915de49bd7afe13733 Mon Sep 17 00:00:00 2001 From: g1879 Date: Sun, 19 Nov 2023 19:49:01 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=E5=85=B3=E9=97=AD=E9=9A=90?= =?UTF-8?q?=E7=A7=81=E5=A3=B0=E6=98=8E=E9=80=BB=E8=BE=91=EF=BC=9B=E6=94=AF?= =?UTF-8?q?=E6=8C=81=E8=AE=BE=E7=BD=AE=E5=AE=9E=E9=AA=8C=E9=A1=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- DrissionPage/__init__.py | 2 +- DrissionPage/_commons/browser.py | 46 +++++++++++++++++++--- DrissionPage/_commons/browser.pyi | 3 ++ DrissionPage/_configs/chromium_options.py | 27 ++++++++++++- DrissionPage/_configs/chromium_options.pyi | 9 +++++ DrissionPage/_configs/configs.ini | 1 + DrissionPage/_pages/chromium_base.py | 19 +++++++-- setup.py | 2 +- 8 files changed, 97 insertions(+), 12 deletions(-) diff --git a/DrissionPage/__init__.py b/DrissionPage/__init__.py index 5b6d740..46a2a1d 100644 --- a/DrissionPage/__init__.py +++ b/DrissionPage/__init__.py @@ -13,4 +13,4 @@ from ._configs.chromium_options import ChromiumOptions from ._configs.session_options import SessionOptions __all__ = ['ChromiumPage', 'ChromiumOptions', 'SessionOptions', 'SessionPage', 'WebPage', '__version__'] -__version__ = '4.0.0b8' +__version__ = '4.0.0b9' diff --git a/DrissionPage/_commons/browser.py b/DrissionPage/_commons/browser.py index c0a5e80..8e3d6aa 100644 --- a/DrissionPage/_commons/browser.py +++ b/DrissionPage/_commons/browser.py @@ -37,6 +37,7 @@ def connect_browser(option): # ----------创建浏览器进程---------- args = get_launch_args(option) set_prefs(option) + set_flags(option) try: _run_browser(port, chrome_path, args) @@ -89,6 +90,7 @@ def get_launch_args(opt): port = opt.debugger_address.split(':')[-1] if opt.debugger_address else '0' path = Path(gettempdir()) / 'DrissionPage' / f'userData_{port}' path.mkdir(parents=True, exist_ok=True) + opt.set_user_data_path(path) result.add(f'--user-data-dir={path}') if not remote_allow: @@ -119,15 +121,13 @@ def set_prefs(opt): :param opt: ChromiumOptions :return: None """ + if not opt.user_data_path or (not opt.preferences and not opt._prefs_to_del): + return prefs = opt.preferences del_list = opt._prefs_to_del - if not opt.user_data_path: - return - - args = opt.arguments user = 'Default' - for arg in args: + for arg in opt.arguments: if arg.startswith('--profile-directory'): user = arg.split('=')[-1].strip() break @@ -158,6 +158,42 @@ def set_prefs(opt): dump(prefs_dict, f) +def set_flags(opt): + """处理启动配置中的prefs项,目前只能对已存在文件夹配置 + :param opt: ChromiumOptions + :return: None + """ + if not opt.user_data_path or (not opt.clear_file_flags and not opt.flags): + return + + state_file = Path(opt.user_data_path) / 'Local State' + + if not state_file.exists(): + state_file.parent.mkdir(parents=True, exist_ok=True) + with open(state_file, 'w') as f: + f.write('{}') + + with open(state_file, "r", encoding='utf-8') as f: + try: + states_dict = load(f) + except JSONDecodeError: + states_dict = {} + flags_list = [] if opt.clear_file_flags else states_dict.setdefault( + 'browser', {}).setdefault('enabled_labs_experiments', []) + flags_dict = {} + for i in flags_list: + f = str(i).split('@', 1) + flags_dict[f[0]] = None if len(f) == 1 else f[1] + + for k, i in opt.flags.items(): + flags_dict[k] = i + + states_dict['browser']['enabled_labs_experiments'] = [f'{k}@{i}' if i else k for k, i in flags_dict.items()] + + with open(state_file, 'w', encoding='utf-8') as f: + dump(states_dict, f) + + def test_connect(ip, port, timeout=30): """测试浏览器是否可用 :param ip: 浏览器ip diff --git a/DrissionPage/_commons/browser.pyi b/DrissionPage/_commons/browser.pyi index 9e74e87..76a2008 100644 --- a/DrissionPage/_commons/browser.pyi +++ b/DrissionPage/_commons/browser.pyi @@ -17,4 +17,7 @@ def get_launch_args(opt: ChromiumOptions) -> list: ... def set_prefs(opt: ChromiumOptions) -> None: ... +def set_flags(opt: ChromiumOptions) -> None: ... + + def test_connect(ip: str, port: Union[int, str], timeout: float = 30) -> None: ... diff --git a/DrissionPage/_configs/chromium_options.py b/DrissionPage/_configs/chromium_options.py index cdcf8c8..5993f7b 100644 --- a/DrissionPage/_configs/chromium_options.py +++ b/DrissionPage/_configs/chromium_options.py @@ -21,6 +21,7 @@ class ChromiumOptions(object): self._user_data_path = None self._user = 'Default' self._prefs_to_del = [] + self.clear_file_flags = False self._headless = None if read_file is not False: @@ -34,6 +35,7 @@ class ChromiumOptions(object): self._browser_path = options.get('browser_path', '') self._extensions = options.get('extensions', []) self._prefs = options.get('prefs', {}) + self._flags = options.get('flags', {}) self._debugger_address = options.get('debugger_address', None) self._load_mode = options.get('load_mode', 'normal') self._proxy = om.proxies.get('http', None) @@ -69,6 +71,7 @@ class ChromiumOptions(object): self._download_path = '' self._extensions = [] self._prefs = {} + self._flags = {} self._timeouts = {'implicit': 10, 'pageLoad': 30, 'script': 30} self._debugger_address = '127.0.0.1:9222' self._load_mode = 'normal' @@ -137,6 +140,11 @@ class ChromiumOptions(object): """返回用户首选项配置""" return self._prefs + @property + def flags(self): + """返回实验项配置""" + return self._flags + @property def system_user_path(self): """返回是否使用系统安装的浏览器所使用的用户数据文件夹""" @@ -221,6 +229,23 @@ class ChromiumOptions(object): self._prefs_to_del.append(arg) return self + def set_flag(self, flag, value=None): + """设置实验项 + :param flag: 设置项名称 + :param value: 设置项的值,为False则删除该项 + :return: 当前对象 + """ + if value is False: + self._flags.pop(flag, None) + else: + self._flags[flag] = value + return self + + def clear_flags_in_file(self): + """删除浏览器设置文件中已设置的实验项""" + self.clear_file_flags = True + return self + def set_timeouts(self, implicit=None, pageLoad=None, script=None): """设置超时时间,单位为秒 :param implicit: 默认超时时间 @@ -454,7 +479,7 @@ class ChromiumOptions(object): # 设置chrome_options attrs = ('debugger_address', 'browser_path', 'arguments', 'extensions', 'user', 'load_mode', - 'auto_port', 'system_user_path', 'existing_only') + 'auto_port', 'system_user_path', 'existing_only', 'flags') for i in attrs: om.set_item('chrome_options', i, self.__getattribute__(f'_{i}')) # 设置代理 diff --git a/DrissionPage/_configs/chromium_options.pyi b/DrissionPage/_configs/chromium_options.pyi index e42c6de..76f8624 100644 --- a/DrissionPage/_configs/chromium_options.pyi +++ b/DrissionPage/_configs/chromium_options.pyi @@ -22,7 +22,9 @@ class ChromiumOptions(object): self._debugger_address: str = ... self._extensions: list = ... self._prefs: dict = ... + self._flags: dict = ... self._prefs_to_del: list = ... + self.clear_file_flags: bool = ... self._auto_port: bool = ... self._system_user_path: bool = ... self._existing_only: bool = ... @@ -61,6 +63,9 @@ class ChromiumOptions(object): @property def preferences(self) -> dict: ... + @property + def flags(self) -> dict: ... + @property def system_user_path(self) -> bool: ... @@ -81,6 +86,10 @@ class ChromiumOptions(object): def remove_pref_from_file(self, arg: str) -> ChromiumOptions: ... + def set_flag(self, flag: str, value: Union[int, str, bool] = None) -> ChromiumOptions: ... + + def clear_flags_in_file(self) -> ChromiumOptions: ... + def set_timeouts(self, implicit: float = None, pageLoad: float = None, script: float = None) -> ChromiumOptions: ... diff --git a/DrissionPage/_configs/configs.ini b/DrissionPage/_configs/configs.ini index e6cb8f5..62e1746 100644 --- a/DrissionPage/_configs/configs.ini +++ b/DrissionPage/_configs/configs.ini @@ -7,6 +7,7 @@ browser_path = chrome arguments = ['--remote-allow-origins=*', '--no-first-run', '--disable-infobars', '--disable-popup-blocking'] extensions = [] prefs = {'profile.default_content_settings.popups': 0, 'profile.default_content_setting_values': {'notifications': 2}} +flags = {} load_mode = normal user = Default auto_port = False diff --git a/DrissionPage/_pages/chromium_base.py b/DrissionPage/_pages/chromium_base.py index 8d01ca5..a345f4f 100644 --- a/DrissionPage/_pages/chromium_base.py +++ b/DrissionPage/_pages/chromium_base.py @@ -10,7 +10,6 @@ from re import findall from threading import Thread from time import perf_counter, sleep -from .._units.rect import TabRect from .._base.base import BasePage from .._commons.constants import ERROR, NoneElement from .._commons.locator import get_loc @@ -20,6 +19,7 @@ from .._elements.chromium_element import ChromiumElement, run_js, make_chromium_ from .._elements.session_element import make_session_ele from .._units.action_chains import ActionChains from .._units.network_listener import NetworkListener +from .._units.rect import TabRect from .._units.screencast import Screencast from .._units.scroller import PageScroller from .._units.setter import ChromiumBaseSetter @@ -88,9 +88,20 @@ class ChromiumBase(BasePage): if not tab_id: tabs = self.browser.driver.get(f'http://{self.address}/json').json() tabs = [(i['id'], i['url']) for i in tabs if i['type'] == 'page' and not i['url'].startswith('devtools://')] - if tabs[0][1] == 'chrome://privacy-sandbox-dialog/notice' and len(tabs) > 1: - tab_id = tabs[1][0] - close_privacy_dialog(self, tabs[0][0]) + dialog = None + if len(tabs) > 1: + for k, t in enumerate(tabs): + if t[1] == 'chrome://privacy-sandbox-dialog/notice': + dialog = k + elif not tab_id: + tab_id = t[0] + + if tab_id and dialog is not None: + break + + if dialog is not None: + close_privacy_dialog(self, tabs[dialog][0]) + else: tab_id = tabs[0][0] diff --git a/setup.py b/setup.py index 77ed58a..ee2e434 100644 --- a/setup.py +++ b/setup.py @@ -6,7 +6,7 @@ with open("README.md", "r", encoding='utf-8') as fh: setup( name="DrissionPage", - version="4.0.0b8", + version="4.0.0b9", author="g1879", author_email="g1879@qq.com", description="Python based web automation tool. It can control the browser and send and receive data packets.",