diff --git a/DrissionPage/__init__.py b/DrissionPage/__init__.py index 3fc9db9..e4e3342 100644 --- a/DrissionPage/__init__.py +++ b/DrissionPage/__init__.py @@ -14,4 +14,4 @@ from ._configs.chromium_options import ChromiumOptions from ._configs.session_options import SessionOptions __all__ = ['ChromiumPage', 'ChromiumOptions', 'SessionOptions', 'SessionPage', 'WebPage', '__version__'] -__version__ = '4.0.4.24' +__version__ = '4.0.4.25' diff --git a/DrissionPage/_elements/chromium_element.py b/DrissionPage/_elements/chromium_element.py index 386c8c1..68f38ec 100644 --- a/DrissionPage/_elements/chromium_element.py +++ b/DrissionPage/_elements/chromium_element.py @@ -637,6 +637,7 @@ class ChromiumElement(DrissionElement): self.run_js('this.dispatchEvent(new Event("change", {bubbles: true}));') return + self.wait.clickable(timeout=.5) if clear and vals not in ('\n', '\ue007'): self.clear(by_js=False) else: @@ -703,7 +704,6 @@ class ChromiumElement(DrissionElement): ele_or_loc = ele_or_loc.rect.midpoint elif not isinstance(ele_or_loc, (list, tuple)): raise TypeError('需要ChromiumElement对象或坐标。') - self.owner.actions.hold(self).move_to(ele_or_loc, duration=duration).release() def _get_obj_id(self, node_id=None, backend_id=None): diff --git a/DrissionPage/_elements/none_element.py b/DrissionPage/_elements/none_element.py index 15502f3..49d55f2 100644 --- a/DrissionPage/_elements/none_element.py +++ b/DrissionPage/_elements/none_element.py @@ -10,6 +10,11 @@ from ..errors import ElementNotFoundError class NoneElement(object): def __init__(self, page=None, method=None, args=None): + """ + :param page: + :param method: + :param args: + """ if page: self._none_ele_value = page._none_ele_value self._none_ele_return_value = page._none_ele_return_value diff --git a/DrissionPage/_functions/tools.py b/DrissionPage/_functions/tools.py index 5a1df3f..a3463ec 100644 --- a/DrissionPage/_functions/tools.py +++ b/DrissionPage/_functions/tools.py @@ -13,6 +13,7 @@ from threading import Lock from time import perf_counter, sleep from .._configs.options_manage import OptionsManager +from .._elements.none_element import NoneElement from ..errors import (ContextLostError, ElementLostError, CDPError, PageDisconnectedError, NoRectError, AlertExistsError, WrongURLError, StorageError, CookieFormatError, JavaScriptError) @@ -235,91 +236,141 @@ def raise_error(result, ignore=None): class ElementsList(list): - def displayed(self): - """返回所有显示的元素""" - return self._any_state('is_displayed') + # def __init__(self, page=None, method=None, ): + # super().__init__() - def hidden(self): - """返回所有不显示的元素""" - return self._any_state('is_displayed', True) + def displayed(self, get_all=False): + """返回显示的元素,默认返回第一个 + :param get_all: 是否返回所有 + :return: 元素或元素组成的列表 + """ + return self._any_state('is_displayed', get_all=get_all) - def checked(self): - """返回所有被选中的元素""" - return self._any_state('is_checked') + def hidden(self, get_all=False): + """返回不显示的元素,默认返回第一个 + :param get_all: 是否返回所有 + :return: 元素或元素组成的列表 + """ + return self._any_state('is_displayed', True, get_all=get_all) - def not_checked(self): - """返回所有没被选中的元素""" - return self._any_state('is_checked', True) + def checked(self, get_all=False): + """返回被选中的元素,默认返回第一个 + :param get_all: 是否返回所有 + :return: 元素或元素组成的列表 + """ + return self._any_state('is_checked', get_all=get_all) - def selected(self): - """返回所有被选中的列表元素""" - return self._any_state('is_selected') + def not_checked(self, get_all=False): + """返回没被选中的元素""" + return self._any_state('is_checked', True, get_all=get_all) - def not_selected(self): - """返回所有没被选中的列表元素""" - return self._any_state('is_selected', True) + def selected(self, get_all=False): + """返回被选中的列表元素,默认返回第一个 + :param get_all: 是否返回所有 + :return: 元素或元素组成的列表 + """ + return self._any_state('is_selected', get_all=get_all) - def enabled(self): - """返回所有有效的元素""" - return self._any_state('is_enabled') + def not_selected(self, get_all=False): + """返回没被选中的列表元素,默认返回第一个 + :param get_all: 是否返回所有 + :return: 元素或元素组成的列表 + """ + return self._any_state('is_selected', True, get_all=get_all) - def disabled(self): - """返回所有无效的元素""" - return self._any_state('is_enabled', True) + def enabled(self, get_all=False): + """返回有效的元素,默认返回第一个 + :param get_all: 是否返回所有 + :return: 元素或元素组成的列表 + """ + return self._any_state('is_enabled', get_all=get_all) - def clickable(self): - """返回所有可被点击的元素""" - return self._any_state('is_clickable') + def disabled(self, get_all=False): + """返回无效的元素,默认返回第一个 + :param get_all: 是否返回所有 + :return: 元素或元素组成的列表 + """ + return self._any_state('is_enabled', True, get_all=get_all) - def not_clickable(self): - """返回所有不可被点击的元素""" - return self._any_state('is_clickable', True) + def clickable(self, get_all=False): + """返回可被点击的元素,默认返回第一个 + :param get_all: 是否返回所有 + :return: 元素或元素组成的列表 + """ + return self._any_state('is_clickable', get_all=get_all) - def has_rect(self): - """返回所有有大小和位置的元素""" - return self._any_state('has_rect') + def not_clickable(self, get_all=False): + """返回不可被点击的元素,默认返回第一个 + :param get_all: 是否返回所有 + :return: 元素或元素组成的列表 + """ + return self._any_state('is_clickable', True, get_all=get_all) - def no_rect(self): - """返回所有没有大小和位置的元素""" - return self._any_state('has_rect', True) + def have_rect(self, get_all=False): + """返回有大小和位置的元素,默认返回第一个 + :param get_all: 是否返回所有 + :return: 元素或元素组成的列表 + """ + return self._any_state('has_rect', get_all=get_all) - def style(self, name, value): - """返回所有拥有某个style值的元素 + def no_rect(self, get_all=False): + """返回没有大小和位置的元素,默认返回第一个 + :param get_all: 是否返回所有 + :return: 元素或元素组成的列表 + """ + return self._any_state('has_rect', True, get_all=get_all) + + def have_text(self, get_all=False): + """返回包含文本的元素,默认返回第一个 + :param get_all: 是否返回所有 + :return: 元素或元素组成的列表 + """ + r = ElementsList() + for i in self: + if i.raw_text: + r.append(i) + return r if get_all else r[0] if r else NoneElement() + + def style(self, name, value, get_all=False): + """返回拥有某个style值的元素,默认返回第一个 :param name: 属性名称 :param value: 属性值 + :param get_all: 是否返回所有 :return: 筛选结果 """ r = ElementsList() for i in self: if i.style(name) == value: r.append(i) - return r + return r if get_all else r[0] if r else NoneElement() - def property(self, name, value): - """返回所有拥有某个property值的元素 + def property(self, name, value, get_all=False): + """返回拥有某个property值的元素,默认返回第一个 :param name: 属性名称 :param value: 属性值 + :param get_all: 是否返回所有 :return: 筛选结果 """ r = ElementsList() for i in self: if i.property(name) == value: r.append(i) - return r + return r if get_all else r[0] if r else NoneElement() - def attr(self, name, value): - """返回所有拥有某个attribute值的元素 + def attr(self, name, value, get_all=False): + """返回拥有某个attribute值的元素,默认返回第一个 :param name: 属性名称 :param value: 属性值 + :param get_all: 是否返回所有 :return: 筛选结果 """ r = ElementsList() for i in self: if i.attr(name) == value: r.append(i) - return r + return r if get_all else r[0] if r else NoneElement() - def _any_state(self, name, is_not=False): + def _any_state(self, name, is_not=False, get_all=False): """ :param name: 状态名称 :param is_not: 是否选择否定的 @@ -334,4 +385,4 @@ class ElementsList(list): for i in self: if getattr(i.states, name): r.append(i) - return r + return r if get_all else r[0] if r else NoneElement() diff --git a/DrissionPage/_functions/tools.pyi b/DrissionPage/_functions/tools.pyi index c35ee0f..d2acb4b 100644 --- a/DrissionPage/_functions/tools.pyi +++ b/DrissionPage/_functions/tools.pyi @@ -50,34 +50,38 @@ def raise_error(result: dict, ignore=None) -> None: ... class ElementsList(list): - def displayed(self) -> List[ChromiumElement]: ... + def displayed(self, get_all: bool = False) -> Union[List[ChromiumElement], ChromiumElement]: ... - def hidden(self) -> List[ChromiumElement]: ... + def hidden(self, get_all: bool = False) -> Union[List[ChromiumElement], ChromiumElement]: ... - def checked(self) -> List[ChromiumElement]: ... + def checked(self, get_all: bool = False) -> Union[List[ChromiumElement], ChromiumElement]: ... - def not_checked(self) -> List[ChromiumElement]: ... + def not_checked(self, get_all: bool = False) -> Union[List[ChromiumElement], ChromiumElement]: ... - def selected(self) -> List[ChromiumElement]: ... + def selected(self, get_all: bool = False) -> Union[List[ChromiumElement], ChromiumElement]: ... - def not_selected(self) -> List[ChromiumElement]: ... + def not_selected(self, get_all: bool = False) -> Union[List[ChromiumElement], ChromiumElement]: ... - def enabled(self) -> List[ChromiumElement]: ... + def enabled(self, get_all: bool = False) -> Union[List[ChromiumElement], ChromiumElement]: ... - def disabled(self) -> List[ChromiumElement]: ... + def disabled(self, get_all: bool = False) -> Union[List[ChromiumElement], ChromiumElement]: ... - def clickable(self) -> List[ChromiumElement]: ... + def clickable(self, get_all: bool = False) -> Union[List[ChromiumElement], ChromiumElement]: ... - def not_clickable(self) -> List[ChromiumElement]: ... + def not_clickable(self, get_all: bool = False) -> Union[List[ChromiumElement], ChromiumElement]: ... - def has_rect(self) -> List[ChromiumElement]: ... + def have_rect(self, get_all: bool = False) -> Union[List[ChromiumElement], ChromiumElement]: ... - def no_rect(self) -> List[ChromiumElement]: ... + def no_rect(self, get_all: bool = False) -> Union[List[ChromiumElement], ChromiumElement]: ... - def style(self, name: str, value: str) -> List[ChromiumElement]: ... + def have_text(self, get_all: bool = False) -> Union[List[ChromiumElement], ChromiumElement]: ... - def property(self, name: str, value: str) -> List[ChromiumElement]: ... + def style(self, name: str, value: str, get_all: bool = False) -> Union[List[ChromiumElement], ChromiumElement]: ... - def attr(self, name: str, value: str) -> List[ChromiumElement]: ... + def property(self, name: str, value: str, get_all: bool = False) -> Union[List[ChromiumElement], ChromiumElement]: ... - def _any_state(self, name: str, is_not: bool = False) -> List[ChromiumElement]: ... + def attr(self, name: str, value: str, get_all: bool = False) -> Union[List[ChromiumElement], ChromiumElement]: ... + + def _any_state(self, name: str, is_not: bool = False, get_all: bool = False) -> List[ChromiumElement]: ... + + def __next__(self) -> ChromiumElement: ... diff --git a/DrissionPage/_units/actions.py b/DrissionPage/_units/actions.py index d61bbd4..e1c951c 100644 --- a/DrissionPage/_units/actions.py +++ b/DrissionPage/_units/actions.py @@ -141,7 +141,7 @@ class Actions: :return: self """ if on_ele: - self.move_to(on_ele, duration=0) + self.move_to(on_ele, duration=.2) self._release('left') return self @@ -159,7 +159,7 @@ class Actions: :return: self """ if on_ele: - self.move_to(on_ele, duration=0) + self.move_to(on_ele, duration=.2) self._release('right') return self @@ -177,7 +177,7 @@ class Actions: :return: self """ if on_ele: - self.move_to(on_ele, duration=0) + self.move_to(on_ele, duration=.2) self._release('middle') return self @@ -189,7 +189,7 @@ class Actions: :return: self """ if on_ele: - self.move_to(on_ele, duration=0) + self.move_to(on_ele, duration=.2) self._dr.run('Input.dispatchMouseEvent', type='mousePressed', button=button, clickCount=count, x=self.curr_x, y=self.curr_y, modifiers=self.modifier) self._holding = button @@ -213,7 +213,7 @@ class Actions: :return: self """ if on_ele: - self.move_to(on_ele, duration=0) + self.move_to(on_ele, duration=.2) self._dr.run('Input.dispatchMouseEvent', type='mouseWheel', x=self.curr_x, y=self.curr_y, deltaX=delta_x, deltaY=delta_y, modifiers=self.modifier) return self diff --git a/DrissionPage/_units/clicker.py b/DrissionPage/_units/clicker.py index ae42230..e0effc9 100644 --- a/DrissionPage/_units/clicker.py +++ b/DrissionPage/_units/clicker.py @@ -204,7 +204,6 @@ class Clicker(object): """ self._ele.owner.run_cdp('Input.dispatchMouseEvent', type='mousePressed', x=client_x, y=client_y, button=button, clickCount=count, _ignore=AlertExistsError) - # sleep(.05) self._ele.owner.run_cdp('Input.dispatchMouseEvent', type='mouseReleased', x=client_x, y=client_y, button=button, _ignore=AlertExistsError) diff --git a/DrissionPage/_units/listener.py b/DrissionPage/_units/listener.py index fcdf311..589b225 100644 --- a/DrissionPage/_units/listener.py +++ b/DrissionPage/_units/listener.py @@ -251,13 +251,13 @@ class Listener(object): self._target_id = target_id self._address = address self._owner = owner - debug = False + # debug = False if self._driver: - debug = self._driver._debug + # debug = self._driver._debug self._driver.stop() if self.listening: self._driver = Driver(self._target_id, 'page', self._address) - self._driver._debug = debug + # self._driver._debug = debug self._driver.run('Network.enable') self._set_callback()