4.1.0.0b5wait()返回调用者

This commit is contained in:
g1879 2024-07-13 10:22:08 +08:00
parent d2bf4f8f13
commit daf435cc9a
4 changed files with 104 additions and 78 deletions

View File

@ -34,6 +34,7 @@ __ERROR__ = 'error'
class Chromium(object): class Chromium(object):
_BROWSERS = {} _BROWSERS = {}
_lock = Lock()
def __new__(cls, addr_or_opts=None, session_options=None): def __new__(cls, addr_or_opts=None, session_options=None):
""" """
@ -42,8 +43,12 @@ class Chromium(object):
""" """
opt = handle_options(addr_or_opts) opt = handle_options(addr_or_opts)
is_headless, browser_id, is_exists = run_browser(opt) is_headless, browser_id, is_exists = run_browser(opt)
if browser_id in cls._BROWSERS: with cls._lock:
return cls._BROWSERS[browser_id] if browser_id in cls._BROWSERS:
r = cls._BROWSERS[browser_id]
while not hasattr(r, '_driver'):
sleep(.1)
return r
r = object.__new__(cls) r = object.__new__(cls)
r._chromium_options = opt r._chromium_options = opt
r.is_headless = is_headless r.is_headless = is_headless
@ -62,11 +67,9 @@ class Chromium(object):
self._created = True self._created = True
self._type = 'Chromium' self._type = 'Chromium'
self._frames = {} self._frames = {}
self._drivers = {} self._drivers = {}
self._all_drivers = {} self._all_drivers = {}
self._lock = Lock()
self._set = None self._set = None
self._wait = None self._wait = None

View File

@ -193,7 +193,7 @@ class ChromiumElement(DrissionElement):
def wait(self): def wait(self):
"""返回用于等待的对象""" """返回用于等待的对象"""
if self._wait is None: if self._wait is None:
self._wait = ElementWaiter(self.owner, self) self._wait = ElementWaiter(self)
return self._wait return self._wait
@property @property
@ -1674,6 +1674,9 @@ def parse_js_result(page, ele, result, end_time):
elif the_type == 'undefined': elif the_type == 'undefined':
return None return None
elif the_type == 'function':
return result['description']
else: else:
return result['value'] return result['value']

View File

