diff --git a/DrissionPage/_functions/elements.py b/DrissionPage/_functions/elements.py index 356febc..fc77631 100644 --- a/DrissionPage/_functions/elements.py +++ b/DrissionPage/_functions/elements.py @@ -36,10 +36,9 @@ class ElementsList(list): self._getter = Getter(self) return self._getter - def search(self, get_all=False, displayed=None, checked=None, selected=None, enabled=None, clickable=None, + def search(self, displayed=None, checked=None, selected=None, enabled=None, clickable=None, have_rect=None, have_text=None): """或关系筛选元素 - :param get_all: 是否返回所有筛选到的元素 :param displayed: 是否显示,bool,None为忽略该项 :param checked: 是否被选中,bool,None为忽略该项 :param selected: 是否被选择,bool,None为忽略该项 @@ -49,26 +48,37 @@ class ElementsList(list): :param have_text: 是否含有文本,bool,None为忽略该项 :return: 筛选结果 """ - if get_all: - r = ElementsList() - for i in self: - if ((displayed is not None and (displayed is True and i.states.is_displayed) or ( - displayed is False and not i.states.is_displayed)) - or (checked is not None and (checked is True and i.states.is_checked) or ( - checked is False and not i.states.is_checked)) - or (selected is not None and (selected is True and i.states.is_selected) or ( - selected is False and not i.states.is_selected)) - or (enabled is not None and (enabled is True and i.states.is_enabled) or ( - enabled is False and not i.states.is_enabled)) - or (clickable is not None and (clickable is True and i.states.is_clickable) or ( - clickable is False and not i.states.is_clickable)) - or (have_rect is not None and (have_rect is True and i.states.has_rect) or ( - have_rect is False and not i.states.has_rect)) - or (have_text is not None and (have_text is True and i.raw_text) or ( - have_text is False and not i.raw_text))): - r.append(i) - return r + r = ElementsList(self._page) + for i in self: + if ((displayed is not None and (displayed is True and i.states.is_displayed) or ( + displayed is False and not i.states.is_displayed)) + or (checked is not None and (checked is True and i.states.is_checked) or ( + checked is False and not i.states.is_checked)) + or (selected is not None and (selected is True and i.states.is_selected) or ( + selected is False and not i.states.is_selected)) + or (enabled is not None and (enabled is True and i.states.is_enabled) or ( + enabled is False and not i.states.is_enabled)) + or (clickable is not None and (clickable is True and i.states.is_clickable) or ( + clickable is False and not i.states.is_clickable)) + or (have_rect is not None and (have_rect is True and i.states.has_rect) or ( + have_rect is False and not i.states.has_rect)) + or (have_text is not None and (have_text is True and i.raw_text) or ( + have_text is False and not i.raw_text))): + r.append(i) + return Filter(r) + def search_one(self, displayed=None, checked=None, selected=None, enabled=None, clickable=None, + have_rect=None, have_text=None): + """或关系筛选元素 + :param displayed: 是否显示,bool,None为忽略该项 + :param checked: 是否被选中,bool,None为忽略该项 + :param selected: 是否被选择,bool,None为忽略该项 + :param enabled: 是否可用,bool,None为忽略该项 + :param clickable: 是否可点击,bool,None为忽略该项 + :param have_rect: 是否拥有大小和位置,bool,None为忽略该项 + :param have_text: 是否含有文本,bool,None为忽略该项 + :return: 筛选结果 + """ for i in self: if ((displayed is not None and (displayed is True and i.states.is_displayed) or ( displayed is False and not i.states.is_displayed)) @@ -86,7 +96,7 @@ class ElementsList(list): have_text is False and not i.raw_text))): return i - return NoneElement(self._page, method='filter()', args={'get_all': get_all, 'displayed': displayed, + return NoneElement(self._page, method='filter()', args={'displayed': displayed, 'checked': checked, 'selected': selected, 'enabled': enabled, 'clickable': clickable, 'have_rect': have_rect, 'have_text': have_text}) @@ -96,82 +106,79 @@ class BaseFilter(object): def __init__(self, _list): self._list = _list - def displayed(self): - """返回显示的元素""" - return self._any_state('is_displayed') - - def hidden(self): - """返回不显示的元素""" - return self._any_state('is_displayed', True) - - def checked(self): - """返回被选中的元素""" - return self._any_state('is_checked') - - def not_checked(self): - """返回没被选中的元素""" - return self._any_state('is_checked', True) - - def selected(self): - """返回被选中的列表元素""" - return self._any_state('is_selected') - - def not_selected(self): - """返回没被选中的列表元素""" - return self._any_state('is_selected', True) - - def enabled(self): - """返回有效的元素""" - return self._any_state('is_enabled') - - def disabled(self): - """返回无效的元素""" - return self._any_state('is_enabled', True) - - def clickable(self): - """返回可被点击的元素""" - return self._any_state('is_clickable') - - def not_clickable(self): - """返回不可被点击的元素""" - return self._any_state('is_clickable', True) - - def have_rect(self): - """返回有大小和位置的元素""" - return self._any_state('has_rect') - - def no_rect(self): - """返回没有大小和位置的元素""" - return self._any_state('has_rect', True) - - def style(self, name, value): - """返回拥有某个style值的元素 - :param name: 属性名称 - :param value: 属性值 + def displayed(self, equal=True): + """以是否显示为条件筛选元素 + :param equal: 是否匹配显示的元素,False匹配不显示的 :return: 筛选结果 """ - return self._get_attr(name, value, 'style') + return self._any_state('is_displayed', equal=equal) - def property(self, name, value): - """返回拥有某个property值的元素 - :param name: 属性名称 - :param value: 属性值 + def checked(self, equal=True): + """以是否被选中为条件筛选元素 + :param equal: 是否匹配被选中的元素,False匹配不被选中的 :return: 筛选结果 """ - return self._get_attr(name, value, 'property') + return self._any_state('is_checked', equal=equal) - def attr(self, name, value): - """返回拥有某个attribute值的元素 - :param name: 属性名称 - :param value: 属性值 + def selected(self, equal=True): + """以是否被选择为条件筛选元素,用于<select>元素项目 + :param equal: 是否匹配被选择的元素,False匹配不被选择的 :return: 筛选结果 """ - return self._get_attr(name, value, 'attr') + return self._any_state('is_selected', equal=equal) - def _get_attr(self, name, value, method): + def enabled(self, equal=True): + """以是否可用为条件筛选元素 + :param equal: 是否匹配可用的元素,False表示匹配disabled状态的 + :return: 筛选结果 + """ + return self._any_state('is_enabled', equal=equal) + + def clickable(self, equal=True): + """以是否可点击为条件筛选元素 + :param equal: 是否匹配可点击的元素,False表示匹配不是可点击的 + :return: 筛选结果 + """ + return self._any_state('is_clickable', equal=equal) + + def have_rect(self, equal=True): + """以是否有大小为条件筛选元素 + :param equal: 是否匹配有大小的元素,False表示匹配没有大小的 + :return: 筛选结果 + """ + return self._any_state('has_rect', equal=equal) + + def style(self, name, value, equal=True): + """以是否拥有某个style值为条件筛选元素 + :param name: 属性名称 + :param value: 属性值 + :param equal: True表示匹配name值为value值的元素,False表示匹配name值不为value值的 + :return: 筛选结果 + """ + return self._get_attr(name, value, 'style', equal=equal) + + def property(self, name, value, equal=True): + """以是否拥有某个property值为条件筛选元素 + :param name: 属性名称 + :param value: 属性值 + :param equal: True表示匹配name值为value值的元素,False表示匹配name值不为value值的 + :return: 筛选结果 + """ + return self._get_attr(name, value, 'property', equal=equal) + + def attr(self, name, value, equal=True): + """以是否拥有某个attribute值为条件筛选元素 + :param name: 属性名称 + :param value: 属性值 + :param equal: True表示匹配name值为value值的元素,False表示匹配name值不为value值的 + :return: 筛选结果 + """ + return self._get_attr(name, value, 'attr', equal=equal) + + def _get_attr(self, name, value, method, equal=True): pass - def _any_state(self, name, is_not=False): + def _any_state(self, name, equal=True): pass @@ -188,85 +195,151 @@ class Filter(BaseFilter): """返回用于获取元素属性的对象""" return self._list.get - def have_text(self): - """返回包含文本的元素""" - r = ElementsList() - for i in self._list: - if i.raw_text: - r.append(i) + @property + def search_one(self, displayed=None, checked=None, selected=None, enabled=None, clickable=None, + have_rect=None, have_text=None): + """或关系筛选元素 + :param displayed: 是否显示,bool,None为忽略该项 + :param checked: 是否被选中,bool,None为忽略该项 + :param selected: 是否被选择,bool,None为忽略该项 + :param enabled: 是否可用,bool,None为忽略该项 + :param clickable: 是否可点击,bool,None为忽略该项 + :param have_rect: 是否拥有大小和位置,bool,None为忽略该项 + :param have_text: 是否含有文本,bool,None为忽略该项 + :return: 筛选结果 + """ + return self._list.search_one(displayed=displayed, checked=checked, selected=selected, enabled=enabled, + clickable=clickable, have_rect=have_rect, have_text=have_text) + + @property + def search(self, displayed=None, checked=None, selected=None, enabled=None, clickable=None, + have_rect=None, have_text=None): + """或关系筛选元素 + :param displayed: 是否显示,bool,None为忽略该项 + :param checked: 是否被选中,bool,None为忽略该项 + :param selected: 是否被选择,bool,None为忽略该项 + :param enabled: 是否可用,bool,None为忽略该项 + :param clickable: 是否可点击,bool,None为忽略该项 + :param have_rect: 是否拥有大小和位置,bool,None为忽略该项 + :param have_text: 是否含有文本,bool,None为忽略该项 + :return: 筛选结果 + """ + return self._list.search(displayed=displayed, checked=checked, selected=selected, enabled=enabled, + clickable=clickable, have_rect=have_rect, have_text=have_text) + + def text(self, text, fuzzy=True, contain=True): + """以是否含有指定文本为条件筛选元素 + :param text: 用于匹配的文本 + :param fuzzy: 是否模糊匹配 + :param contain: 是否包含该字符串,False表示不包含 + :return: 筛选结果 + """ + r = ElementsList(self._list._page) + if contain: + for i in self._list: + t = i.raw_text + if (fuzzy and text in t) or (not fuzzy and text == t): + r.append(i) + else: + for i in self._list: + t = i.raw_text + if (fuzzy and text not in t) or (not fuzzy and text != t): + r.append(i) self._list = r return self - def _get_attr(self, name, value, method): + def _get_attr(self, name, value, method, equal=True): """返回通过某个方法可获得某个值的元素 :param name: 属性名称 :param value: 属性值 :param method: 方法名称 :return: 筛选结果 """ - r = ElementsList() - for i in self._list: - if getattr(i, method)(name) == value: - r.append(i) - self._list = r - return self - - def _any_state(self, name, is_not=False): - """ - :param name: 状态名称 - :param is_not: 是否选择否定的 - :return: 选中的列表 - """ - r = ElementsList() - if is_not: + r = ElementsList(self._list._page) + if equal: for i in self._list: - if not getattr(i.states, name): + if getattr(i, method)(name) == value: r.append(i) else: + for i in self._list: + if getattr(i, method)(name) != value: + r.append(i) + self._list = r + return self + + def _any_state(self, name, equal=True): + """ + :param name: 状态名称 + :param equal: 是否是指定状态,False表示否定状态 + :return: 选中的列表 + """ + r = ElementsList(self._list._page) + if equal: for i in self._list: if getattr(i.states, name): r.append(i) + else: + for i in self._list: + if not getattr(i.states, name): + r.append(i) self._list = r return self class FilterOne(BaseFilter): - def have_text(self): - """返回包含文本的元素""" - for i in self._list: - if i.raw_text: - return i - return NoneElement(self._list._page, method='have_text()') + def text(self, text, fuzzy=True, contain=True): + """以是否含有指定文本为条件筛选元素 + :param text: 用于匹配的文本 + :param fuzzy: 是否模糊匹配 + :param contain: 是否包含该字符串,False表示不包含 + :return: 选中的元素 + """ + if contain: + for i in self._list: + t = i.raw_text + if (fuzzy and text in t) or (not fuzzy and text == t): + return i + else: + for i in self._list: + t = i.raw_text + if (fuzzy and text not in t) or (not fuzzy and text != t): + return i + return NoneElement(self._list._page, 'text()', args={'text': text, 'fuzzy': fuzzy, 'contain': contain}) - def _get_attr(self, name, value, method): + def _get_attr(self, name, value, method, equal=True): """返回通过某个方法可获得某个值的元素 :param name: 属性名称 :param value: 属性值 :param method: 方法名称 - :return: 筛选结果 + :param equal: 是否是指定状态,False表示否定状态 + :return: 选中的元素 """ - for i in self._list: - if getattr(i, method)(name) == value: - return i - return NoneElement(self._list._page, f'{method}()', args={'name': name, 'value': value}) - - def _any_state(self, name, is_not=False): - """ - :param name: 状态名称 - :param is_not: 是否选择否定的 - :return: 选中的列表 - """ - if is_not: + if equal: for i in self._list: - if not getattr(i.states, name): + if getattr(i, method)(name) == value: return i else: + for i in self._list: + if getattr(i, method)(name) != value: + return i + return NoneElement(self._list._page, f'{method}()', args={'name': name, 'value': value}) + + def _any_state(self, name, equal=True): + """ + :param name: 状态名称 + :param equal: 是否是指定状态,False表示否定状态 + :return: 选中的元素 + """ + if equal: for i in self._list: if getattr(i.states, name): return i - - return NoneElement(self._list._page, f'{name}()', args={'name': name, 'is_not': is_not}) + else: + for i in self._list: + if not getattr(i.states, name): + return i + return NoneElement(self._list._page, f'{name}()', args={'equal': equal}) class Getter(object): @@ -274,12 +347,18 @@ class Getter(object): self._list = _list def links(self): + """返回所有元素的link属性组成的列表""" return [e.link for e in self._list] def texts(self): + """返回所有元素的text属性组成的列表""" return [e.text for e in self._list] def attrs(self, name): + """返回所有元素指定的attr属性组成的列表 + :param name: 属性名称 + :return: 属性文本组成的列表 + """ return [e.attr(name) for e in self._list] diff --git a/DrissionPage/_functions/elements.pyi b/DrissionPage/_functions/elements.pyi index 5517e9a..2d0d4bb 100644 --- a/DrissionPage/_functions/elements.pyi +++ b/DrissionPage/_functions/elements.pyi @@ -34,14 +34,22 @@ class ElementsList(list): def get(self) -> Getter: ... def search(self, - get_all: bool = False, displayed: Optional[bool] = None, checked: Optional[bool] = None, selected: Optional[bool] = None, enabled: Optional[bool] = None, clickable: Optional[bool] = None, have_rect: Optional[bool] = None, - have_text: Optional[bool] = None) -> Union[ElementsList, ChromiumElement]: ... + have_text: Optional[bool] = None) -> Filter: ... + + def search_one(self, + displayed: Optional[bool] = None, + checked: Optional[bool] = None, + selected: Optional[bool] = None, + enabled: Optional[bool] = None, + clickable: Optional[bool] = None, + have_rect: Optional[bool] = None, + have_text: Optional[bool] = None) -> ChromiumElement: ... def __next__(self) -> ChromiumElement: ... @@ -51,46 +59,34 @@ class BaseFilter(object): def __init__(self, _list: ElementsList): ... - def displayed(self): ... + def displayed(self, equal: bool = True): ... - def hidden(self): ... + def checked(self, equal: bool = True): ... - def checked(self): ... + def selected(self, equal: bool = True): ... - def not_checked(self): ... + def enabled(self, equal: bool = True): ... - def selected(self): ... + def clickable(self, equal: bool = True): ... - def not_selected(self): ... + def have_rect(self, equal: bool = True): ... - def enabled(self): ... - - def disabled(self): ... - - def clickable(self): ... - - def not_clickable(self): ... - - def have_rect(self): ... - - def no_rect(self): ... - - # def have_text(self): ... - - def style(self, name: str, value: str): ... + def style(self, name: str, value: str, equal: bool = True): ... def property(self, name: str, - value: str): ... + value: str, + equal: bool = True): ... - def attr(self, name: str, value: str): ... + def attr(self, name: str, value: str, equal: bool = True): ... def _get_attr(self, name: str, value: str, - method: str): ... + method: str, + equal: bool = True): ... - def _any_state(self, name: str, is_not: bool = False): ... + def _any_state(self, name: str, equal: bool = True): ... class Filter: @@ -105,46 +101,52 @@ class Filter: @property def get(self) -> Getter: ... - def displayed(self) -> Filter: ... + def displayed(self, equal: bool = True) -> Filter: ... - def hidden(self) -> Filter: ... + def checked(self, equal: bool = True) -> Filter: ... - def checked(self) -> Filter: ... + def selected(self, equal: bool = True) -> Filter: ... - def not_checked(self) -> Filter: ... + def enabled(self, equal: bool = True) -> Filter: ... - def selected(self) -> Filter: ... + def clickable(self, equal: bool = True) -> Filter: ... - def not_selected(self) -> Filter: ... + def have_rect(self, equal: bool = True) -> Filter: ... - def enabled(self) -> Filter: ... - - def disabled(self) -> Filter: ... - - def clickable(self) -> Filter: ... - - def not_clickable(self) -> Filter: ... - - def have_rect(self) -> Filter: ... - - def no_rect(self) -> Filter: ... - - def have_text(self) -> Filter: ... - - def style(self, name: str, value: str) -> Filter: ... + def style(self, name: str, value: str, equal: bool = True) -> Filter: ... def property(self, name: str, - value: str) -> Filter: ... + value: str, equal: bool = True) -> Filter: ... - def attr(self, name: str, value: str) -> Filter: ... + def attr(self, name: str, value: str, equal: bool = True) -> Filter: ... + + def text(self, text: str, fuzzy: bool = True, contain: bool = True) -> Filter: ... + + def search(self, + displayed: Optional[bool] = None, + checked: Optional[bool] = None, + selected: Optional[bool] = None, + enabled: Optional[bool] = None, + clickable: Optional[bool] = None, + have_rect: Optional[bool] = None, + have_text: Optional[bool] = None) -> Filter: ... + + def search_one(self, + displayed: Optional[bool] = None, + checked: Optional[bool] = None, + selected: Optional[bool] = None, + enabled: Optional[bool] = None, + clickable: Optional[bool] = None, + have_rect: Optional[bool] = None, + have_text: Optional[bool] = None) -> ChromiumElement: ... def _get_attr(self, name: str, value: str, - method: str) -> Filter: ... + method: str, equal: bool = True) -> Filter: ... - def _any_state(self, name: str, is_not: bool = False) -> Filter: ... + def _any_state(self, name: str, equal: bool = True) -> Filter: ... class FilterOne(BaseFilter): @@ -152,46 +154,34 @@ class FilterOne(BaseFilter): def __init__(self, _list: ElementsList): ... - def displayed(self) -> ChromiumElement: ... + def displayed(self, equal: bool = True) -> ChromiumElement: ... - def hidden(self) -> ChromiumElement: ... + def checked(self, equal: bool = True) -> ChromiumElement: ... - def checked(self) -> ChromiumElement: ... + def selected(self, equal: bool = True) -> ChromiumElement: ... - def not_checked(self) -> ChromiumElement: ... + def enabled(self, equal: bool = True) -> ChromiumElement: ... - def selected(self) -> ChromiumElement: ... + def clickable(self, equal: bool = True) -> ChromiumElement: ... - def not_selected(self) -> ChromiumElement: ... + def have_rect(self, equal: bool = True) -> ChromiumElement: ... - def enabled(self) -> ChromiumElement: ... - - def disabled(self) -> ChromiumElement: ... - - def clickable(self) -> ChromiumElement: ... - - def not_clickable(self) -> ChromiumElement: ... - - def have_rect(self) -> ChromiumElement: ... - - def no_rect(self) -> ChromiumElement: ... - - def have_text(self) -> ChromiumElement: ... - - def style(self, name: str, value: str) -> ChromiumElement: ... + def style(self, name: str, value: str, equal: bool = True) -> ChromiumElement: ... def property(self, name: str, - value: str) -> ChromiumElement: ... + value: str, equal: bool = True) -> ChromiumElement: ... - def attr(self, name: str, value: str) -> ChromiumElement: ... + def attr(self, name: str, value: str, equal: bool = True) -> ChromiumElement: ... + + def text(self, text: str, fuzzy: bool = True, contain: bool = True) -> ChromiumElement: ... def _get_attr(self, name: str, value: str, - method: str) -> ChromiumElement: ... + method: str, equal: bool = True) -> ChromiumElement: ... - def _any_state(self, name: str, is_not: bool = False) -> ChromiumElement: ... + def _any_state(self, name: str, equal: bool = True) -> ChromiumElement: ... class Getter(object): @@ -199,8 +189,8 @@ class Getter(object): def __init__(self, _list: ElementsList): ... - def links(self) -> list: ... + def links(self) -> List[str]: ... - def texts(self) -> list: ... + def texts(self) -> List[str]: ... - def attrs(self, name) -> list: ... + def attrs(self, name: str) -> List[str]: ...