From b5a86326c5399c65f068bff3b64a9541bc8fec58 Mon Sep 17 00:00:00 2001
From: g1879 <g1879@qq.com>
Date: Tue, 14 Feb 2023 23:48:57 +0800
Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8Ddriver=E4=B8=8E=E6=B5=8F?=
 =?UTF-8?q?=E8=A7=88=E5=99=A8=E8=BF=9E=E6=8E=A5=E6=B2=A1=E6=9C=89=E5=85=B3?=
 =?UTF-8?q?=E9=97=AD=E9=97=AE=E9=A2=98?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 DrissionPage/chromium_base.py    | 17 +++++++++--------
 DrissionPage/chromium_driver.py  | 17 ++++++++---------
 DrissionPage/chromium_driver.pyi |  9 +++------
 DrissionPage/chromium_element.py |  4 ++--
 DrissionPage/chromium_frame.py   | 14 ++++++++++++++
 DrissionPage/functions/errors.py |  4 ++++
 6 files changed, 40 insertions(+), 25 deletions(-)

diff --git a/DrissionPage/chromium_base.py b/DrissionPage/chromium_base.py
index 9badf6b..f4c3c1f 100644
--- a/DrissionPage/chromium_base.py
+++ b/DrissionPage/chromium_base.py
@@ -15,7 +15,7 @@ from .chromium_driver import ChromiumDriver
 from .chromium_element import ChromiumWaiter, ChromiumScroll, ChromiumElement, run_js, make_chromium_ele, \
     ChromiumElementWaiter
 from .functions.constants import HANDLE_ALERT_METHOD
-from .functions.errors import ContextLossError, ElementLossError, AlertExistsError
+from .functions.errors import ContextLossError, ElementLossError, AlertExistsError, CallMethodException
 from .functions.locator import get_loc
 from .functions.tools import get_usable_path
 from .functions.web import offset_scroll, cookies_to_tuple
@@ -337,14 +337,16 @@ class ChromiumBase(BasePage):
         if 'error' not in r:
             return r
 
-        if 'Cannot find context with specified id' in r['error']:
+        if r['error'] == 'Cannot find context with specified id':
             raise ContextLossError('页面被刷新,请操作前尝试等待页面刷新或加载完成。')
-        elif 'Could not find node with given id' in r['error']:
+        elif r['error'] in ('Could not find node with given id', 'Could not find object with given id'):
             raise ElementLossError('该元素已不在当前页面中。')
-        elif 'tab closed' in r['error']:
+        elif r['error'] == 'tab closed':
             raise RuntimeError('标签页已关闭。')
-        elif 'alert exists' in r['error']:
+        elif r['error'] == 'alert exists':
             pass
+        elif r['type'] == 'call_method_error':
+            raise CallMethodException(f'\n错误:{r["error"]}\nmethod:{r["method"]}\nargs:{r["args"]}')
         else:
             raise RuntimeError(r)
 