@ -13,6 +13,9 @@ from ..errors import WaitTimeoutError, NoRectError
class OriginWaiter(object): class OriginWaiter(object):
def __init__(self, owner):
self._owner = owner
def __call__(self, second, scope=None): def __call__(self, second, scope=None):
"""等待若干秒,如传入两个参数,等待时间为这两个数间的一个随机数 """等待若干秒,如传入两个参数,等待时间为这两个数间的一个随机数
:param second: 秒数 :param second: 秒数
@ -24,11 +27,10 @@ class OriginWaiter(object):
else: else:
from random import uniform from random import uniform
sleep(uniform(second, scope)) sleep(uniform(second, scope))
return self._owner
class BrowserWaiter(OriginWaiter): class BrowserWaiter(OriginWaiter):
def __init__(self, owner):
self._owner = owner
def new_tab(self, timeout=None, curr_tab=None, raise_err=None): def new_tab(self, timeout=None, curr_tab=None, raise_err=None):
"""等待新标签页出现 """等待新标签页出现
@ -105,11 +107,6 @@ class BrowserWaiter(OriginWaiter):
class BaseWaiter(OriginWaiter): class BaseWaiter(OriginWaiter):
def __init__(self, page_or_ele):
"""
:param page_or_ele: 页面对象或元素对象
"""
self._driver = page_or_ele
def ele_deleted(self, loc_or_ele, timeout=None, raise_err=None): def ele_deleted(self, loc_or_ele, timeout=None, raise_err=None):
"""等待元素从DOM中删除 """等待元素从DOM中删除
@ -118,7 +115,7 @@ class BaseWaiter(OriginWaiter):
:param raise_err: 等待失败时是否报错为None时根据Settings设置 :param raise_err: 等待失败时是否报错为None时根据Settings设置
:return: 是否等待成功 :return: 是否等待成功
""" """
ele = self._driver._ele(loc_or_ele, raise_err=False, timeout=0) ele = self._owner._ele(loc_or_ele, raise_err=False, timeout=0)
return ele.wait.deleted(timeout, raise_err=raise_err) if ele else True return ele.wait.deleted(timeout, raise_err=raise_err) if ele else True
def ele_displayed(self, loc_or_ele, timeout=None, raise_err=None): def ele_displayed(self, loc_or_ele, timeout=None, raise_err=None):
@ -129,9 +126,9 @@ class BaseWaiter(OriginWaiter):
:return: 是否等待成功 :return: 是否等待成功
""" """
if timeout is None: if timeout is None:
timeout = self._driver.timeout timeout = self._owner.timeout
end_time = perf_counter() + timeout end_time = perf_counter() + timeout
ele = self._driver._ele(loc_or_ele, raise_err=False, timeout=timeout) ele = self._owner._ele(loc_or_ele, raise_err=False, timeout=timeout)
timeout = end_time - perf_counter() timeout = end_time - perf_counter()
if timeout <= 0: if timeout <= 0:
if raise_err is True or Settings.raise_when_wait_failed is True: if raise_err is True or Settings.raise_when_wait_failed is True:
@ -148,9 +145,9 @@ class BaseWaiter(OriginWaiter):
:return: 是否等待成功 :return: 是否等待成功
""" """
if timeout is None: if timeout is None:
timeout = self._driver.timeout timeout = self._owner.timeout
end_time = perf_counter() + timeout end_time = perf_counter() + timeout
ele = self._driver._ele(loc_or_ele, raise_err=False, timeout=timeout) ele = self._owner._ele(loc_or_ele, raise_err=False, timeout=timeout)
timeout = end_time - perf_counter() timeout = end_time - perf_counter()
if timeout <= 0: if timeout <= 0:
if raise_err is True or Settings.raise_when_wait_failed is True: if raise_err is True or Settings.raise_when_wait_failed is True:
@ -199,10 +196,10 @@ class BaseWaiter(OriginWaiter):
else [get_loc(l)[1] for l in locators]) else [get_loc(l)[1] for l in locators])
method = any if any_one else all method = any if any_one else all
timeout = self._driver.timeout if timeout is None else timeout timeout = self._owner.timeout if timeout is None else timeout
end_time = perf_counter() + timeout end_time = perf_counter() + timeout
while perf_counter() < end_time: while perf_counter() < end_time:
if method([_find(l, self._driver.driver) for l in locators]): if method([_find(l, self._owner.driver) for l in locators]):
return True return True
sleep(.01) sleep(.01)
if raise_err is True or Settings.raise_when_wait_failed is True: if raise_err is True or Settings.raise_when_wait_failed is True:
@ -228,9 +225,9 @@ class BaseWaiter(OriginWaiter):
def upload_paths_inputted(self): def upload_paths_inputted(self):
"""等待自动填写上传文件路径""" """等待自动填写上传文件路径"""
end_time = perf_counter() + self._driver.timeout end_time = perf_counter() + self._owner.timeout
while perf_counter() < end_time: while perf_counter() < end_time:
if not self._driver._upload_list: if not self._owner._upload_list:
return True return True
sleep(.01) sleep(.01)
return False return False
@ -241,22 +238,22 @@ class BaseWaiter(OriginWaiter):
:param cancel_it: 是否取消该任务 :param cancel_it: 是否取消该任务
:return: 成功返回任务对象失败返回False :return: 成功返回任务对象失败返回False
""" """
if not self._driver.browser._dl_mgr._running: if not self._owner.browser._dl_mgr._running:
raise RuntimeError('此功能需显式设置下载路径使用set.download_path()方法、配置对象或ini文件均可') raise RuntimeError('此功能需显式设置下载路径使用set.download_path()方法、配置对象或ini文件均可')
self._driver.browser._dl_mgr.set_flag(self._driver.tab_id, False if cancel_it else True) self._owner.browser._dl_mgr.set_flag(self._owner.tab_id, False if cancel_it else True)
if timeout is None: if timeout is None:
timeout = self._driver.timeout timeout = self._owner.timeout
r = False r = False
end_time = perf_counter() + timeout end_time = perf_counter() + timeout
while perf_counter() < end_time: while perf_counter() < end_time:
v = self._driver.browser._dl_mgr.get_flag(self._driver.tab_id) v = self._owner.browser._dl_mgr.get_flag(self._owner.tab_id)
if not isinstance(v, bool): if not isinstance(v, bool):
r = v r = v
break break
sleep(.005) sleep(.005)
self._driver.browser._dl_mgr.set_flag(self._driver.tab_id, None) self._owner.browser._dl_mgr.set_flag(self._owner.tab_id, None)
return r return r
def url_change(self, text, exclude=False, timeout=None, raise_err=None): def url_change(self, text, exclude=False, timeout=None, raise_err=None):
@ -289,14 +286,14 @@ class BaseWaiter(OriginWaiter):
:return: 是否等待成功 :return: 是否等待成功
""" """
if timeout is None: if timeout is None:
timeout = self._driver.timeout timeout = self._owner.timeout
end_time = perf_counter() + timeout end_time = perf_counter() + timeout
while perf_counter() < end_time: while perf_counter() < end_time:
if arg == 'url': if arg == 'url':
val = self._driver.url val = self._owner.url
elif arg == 'title': elif arg == 'title':
val = self._driver.title val = self._owner.title
else: else:
raise ValueError raise ValueError
if (not exclude and text in val) or (exclude and text not in val): if (not exclude and text in val) or (exclude and text not in val):
@ -318,10 +315,10 @@ class BaseWaiter(OriginWaiter):
""" """
if timeout != 0: if timeout != 0:
if timeout is None or timeout is True: if timeout is None or timeout is True:
timeout = self._driver.timeout timeout = self._owner.timeout
end_time = perf_counter() + timeout end_time = perf_counter() + timeout
while perf_counter() < end_time: while perf_counter() < end_time:
if self._driver._is_loading == start: if self._owner._is_loading == start:
return True return True
sleep(gap) sleep(gap)
@ -340,23 +337,23 @@ class TabWaiter(BaseWaiter):
:param cancel_if_timeout: 超时时是否取消剩余任务 :param cancel_if_timeout: 超时时是否取消剩余任务
:return: 是否等待成功 :return: 是否等待成功
""" """
if not self._driver.browser._dl_mgr._running: if not self._owner.browser._dl_mgr._running:
raise RuntimeError('此功能需显式设置下载路径使用set.download_path()方法、配置对象或ini文件均可') raise RuntimeError('此功能需显式设置下载路径使用set.download_path()方法、配置对象或ini文件均可')
if not timeout: if not timeout:
while self._driver.browser._dl_mgr.get_tab_missions(self._driver.tab_id): while self._owner.browser._dl_mgr.get_tab_missions(self._owner.tab_id):
sleep(.5) sleep(.5)
return True return True
else: else:
end_time = perf_counter() + timeout end_time = perf_counter() + timeout
while perf_counter() < end_time: while perf_counter() < end_time:
if not self._driver.browser._dl_mgr.get_tab_missions(self._driver.tab_id): if not self._owner.browser._dl_mgr.get_tab_missions(self._owner.tab_id):
return True return True
sleep(.5) sleep(.5)
if self._driver.browser._dl_mgr.get_tab_missions(self._driver.tab_id): if self._owner.browser._dl_mgr.get_tab_missions(self._owner.tab_id):
if cancel_if_timeout: if cancel_if_timeout:
for m in self._driver.browser._dl_mgr.get_tab_missions(self._driver.tab_id): for m in self._owner.browser._dl_mgr.get_tab_missions(self._owner.tab_id):
m.cancel() m.cancel()
return False return False
else: else:
@ -364,25 +361,22 @@ class TabWaiter(BaseWaiter):
def alert_closed(self): def alert_closed(self):
"""等待弹出框关闭""" """等待弹出框关闭"""
while not self._driver.states.has_alert: while not self._owner.states.has_alert:
sleep(.2) sleep(.2)
while self._driver.states.has_alert: while self._owner.states.has_alert:
sleep(.2) sleep(.2)
class PageWaiter(TabWaiter): class PageWaiter(TabWaiter):
"""ChromiumPage和MixPage的等待对象""" """ChromiumPage和MixPage的等待对象"""
def __init__(self, page):
super().__init__(page)
def new_tab(self, timeout=None, raise_err=None): def new_tab(self, timeout=None, raise_err=None):
"""等待新标签页出现 """等待新标签页出现
:param timeout: 超时时间为None则使用页面对象timeout属性 :param timeout: 超时时间为None则使用页面对象timeout属性
:param raise_err: 等待失败时是否报错为None时根据Settings设置 :param raise_err: 等待失败时是否报错为None时根据Settings设置
:return: 等到新标签页返回其id否则返回False :return: 等到新标签页返回其id否则返回False
""" """
return self._driver.browser.wait.new_tab(timeout=timeout, raise_err=raise_err) return self._owner.browser.wait.new_tab(timeout=timeout, raise_err=raise_err)
def all_downloads_done(self, timeout=None, cancel_if_timeout=True): def all_downloads_done(self, timeout=None, cancel_if_timeout=True):
"""等待所有浏览器下载任务结束 """等待所有浏览器下载任务结束
@ -390,19 +384,16 @@ class PageWaiter(TabWaiter):
:param cancel_if_timeout: 超时时是否取消剩余任务 :param cancel_if_timeout: 超时时是否取消剩余任务
:return: 是否等待成功 :return: 是否等待成功
""" """
return self._driver.browser.wait.all_downloads_done(timeout=timeout, cancel_if_timeout=cancel_if_timeout) return self._owner.browser.wait.all_downloads_done(timeout=timeout, cancel_if_timeout=cancel_if_timeout)
class ElementWaiter(OriginWaiter): class ElementWaiter(OriginWaiter):
"""等待元素在dom中某种状态如删除、显示、隐藏""" """等待元素在dom中某种状态如删除、显示、隐藏"""
def __init__(self, owner, ele): @property
"""等待元素在dom中某种状态如删除、显示、隐藏 def _timeout(self):
:param owner: 元素所在页面 """返回超时设置"""
:param ele: 要执行等待的元素 return self._owner.owner.timeout
"""
self._owner = owner
self._ele = ele
def deleted(self, timeout=None, raise_err=None): def deleted(self, timeout=None, raise_err=None):
"""等待元素从dom删除 """等待元素从dom删除
@ -467,10 +458,10 @@ class ElementWaiter(OriginWaiter):
:return: 是否等待成功 :return: 是否等待成功
""" """
if timeout is None: if timeout is None:
timeout = self._owner.timeout timeout = self._timeout
end_time = perf_counter() + timeout end_time = perf_counter() + timeout
while perf_counter() < end_time: while perf_counter() < end_time:
if not self._ele.states.is_enabled or not self._ele.states.is_alive: if not self._owner.states.is_enabled or not self._owner.states.is_alive:
return True return True
sleep(.05) sleep(.05)
@ -487,12 +478,12 @@ class ElementWaiter(OriginWaiter):
:return: 是否等待成功 :return: 是否等待成功
""" """
if timeout is None: if timeout is None:
timeout = self._owner.timeout timeout = self._timeout
end_time = perf_counter() + timeout end_time = perf_counter() + timeout
while perf_counter() < end_time: while perf_counter() < end_time:
try: try:
size = self._ele.states.has_rect size = self._owner.states.has_rect
location = self._ele.rect.location location = self._owner.rect.location
break break
except NoRectError: except NoRectError:
pass pass
@ -502,10 +493,10 @@ class ElementWaiter(OriginWaiter):
while perf_counter() < end_time: while perf_counter() < end_time:
sleep(gap) sleep(gap)
if self._ele.rect.size == size and self._ele.rect.location == location: if self._owner.rect.size == size and self._owner.rect.location == location:
return True return True
size = self._ele.rect.size size = self._owner.rect.size
location = self._ele.rect.location location = self._owner.rect.location
if raise_err is True or Settings.raise_when_wait_failed is True: if raise_err is True or Settings.raise_when_wait_failed is True:
raise WaitTimeoutError(f'等待元素停止运动失败(等待{timeout}秒)。') raise WaitTimeoutError(f'等待元素停止运动失败(等待{timeout}秒)。')
@ -543,15 +534,15 @@ class ElementWaiter(OriginWaiter):
:param err_text: 抛出错误时显示的信息 :param err_text: 抛出错误时显示的信息
:return: 是否等待成功 :return: 是否等待成功
""" """
a = self._ele.states.__getattribute__(attr) a = self._owner.states.__getattribute__(attr)
if (a and mode) or (not a and not mode): if (a and mode) or (not a and not mode):
return True if isinstance(a, bool) else a return True if isinstance(a, bool) else a
if timeout is None: if timeout is None:
timeout = self._owner.timeout timeout = self._timeout
end_time = perf_counter() + timeout end_time = perf_counter() + timeout
while perf_counter() < end_time: while perf_counter() < end_time:
a = self._ele.states.__getattribute__(attr) a = self._owner.states.__getattribute__(attr)
if (a and mode) or (not a and not mode): if (a and mode) or (not a and not mode):
return True if isinstance(a, bool) else a return True if isinstance(a, bool) else a
sleep(.05) sleep(.05)
@ -564,9 +555,14 @@ class ElementWaiter(OriginWaiter):
class FrameWaiter(BaseWaiter, ElementWaiter): class FrameWaiter(BaseWaiter, ElementWaiter):
def __init__(self, frame): def __init__(self, owner):
""" """
:param frame: ChromiumFrame对象 :param owner: ChromiumFrame对象
""" """
super().__init__(frame) super().__init__(owner)
super(BaseWaiter, self).__init__(frame, frame.frame_ele) super(BaseWaiter, self).__init__(owner.frame_ele)
@property
def _timeout(self):
"""返回超时设置"""
return self._owner.timeout

