From 8b7df4675b0f5e1fe77b96d83fc30aca5be3e08e Mon Sep 17 00:00:00 2001
From: g1879 <g1879@qq.com>
Date: Sun, 15 Jan 2023 23:11:28 +0800
Subject: [PATCH] =?UTF-8?q?=E9=85=8D=E7=BD=AE=E9=A1=B9=E8=83=BD=E5=AE=8C?=
 =?UTF-8?q?=E6=95=B4=E6=94=AF=E6=8C=81experimental=5Foptions=EF=BC=8C?=
 =?UTF-8?q?=E5=8C=85=E6=8B=AC=E6=96=B0=E5=BB=BA=E7=9A=84=E7=A9=BA=E6=96=87?=
 =?UTF-8?q?=E4=BB=B6=E5=A4=B9=EF=BC=9B=E6=94=B9=E8=BF=9BOptionManager?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 DrissionPage/chromium_driver.py  | 10 +++---
 DrissionPage/chromium_element.py |  2 +-
 DrissionPage/common.py           | 28 ++++++++++-----
 DrissionPage/config.py           | 62 ++++----------------------------
 DrissionPage/config.pyi          | 62 ++++----------------------------
 5 files changed, 40 insertions(+), 124 deletions(-)

diff --git a/DrissionPage/chromium_driver.py b/DrissionPage/chromium_driver.py
index bf86780..d40f4cf 100644
--- a/DrissionPage/chromium_driver.py
+++ b/DrissionPage/chromium_driver.py
@@ -22,7 +22,7 @@ class GenericAttr(object):
         self.__dict__['tab'] = tab
 
     def __getattr__(self, item):
-        method_name = "%s.%s" % (self.name, item)
+        method_name = f"{self.name}.{item}"
         event_listener = self.tab.get_listener(method_name)
 
         if event_listener:
@@ -31,7 +31,7 @@ class GenericAttr(object):
         return partial(self.tab.call_method, method_name)
 
     def __setattr__(self, key, value):
-        self.tab.set_listener("%s.%s" % (self.name, key), value)
+        self.tab.set_listener(f"{self.name}.{key}", value)
 
 
 class ChromiumDriver(object):
@@ -73,7 +73,7 @@ class ChromiumDriver(object):
         message_json = dumps(message)
 
         if self.debug:  # pragma: no cover
-            print("SEND > %s" % message_json)
+            print(f"SEND > {message_json}")
 
         if not isinstance(timeout, (int, float)) or timeout > 1:
             q_timeout = 1
@@ -122,7 +122,7 @@ class ChromiumDriver(object):
                 return
 
             if self.debug:  # pragma: no cover
-                print('< RECV %s' % message_json)
+                print(f'< RECV {message_json}')
 
             if "method" in message:
                 self.event_queue.put(message)
@@ -144,7 +144,7 @@ class ChromiumDriver(object):
                 try:
                     self.event_handlers[event['method']](**event['params'])
                 except Exception as e:
-                    logger.error("callback %s exception" % event['method'], exc_info=True)
+                    logger.error(f"callback {event['method']} exception", exc_info=True)
 
             self.event_queue.task_done()
 
diff --git a/DrissionPage/chromium_element.py b/DrissionPage/chromium_element.py
index f0ed2fa..bd67512 100644
--- a/DrissionPage/chromium_element.py
+++ b/DrissionPage/chromium_element.py
@@ -157,7 +157,7 @@ class ChromiumElement(DrissionElement):
     def _client_click_point(self):
         """返回元素左上角可接受点击的点视口坐标"""
         m = self._get_client_rect('padding')
-        return (int(self.client_midpoint[0]), int(m[1])) if m else (0, 0)
+        return (int(self.client_midpoint[0]), int(m[1]) + 1) if m else (0, 0)
 
     @property
     def _click_point(self):