@@ -919,11 +921,10 @@ class ChromiumPageScroll(ChromiumScroll):
         :return: None
         """
         ele = self._driver.ele(loc_or_ele)
-        node_id = ele.node_id
         try:
-            self._driver.run_cdp_loaded('DOM.scrollIntoViewIfNeeded', nodeId=node_id)
+            self._driver.run_cdp('DOM.scrollIntoViewIfNeeded', nodeId=ele.node_id)
         except Exception:
-            ele.run_js_loaded("this.scrollIntoView();")
+            ele.run_js("this.scrollIntoView();")
 
         if not ele.is_in_viewport:
             offset_scroll(ele, 0, 0)
diff --git a/DrissionPage/chromium_driver.py b/DrissionPage/chromium_driver.py
index 72020db..33d138d 100644
--- a/DrissionPage/chromium_driver.py
+++ b/DrissionPage/chromium_driver.py
@@ -11,6 +11,8 @@ from threading import Thread, Event
 from websocket import WebSocketTimeoutException, WebSocketException, WebSocketConnectionClosedException, \
     create_connection
 
+from .functions.errors import CallMethodException
+
 
 class GenericAttr(object):
     def __init__(self, name, tab):
@@ -52,8 +54,8 @@ class ChromiumDriver(object):
         self._ws = None
 
         self._recv_th = Thread(target=self._recv_loop)
-        self._recv_th.daemon = True
         self._handle_event_th = Thread(target=self._handle_event_loop)
+        self._recv_th.daemon = True
         self._handle_event_th.daemon = True
 
         self._stopped = Event()
@@ -120,7 +122,7 @@ class ChromiumDriver(object):
                 continue
             except (WebSocketException, OSError, WebSocketConnectionClosedException):
                 if not self._stopped.is_set():
-                    self._stopped.set()
+                    self.stop()
                 return
 
             if self.debug:
@@ -212,9 +214,10 @@ class ChromiumDriver(object):
         self._stopped.set()
         if self._ws:
             self._ws.close()
-        self.event_handlers = {}
-        self.method_results = {}
-        self.event_queue = Queue()
+            self._ws = None
+        self.event_handlers = None
+        self.method_results = None
+        self.event_queue = None
         return True
 
     def set_listener(self, event, callback):
@@ -242,7 +245,3 @@ class ChromiumDriver(object):
         return f"<ChromiumDriver {self.id}>"
 
     __repr__ = __str__
-
-
-class CallMethodException(Exception):
-    pass
diff --git a/DrissionPage/chromium_driver.pyi b/DrissionPage/chromium_driver.pyi
index 4b1179c..ac73ece 100644
--- a/DrissionPage/chromium_driver.pyi
+++ b/DrissionPage/chromium_driver.pyi
@@ -33,9 +33,9 @@ class ChromiumDriver(object):
     _stopped: Event
     _started: bool
     status: str
-    event_handlers: dict
-    method_results: dict
-    event_queue: Queue
+    event_handlers: Union[dict, None]
+    method_results: Union[dict, None]
+    event_queue: Union[Queue, None]
 
     def __init__(self, tab_id: str, tab_type: str, address: str): ...
 
@@ -58,6 +58,3 @@ class ChromiumDriver(object):
     def get_listener(self, event: str) -> Union[Callable, None]: ...
 
     def __str__(self) -> str: ...
-
-
-class CallMethodException(Exception): ...
diff --git a/DrissionPage/chromium_element.py b/DrissionPage/chromium_element.py
index 089df08..85ca3f5 100644
--- a/DrissionPage/chromium_element.py
+++ b/DrissionPage/chromium_element.py
@@ -11,7 +11,7 @@ from warnings import warn
 
 from .base import DrissionElement, BaseElement
 from .functions.constants import FRAME_ELEMENT
-from .functions.errors import ContextLossError, ElementLossError
+from .functions.errors import ContextLossError, ElementLossError, CallMethodException
 from .functions.locator import get_loc
 from .functions.web import make_absolute_link, get_ele_txt, format_html, is_js_func, location_in_viewport, offset_scroll
 from .keys import _keys_to_typing, _keyDescriptionForString, _keyDefinitions
@@ -826,7 +826,7 @@ class ChromiumElement(DrissionElement):
         """
         try:
             return self.page.run_cdp('DOM.getBoxModel', nodeId=self.node_id)['model'][quad]
-        except Exception:
+        except CallMethodException:
             return None
 
     def _get_absolute_rect(self, x, y):
diff --git a/DrissionPage/chromium_frame.py b/DrissionPage/chromium_frame.py
index 3a3d6da..92f1207 100644
--- a/DrissionPage/chromium_frame.py
+++ b/DrissionPage/chromium_frame.py
@@ -471,6 +471,20 @@ class ChromiumFrameScroll(ChromiumPageScroll):
         self._driver = frame.doc_ele
         self.t1 = self.t2 = 'this.documentElement'
 
+    def to_see(self, loc_or_ele):
+        """滚动页面直到元素可见
+        :param loc_or_ele: 元素的定位信息,可以是loc元组,或查询字符串
+        :return: None
+        """
+        ele = loc_or_ele if isinstance(loc_or_ele, ChromiumElement) else self._driver.ele(loc_or_ele)
+        try:
+            self._driver.page.run_cdp('DOM.scrollIntoViewIfNeeded', nodeId=ele.node_id)
+        except Exception:
+            ele.run_js("this.scrollIntoView();")
+
+        # if not ele.is_in_viewport:
+        #     offset_scroll(ele, 0, 0)
+
 
 class ChromiumFrameSetter(ChromiumBaseSetter):
     def attr(self, attr, value):
diff --git a/DrissionPage/functions/errors.py b/DrissionPage/functions/errors.py
index 8bd005b..23afe18 100644
--- a/DrissionPage/functions/errors.py
+++ b/DrissionPage/functions/errors.py
@@ -9,3 +9,7 @@ class ContextLossError(Exception):
 
 class ElementLossError(Exception):
     pass
+
+
+class CallMethodException(Exception):
+    pass