View File

@ -13,28 +13,36 @@ from .._elements.chromium_element import ChromiumElement
from .._pages.chromium_base import ChromiumBase from .._pages.chromium_base import ChromiumBase
from .._pages.chromium_frame import ChromiumFrame from .._pages.chromium_frame import ChromiumFrame
from .._pages.chromium_page import ChromiumPage from .._pages.chromium_page import ChromiumPage
from .._pages.mix_page import MixPage
from .._pages.tabs import ChromiumTab, MixTab
class OriginWaiter(object): class OriginWaiter(object):
def __call__(self, second: float, scope: float = None) -> None: ... _owner = ...
def __init__(self, owner): ...
def __call__(self, second: float, scope: float = None): ...
class BrowserWaiter(OriginWaiter): class BrowserWaiter(OriginWaiter):
def __init__(self, owner: Chromium): _owner: Chromium = ...
self._owner = owner
def __init__(self, owner: Chromium): ...
def __call__(self, second: float, scope: float = None) -> Chromium: ...
def download_begin(self, timeout: float = None, cancel_it: bool = False) -> DownloadMission: ... def download_begin(self, timeout: float = None, cancel_it: bool = False) -> DownloadMission: ...
def new_tab(self, timeout: float = None, curr_tab: str = None, raise_err: bool = None) -> Union[str, bool]: ... def new_tab(self, timeout: float = None, curr_tab: str = None, raise_err: bool = None) -> Union[str, bool]: ...
def all_downloads_done(self, timeout: float = None, cancel_if_timeout: bool = True): ... def all_downloads_done(self, timeout: float = None, cancel_if_timeout: bool = True) -> bool: ...
class BaseWaiter(OriginWaiter): class BaseWaiter(OriginWaiter):
def __init__(self, page: ChromiumBase): _owner: ChromiumBase = ...
self._driver: ChromiumBase = ...
def __call__(self, second: float, scope: float = None) -> None: ... def __call__(self, second: float, scope: float = None) -> ChromiumBase: ...
def ele_deleted(self, def ele_deleted(self,
loc_or_ele: Union[str, tuple, ChromiumElement], loc_or_ele: Union[str, tuple, ChromiumElement],
@ -76,6 +84,11 @@ class BaseWaiter(OriginWaiter):
class TabWaiter(BaseWaiter): class TabWaiter(BaseWaiter):
_owner: Union[ChromiumTab, MixTab] = ...
def __init__(self, owner: Union[ChromiumTab, MixTab]): ...
def __call__(self, second: float, scope: float = None) -> Union[ChromiumTab, MixTab]: ...
def downloads_done(self, timeout: float = None, cancel_if_timeout: bool = True) -> bool: ... def downloads_done(self, timeout: float = None, cancel_if_timeout: bool = True) -> bool: ...
@ -83,7 +96,11 @@ class TabWaiter(BaseWaiter):
class PageWaiter(TabWaiter): class PageWaiter(TabWaiter):
_driver: ChromiumPage = ... _owner: Union[ChromiumPage, MixPage] = ...
def __init__(self, owner: Union[ChromiumPage, MixPage]): ...
def __call__(self, second: float, scope: float = None) -> Union[ChromiumPage, MixPage]: ...
def new_tab(self, timeout: float = None, raise_err: bool = None) -> Union[str, bool]: ... def new_tab(self, timeout: float = None, raise_err: bool = None) -> Union[str, bool]: ...
@ -91,11 +108,14 @@ class PageWaiter(TabWaiter):
class ElementWaiter(OriginWaiter): class ElementWaiter(OriginWaiter):
def __init__(self, owner: ChromiumBase, ele: ChromiumElement): _owner: ChromiumElement = ...
self._ele: ChromiumElement = ...
self._owner: ChromiumBase = ...
def __call__(self, second: float, scope: float = None) -> None: ... def __init__(self, owner: ChromiumElement): ...
def __call__(self, second: float, scope: float = None) -> ChromiumElement: ...
@property
def _timeout(self) -> float: ...
def deleted(self, timeout: float = None, raise_err: bool = None) -> bool: ... def deleted(self, timeout: float = None, raise_err: bool = None) -> bool: ...
@ -130,4 +150,8 @@ class ElementWaiter(OriginWaiter):
class FrameWaiter(BaseWaiter, ElementWaiter): class FrameWaiter(BaseWaiter, ElementWaiter):
def __init__(self, frame: ChromiumFrame): ... _owner: ChromiumFrame = ...
def __init__(self, owner: ChromiumFrame): ...
def __call__(self, second: float, scope: float = None) -> ChromiumFrame: ...