修复driver与浏览器连接没有关闭问题

This commit is contained in:
g1879 2023-02-14 23:48:57 +08:00
parent ec4edf868b
commit b5a86326c5
6 changed files with 40 additions and 25 deletions

View File

@ -15,7 +15,7 @@ from .chromium_driver import ChromiumDriver
from .chromium_element import ChromiumWaiter, ChromiumScroll, ChromiumElement, run_js, make_chromium_ele, \ from .chromium_element import ChromiumWaiter, ChromiumScroll, ChromiumElement, run_js, make_chromium_ele, \
ChromiumElementWaiter ChromiumElementWaiter
from .functions.constants import HANDLE_ALERT_METHOD 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.locator import get_loc
from .functions.tools import get_usable_path from .functions.tools import get_usable_path
from .functions.web import offset_scroll, cookies_to_tuple from .functions.web import offset_scroll, cookies_to_tuple
@ -337,14 +337,16 @@ class ChromiumBase(BasePage):
if 'error' not in r: if 'error' not in r:
return r return r
if 'Cannot find context with specified id' in r['error']: if r['error'] == 'Cannot find context with specified id':
raise ContextLossError('页面被刷新,请操作前尝试等待页面刷新或加载完成。') 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('该元素已不在当前页面中。') raise ElementLossError('该元素已不在当前页面中。')
elif 'tab closed' in r['error']: elif r['error'] == 'tab closed':
raise RuntimeError('标签页已关闭。') raise RuntimeError('标签页已关闭。')
elif 'alert exists' in r['error']: elif r['error'] == 'alert exists':
pass pass
elif r['type'] == 'call_method_error':
raise CallMethodException(f'\n错误:{r["error"]}\nmethod{r["method"]}\nargs{r["args"]}')
else: else:
raise RuntimeError(r) raise RuntimeError(r)
@ -919,11 +921,10 @@ class ChromiumPageScroll(ChromiumScroll):
:return: None :return: None
""" """
ele = self._driver.ele(loc_or_ele) ele = self._driver.ele(loc_or_ele)
node_id = ele.node_id
try: try:
self._driver.run_cdp_loaded('DOM.scrollIntoViewIfNeeded', nodeId=node_id) self._driver.run_cdp('DOM.scrollIntoViewIfNeeded', nodeId=ele.node_id)
except Exception: except Exception:
ele.run_js_loaded("this.scrollIntoView();") ele.run_js("this.scrollIntoView();")
if not ele.is_in_viewport: if not ele.is_in_viewport:
offset_scroll(ele, 0, 0) offset_scroll(ele, 0, 0)

View File

@ -11,6 +11,8 @@ from threading import Thread, Event
from websocket import WebSocketTimeoutException, WebSocketException, WebSocketConnectionClosedException, \ from websocket import WebSocketTimeoutException, WebSocketException, WebSocketConnectionClosedException, \
create_connection create_connection
from .functions.errors import CallMethodException
class GenericAttr(object): class GenericAttr(object):
def __init__(self, name, tab): def __init__(self, name, tab):
@ -52,8 +54,8 @@ class ChromiumDriver(object):
self._ws = None self._ws = None
self._recv_th = Thread(target=self._recv_loop) self._recv_th = Thread(target=self._recv_loop)
self._recv_th.daemon = True
self._handle_event_th = Thread(target=self._handle_event_loop) self._handle_event_th = Thread(target=self._handle_event_loop)
self._recv_th.daemon = True
self._handle_event_th.daemon = True self._handle_event_th.daemon = True
self._stopped = Event() self._stopped = Event()
@ -120,7 +122,7 @@ class ChromiumDriver(object):
continue continue
except (WebSocketException, OSError, WebSocketConnectionClosedException): except (WebSocketException, OSError, WebSocketConnectionClosedException):
if not self._stopped.is_set(): if not self._stopped.is_set():
self._stopped.set() self.stop()
return return
if self.debug: if self.debug:
@ -212,9 +214,10 @@ class ChromiumDriver(object):
self._stopped.set() self._stopped.set()
if self._ws: if self._ws:
self._ws.close() self._ws.close()
self.event_handlers = {} self._ws = None
self.method_results = {} self.event_handlers = None
self.event_queue = Queue() self.method_results = None
self.event_queue = None
return True return True
def set_listener(self, event, callback): def set_listener(self, event, callback):
@ -242,7 +245,3 @@ class ChromiumDriver(object):
return f"<ChromiumDriver {self.id}>" return f"<ChromiumDriver {self.id}>"
__repr__ = __str__ __repr__ = __str__
class CallMethodException(Exception):
pass

View File

@ -33,9 +33,9 @@ class ChromiumDriver(object):
_stopped: Event _stopped: Event
_started: bool _started: bool
status: str status: str
event_handlers: dict event_handlers: Union[dict, None]
method_results: dict method_results: Union[dict, None]
event_queue: Queue event_queue: Union[Queue, None]
def __init__(self, tab_id: str, tab_type: str, address: str): ... 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 get_listener(self, event: str) -> Union[Callable, None]: ...
def __str__(self) -> str: ... def __str__(self) -> str: ...
class CallMethodException(Exception): ...

View File

@ -11,7 +11,7 @@ from warnings import warn
from .base import DrissionElement, BaseElement from .base import DrissionElement, BaseElement
from .functions.constants import FRAME_ELEMENT 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.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 .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 from .keys import _keys_to_typing, _keyDescriptionForString, _keyDefinitions
@ -826,7 +826,7 @@ class ChromiumElement(DrissionElement):
""" """
try: try:
return self.page.run_cdp('DOM.getBoxModel', nodeId=self.node_id)['model'][quad] return self.page.run_cdp('DOM.getBoxModel', nodeId=self.node_id)['model'][quad]
except Exception: except CallMethodException:
return None return None
def _get_absolute_rect(self, x, y): def _get_absolute_rect(self, x, y):

View File

@ -471,6 +471,20 @@ class ChromiumFrameScroll(ChromiumPageScroll):
self._driver = frame.doc_ele self._driver = frame.doc_ele
self.t1 = self.t2 = 'this.documentElement' 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): class ChromiumFrameSetter(ChromiumBaseSetter):
def attr(self, attr, value): def attr(self, attr, value):

View File

@ -9,3 +9,7 @@ class ContextLossError(Exception):
class ElementLossError(Exception): class ElementLossError(Exception):
pass pass
class CallMethodException(Exception):
pass