diff --git a/DrissionPage/common.py b/DrissionPage/common.py
index 30843f6..76c1d0c 100644
--- a/DrissionPage/common.py
+++ b/DrissionPage/common.py
@@ -524,7 +524,8 @@ def connect_browser(option):
         chrome_path = get_exe_from_port(port) if chrome_path == 'chrome' and system_type == 'windows' else chrome_path
         return chrome_path, None
 
-    args = _get_running_args(option)
+    args = _get_launch_args(option)
+    _set_prefs(option)
 
     # ----------创建浏览器进程----------
     try:
@@ -573,7 +574,7 @@ def _run_browser(port, path: str, args) -> Popen:
     raise ConnectionError('无法连接浏览器。')
 
 
-def _get_running_args(opt: DriverOptions) -> list:
+def _get_launch_args(opt: DriverOptions) -> list:
     """从DriverOptions获取命令行启动参数"""
     sys = system().lower()
     result = []
@@ -587,7 +588,7 @@ def _get_running_args(opt: DriverOptions) -> list:
         else:
             result.append(arg)
 
-    # ----------处理extensions-------------
+    # ----------处理插件extensions-------------
     ext = opt._extension_files
     if ext:
         ext = set(ext)
@@ -599,12 +600,25 @@ def _get_running_args(opt: DriverOptions) -> list:
         ext = f'--load-extension={ext}'
         result.append(ext)
 
-    # ----------处理experimental_options-------------
+    return result
+
+
+def _set_prefs(opt: DriverOptions) -> None:
+    """处理启动配置中的prefs项,目前只能对已存在文件夹配置"""
     prefs = opt.experimental_options.get('prefs', None)
     if prefs and opt.user_data_path:
-        prefs_file = Path(opt.user_data_path) / 'Default' / 'Preferences'
+        args = opt.arguments
+        profile = 'Default'
+        for arg in args:
+            if arg.startswith('--profile-directory'):
+                profile = arg.split('=')[-1].strip()
+                break
+
+        prefs_file = Path(opt.user_data_path) / profile / 'Preferences'
         if not prefs_file.exists():
-            return result
+            prefs_file.parent.mkdir(parents=True, exist_ok=True)
+            with open(prefs_file, 'w') as f:
+                f.write('{}')
 
         from json import load, dump
         with open(prefs_file, "r", encoding='utf-8') as f:
@@ -619,8 +633,6 @@ def _get_running_args(opt: DriverOptions) -> list:
         with open(prefs_file, 'w', encoding='utf-8') as f:
             dump(j, f)
 
-    return result
-
 
 def _make_leave_in_dict(target_dict: dict, src: list, num: int, end: int) -> None:
     """把prefs中a.b.c形式的属性转为a['b']['c']形式
diff --git a/DrissionPage/config.py b/DrissionPage/config.py
index bcad2ab..f75ed0a 100644
--- a/DrissionPage/config.py
+++ b/DrissionPage/config.py
@@ -22,41 +22,14 @@ class OptionsManager(object):
         if not Path(self.ini_path).exists():
             raise FileNotFoundError('ini文件不存在。')
         self._conf = RawConfigParser()
-        self._conf.read(self.ini_path, encoding='utf-8-sig')
+        self._conf.read(self.ini_path, encoding='utf-8')
 
-        self._paths = None
-        self._chrome_options = None
-        self._session_options = None
-
-    def __text__(self):
-        """打印ini文件内容"""
-        return (f"paths:\n"
-                f"{self.get_option('paths')}\n\n"
-                "chrome options:\n"
-                f"{self.get_option('chrome_options')}\n\n"
-                "session options:\n"
-                f"{self.get_option('session_options')}")
-
-    @property
-    def paths(self):
-        """返回paths设置"""
-        if self._paths is None:
-            self._paths = self.get_option('paths')
-        return self._paths
-
-    @property
-    def chrome_options(self):
-        """返回chrome设置"""
-        if self._chrome_options is None:
-            self._chrome_options = self.get_option('chrome_options')
-        return self._chrome_options
-
-    @property
-    def session_options(self):
-        """返回session设置"""
-        if self._session_options is None:
-            self._session_options = self.get_option('session_options')
-        return self._session_options
+    def __getattr__(self, item):
+        """以dict形似返回获取大项信息
+        :param item: 项名
+        :return: None
+        """
+        return self.get_option(item)
 
     def get_value(self, section, item):
         """获取配置的值         \n
@@ -276,19 +249,6 @@ class SessionOptions(object):
         """返回max_redirects设置信息"""
         return self._max_redirects
 
-    @timeout.setter
-    def timeout(self, second):
-        """返回timeout属性信息"""
-        self._timeout = second
-
-    @headers.setter
-    def headers(self, headers):
-        """设置headers参数           \n
-        :param headers: 参数值
-        :return: None
-        """
-        self.set_headers(headers)
-
     @cookies.setter
     def cookies(self, cookies):
         """设置cookies参数           \n
@@ -305,14 +265,6 @@ class SessionOptions(object):
         """
         self._auth = auth
 
-    @proxies.setter
-    def proxies(self, proxies):
-        """设置proxies参数           \n
-        :param proxies: 参数值
-        :return: None
-        """
-        self.set_proxies(proxies)
-
     @hooks.setter
     def hooks(self, hooks):
         """设置hooks参数           \n
diff --git a/DrissionPage/config.pyi b/DrissionPage/config.pyi
index bb5ec09..253705e 100644
--- a/DrissionPage/config.pyi
+++ b/DrissionPage/config.pyi
@@ -13,24 +13,15 @@ from selenium.webdriver.chrome.options import Options
 
 
 class OptionsManager(object):
+    ini_path: str = ...
+    _conf: RawConfigParser = ...
+    paths: dict = ...
+    chrome_options: dict = ...
+    session_options: dict = ...
 
-    def __init__(self, path: str = None):
-        self.ini_path: str = ...
-        self._conf: RawConfigParser = ...
-        self._paths: dict = ...
-        self._chrome_options: dict = ...
-        self._session_options: dict = ...
+    def __init__(self, path: str = None): ...
 
-    def __text__(self) -> str: ...
-
-    @property
-    def paths(self) -> dict: ...
-
-    @property
-    def chrome_options(self) -> dict: ...
-
-    @property
-    def session_options(self) -> dict: ...
+    def __getattr__(self, item) -> dict: ...
 
     def get_value(self, section: str, item: str) -> Any: ...
 
@@ -103,45 +94,6 @@ class SessionOptions(object):
     @property
     def max_redirects(self) -> int: ...
 
-    @timeout.setter
-    def timeout(self, second: Union[int, float]) -> None: ...
-
-    @headers.setter
-    def headers(self, headers: dict) -> None: ...
-
-    @cookies.setter
-    def cookies(self, cookies: Union[RequestsCookieJar, list, tuple, str, dict]) -> None: ...
-
-    @auth.setter
-    def auth(self, auth: tuple) -> None: ...
-
-    @proxies.setter
-    def proxies(self, proxies: dict) -> None: ...
-
-    @hooks.setter
-    def hooks(self, hooks: dict) -> None: ...
-
-    @params.setter
-    def params(self, params: dict) -> None: ...
-
-    @verify.setter
-    def verify(self, verify: bool) -> None: ...
-
-    @cert.setter
-    def cert(self, cert: Union[str, tuple]) -> None: ...
-
-    @adapters.setter
-    def adapters(self, adapters) -> None: ...
-
-    @stream.setter
-    def stream(self, stream: bool) -> None: ...
-
-    @trust_env.setter
-    def trust_env(self, trust_env: bool) -> None: ...
-
-    @max_redirects.setter
-    def max_redirects(self, max_redirects: int) -> None: ...
-
     def set_timeout(self, second: Union[int, float]) -> SessionOptions: ...
 
     def set_headers(self, headers: dict) -> SessionOptions: ...