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):
_BROWSERS = {}
_lock = Lock()
def __new__(cls, addr_or_opts=None, session_options=None):
"""
@ -42,8 +43,12 @@ class Chromium(object):
"""
opt = handle_options(addr_or_opts)
is_headless, browser_id, is_exists = run_browser(opt)
if browser_id in cls._BROWSERS:
return cls._BROWSERS[browser_id]
with cls._lock:
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._chromium_options = opt
r.is_headless = is_headless
@ -62,11 +67,9 @@ class Chromium(object):
self._created = True
self._type = 'Chromium'
self._frames = {}
self._drivers = {}
self._all_drivers = {}
self._lock = Lock()
self._set = None
self._wait = None

View File

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

View File

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