From 1daadf25d4225a32cbda858daa246bc556661ddd Mon Sep 17 00:00:00 2001 From: g1879 Date: Mon, 27 Apr 2020 18:44:40 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9C=AA=E5=AE=8C=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- DrissionPage/driver_page.py | 16 +++++-- DrissionPage/mix_element.py | 87 ++++++++++++++++++++++++------------ DrissionPage/mix_page.py | 11 ++++- DrissionPage/session_page.py | 12 +++-- 4 files changed, 90 insertions(+), 36 deletions(-) diff --git a/DrissionPage/driver_page.py b/DrissionPage/driver_page.py index f849e89..4888e68 100644 --- a/DrissionPage/driver_page.py +++ b/DrissionPage/driver_page.py @@ -104,7 +104,13 @@ class DriverPage(object): """查找符合条件的所有元素""" return self.find(loc, mode='all', timeout=timeout, show_errmsg=show_errmsg) - def search(self, value: str, mode: str = None, timeout: float = 10): + def search(self, value: str, mode: str = None, timeout: float = 10) -> Union[WebElement, list, None]: + """根据内容搜索元素 + :param value: 搜索内容 + :param mode: 可选'single','all' + :param timeout: 超时时间 + :return: 页面元素对象 + """ mode = mode if mode else 'single' if mode not in ['single', 'all']: raise ValueError("mode须在'single', 'all'中选择") @@ -118,9 +124,13 @@ class DriverPage(object): ele = wait.until(EC.presence_of_all_elements_located(loc)) return ele except: - return ele + if mode == 'single': + return None + elif mode == 'all': + return [] - def search_all(self, value: str, timeout: float = 10): + def search_all(self, value: str, timeout: float = 10) -> list: + """根据内容搜索元素""" return self.search(value, mode='all', timeout=timeout) def get_attr(self, loc_or_ele: Union[WebElement, tuple], attr: str) -> str: diff --git a/DrissionPage/mix_element.py b/DrissionPage/mix_element.py index 29f8f4f..31f08f7 100644 --- a/DrissionPage/mix_element.py +++ b/DrissionPage/mix_element.py @@ -1,5 +1,9 @@ -#!/usr/bin/env python # -*- coding:utf-8 -*- +""" +@Author : g1879 +@Contact : g1879@qq.com +@File : mix_page.py +""" import re from html import unescape from time import sleep @@ -8,6 +12,7 @@ from typing import Union from requests_html import Element from selenium.webdriver.remote.webelement import WebElement from selenium.webdriver.support import expected_conditions as EC +from selenium.webdriver.support.select import Select from selenium.webdriver.support.wait import WebDriverWait from .config import global_tmp_path @@ -19,18 +24,21 @@ class MixElement(object): self._ele = ele @property - def ele(self): + def ele(self) -> Union[WebElement, Element]: + """返回元素对象""" return self._ele @property - def text(self): + def text(self) -> str: + """元素内文本""" if isinstance(self._ele, Element): return unescape(self._ele.text).replace('\xa0', ' ') else: return unescape(self.attr('innerText')).replace('\xa0', ' ') @property - def html(self): + def html(self) -> str: + """元素innerHTML""" if isinstance(self._ele, Element): html = unescape(self._ele.html).replace('\xa0', ' ') r = re.match(r'<.*?>(.*)', html, flags=re.DOTALL) @@ -39,7 +47,8 @@ class MixElement(object): return unescape(self.attr('innerHTML')).replace('\xa0', ' ') @property - def tag_name(self): + def tag_name(self) -> str: + """获取标签名""" if isinstance(self._ele, Element): html = unescape(self._ele.html).replace('\xa0', ' ') r = re.match(r'^<(.*?)\s+', html, flags=re.DOTALL) @@ -47,7 +56,8 @@ class MixElement(object): else: return self._ele.tag_name - def attr(self, attr): + def attr(self, attr) -> str: + """获取属性值""" if isinstance(self._ele, Element): try: if attr == 'href': @@ -67,26 +77,28 @@ class MixElement(object): else: return self._ele.get_attribute(attr) - def find(self, loc: tuple, mode: str = None, show_errmsg: bool = True): + def find(self, loc: tuple, mode: str = None, show_errmsg: bool = True) -> Union[WebElement, Element, list, None]: """根据loc获取元素""" if isinstance(self._ele, Element): mode = mode if mode else 'single' if mode not in ['single', 'all']: raise ValueError("mode须在'single', 'all'中选择") loc_by, loc_str = _translate_loc(loc) - msg = first = None + msg = ele = None try: if mode == 'single': msg = '未找到元素' - first = True + if loc_by == 'xpath': + ele = MixElement(self.ele.xpath(loc_str, first=True, _encoding='utf-8')) + else: + ele = MixElement(self.ele.find(loc_str, first=True, _encoding='utf-8')) elif mode == 'all': msg = '未找到元素s' - first = False - if loc_by == 'xpath': - ele = self.ele.xpath(loc_str, first=first, _encoding='utf-8') - else: - ele = self.ele.find(loc_str, first=first, _encoding='utf-8') - return MixElement(ele) + if loc_by == 'xpath': + ele = self.ele.xpath(loc_str, first=False, _encoding='utf-8') + else: + ele = self.ele.find(loc_str, first=False, _encoding='utf-8') + return ele except: if show_errmsg: print(msg, loc) @@ -103,16 +115,18 @@ class MixElement(object): ele = wait.until(EC.presence_of_element_located(loc)) elif mode == 'all': msg = '未找到元素s' - ele = wait.until(EC.presence_of_all_elements_located(loc)) + ele = MixElement(wait.until(EC.presence_of_all_elements_located(loc))) elif mode == 'visible': msg = '元素不可见或不存在' ele = wait.until(EC.visibility_of_element_located(loc)) - return MixElement(ele) + return ele except: if show_errmsg: print(msg, loc) + raise - def find_all(self, loc: tuple, show_errmsg: bool = True): + def find_all(self, loc: tuple, show_errmsg: bool = True) -> list: + """根据loc获取子元素列表""" return self.find(loc, mode='all', show_errmsg=show_errmsg) def search(self, value: str, mode: str = None): @@ -143,11 +157,12 @@ class MixElement(object): except: return None - def search_all(self, value: str): + def search_all(self, value: str) -> list: + """根据内容获取元素列表""" return self.search(value, mode='all') # -----------------以下为d模式独占------------------- - def click(self): + def click(self) -> bool: """点击""" for _ in range(10): try: @@ -164,7 +179,8 @@ class MixElement(object): except: raise - def input(self, value, clear: bool = True): + def input(self, value, clear: bool = True) -> bool: + """输入文本""" try: if clear: self.run_script("arguments[0].value=''") @@ -174,32 +190,41 @@ class MixElement(object): raise def run_script(self, script: str): + """运行js""" self.ele.parent.execute_script(script, self.ele) def submit(self): + """提交表单""" self.ele.submit() def clear(self): + """清空元素""" self.ele.clear() - def is_selected(self): + def is_selected(self) -> bool: + """是否选中""" return self.ele.is_selected() - def is_enabled(self): + def is_enabled(self) -> bool: + """是否可用""" return self.ele.is_enabled() - def is_displayed(self): + def is_displayed(self) -> bool: + """是否可见""" return self.ele.is_displayed() @property def size(self): + """元素大小""" return self.ele.size @property def location(self): + """元素坐标""" return self.ele.location - def screenshot(self, path: str = None, filename: str = None): + def screenshot(self, path: str = None, filename: str = None) -> str: + """元素截图""" path = path if path else global_tmp_path name = filename if filename else self.tag_name # 等待元素加载完成 @@ -212,10 +237,16 @@ class MixElement(object): self.ele.screenshot(img_path) return img_path - def select(self, value: str): - pass + def select(self, text: str): + """选择下拉列表""" + ele = Select(self.ele) + try: + ele.select_by_visible_text(text) + return True + except: + return False - def set_attr(self, attr, value): + def set_attr(self, attr, value) -> bool: """设置元素属性""" try: self.run_script(f"arguments[0].{attr} = '{value}';") diff --git a/DrissionPage/mix_page.py b/DrissionPage/mix_page.py index bc11e8a..df8c07f 100644 --- a/DrissionPage/mix_page.py +++ b/DrissionPage/mix_page.py @@ -183,13 +183,20 @@ class MixPage(Null, SessionPage, DriverPage): elif self._mode == 'd': return super(SessionPage, self).find_all(loc, timeout=timeout, show_errmsg=show_errmsg) - def search(self, value: str, mode: str = None, timeout: float = 10): + def search(self, value: str, mode: str = None, timeout: float = 10) -> Union[WebElement, Element, None]: + """根据内容搜索元素 + :param value: 搜索内容 + :param mode: 可选'single','all' + :param timeout: 超时时间 + :return: 页面元素对象,s模式下返回Element,d模式下返回WebElement + """ if self._mode == 's': return super().search(value, mode=mode) elif self._mode == 'd': return super(SessionPage, self).search(value, mode=mode, timeout=timeout) - def search_all(self, value: str, timeout: float = 10): + def search_all(self, value: str, timeout: float = 10) -> list: + """根据内容搜索元素""" if self._mode == 's': return super().search_all(value) elif self._mode == 'd': diff --git a/DrissionPage/session_page.py b/DrissionPage/session_page.py index 99eedbf..8014f70 100644 --- a/DrissionPage/session_page.py +++ b/DrissionPage/session_page.py @@ -115,7 +115,12 @@ class SessionPage(object): """查找符合条件的所有元素""" return self.find(loc, mode='all', show_errmsg=True) - def search(self, value: str, mode: str = None): + def search(self, value: str, mode: str = None) -> Union[Element, list, None]: + """根据内容搜索元素 + :param value: 搜索内容 + :param mode: 可选'single','all' + :return: 页面元素对象 + """ mode = mode if mode else 'single' if mode not in ['single', 'all']: raise ValueError("mode须在'single', 'all'中选择") @@ -127,9 +132,10 @@ class SessionPage(object): eles = self.response.html.xpath(f'.//*[contains(text(),"{value}")]') return eles except: - return None + return - def search_all(self, value: str): + def search_all(self, value: str) -> list: + """根据内容搜索元素""" return self.search(value, mode='all') def _get_ele(self, loc_or_ele: Union[Element, tuple]) -> Element: