DriverElement

- set_property属性改名为set_prop
- 增加prop()
- clear()改用selenium原生
- 增加r_click()和r_click_at()
- input()返回None
- 增加input_txt()

DriverPage
- wait属性改名为wait_object

其余一些微调
This commit is contained in:
g1879 2021-08-11 10:28:20 +08:00
parent 530598ed58
commit 19f8b14500
5 changed files with 92 additions and 36 deletions

View File

@ -4,8 +4,9 @@
@Contact : g1879@qq.com
@File : driver_element.py
"""
import re
from pathlib import Path
from re import sub
from time import sleep
from typing import Union, List, Any, Tuple
@ -82,8 +83,8 @@ class DriverElement(DrissionElement):
"""返回元素内所有文本"""
# return format_html(self.inner_ele.get_attribute('innerText'), False)
re_str = self.inner_ele.get_attribute('innerText')
re_str = re.sub(r'\n{2,}', '\n', re_str)
re_str = re.sub(r' {2,}', ' ', re_str)
re_str = sub(r'\n{2,}', '\n', re_str)
re_str = sub(r' {2,}', ' ', re_str)
return format_html(re_str.strip('\n '), False)
@ -104,6 +105,7 @@ class DriverElement(DrissionElement):
@property
def xpath(self) -> str:
"""返回xpath路径"""
return self._get_ele_path('xpath')
@property
@ -114,12 +116,12 @@ class DriverElement(DrissionElement):
@property
def next(self):
"""返回后一个兄弟元素"""
return self._get_brother(1, 'ele', 'next')
return self.nexts()
@property
def prev(self):
"""返回前一个兄弟元素"""
return self._get_brother(1, 'ele', 'prev')
return self.prevs()
@property
def comments(self) -> list:
@ -385,22 +387,56 @@ class DriverElement(DrissionElement):
from selenium.webdriver import ActionChains
ActionChains(self.page.driver).move_to_element_with_offset(self.inner_ele, x, y).click().perform()
def input(self, value: Union[str, tuple], clear: bool = True) -> bool:
"""输入文本或组合键 \n
def r_click(self) -> None:
"""右键单击"""
from selenium.webdriver import ActionChains
ActionChains(self.page.driver).context_click(self.inner_ele).perform()
def r_click_at(self, x: Union[int, str] = None, y: Union[int, str] = None) -> None:
"""带偏移量右键单击本元素相对于左上角坐标。不传入x或y值时点击元素中点 \n
:param x: 相对元素左上角坐标的x轴偏移量
:param y: 相对元素左上角坐标的y轴偏移量
:return: None
"""
x = int(x) if x is not None else self.size['width'] // 2
y = int(y) if y is not None else self.size['height'] // 2
from selenium.webdriver import ActionChains
ActionChains(self.page.driver).move_to_element_with_offset(self.inner_ele, x, y).context_click().perform()
def input(self, value: Union[str, tuple], clear: bool = True) -> None:
"""输入文本或组合键,可用于所有场合 \n
:param value: 文本值或按键组合
:param clear: 输入前是否清空文本框
:return: 是否输入成功
"""
try:
if clear:
self.clear()
self.inner_ele.send_keys(*value)
def input_txt(self, txt: Union[str, tuple], clear: bool = True) -> None:
"""专门用于输入文本框,解决文本框有时输入失效的问题 \n
:param txt: 文本值
:param clear: 输入前是否清空文本框
:return: 是否输入成功
"""
enter = '\n' if txt.endswith('\n') else None
full_txt = txt if clear else f'{self.attr("value")}{txt}'
full_txt = full_txt.rstrip('\n')
from time import perf_counter
t1 = perf_counter()
while True:
if self.attr('value') == full_txt or perf_counter() - t1 > self.page.timeout:
break
if clear:
self.clear()
self.inner_ele.send_keys(*value)
return True
self.inner_ele.send_keys(txt)
except Exception as e:
print(e)
return False
if enter:
self.inner_ele.send_keys(enter)
def run_script(self, script: str, *args) -> Any:
"""执行js代码传入自己为第一个参数 \n
@ -416,8 +452,7 @@ class DriverElement(DrissionElement):
def clear(self) -> None:
"""清空元素文本"""
self.run_script("arguments[0].value=''")
# self.inner_ele.clear()
self.inner_ele.clear()
def is_selected(self) -> bool:
"""是否选中"""
@ -463,7 +498,14 @@ class DriverElement(DrissionElement):
return img_path
def set_property(self, prop: str, value: str) -> bool:
def prop(self, prop: str) -> str:
"""获取property属性值 \n
:param prop: 属性名
:return: 属性值文本
"""
return format_html(self.inner_ele.get_property(prop))
def set_prop(self, prop: str, value: str) -> bool:
"""设置元素property属性 \n
:param prop: 属性名
:param value: 属性值
@ -669,8 +711,8 @@ def execute_driver_find(page_or_ele,
if timeout is not None and timeout != page.timeout:
wait = WebDriverWait(driver, timeout=timeout)
else:
page.wait._driver = driver
wait = page.wait
page.wait_object._driver = driver
wait = page.wait_object
try:
# 使用xpath查找

View File

@ -5,15 +5,15 @@
@File : driver_page.py
"""
from glob import glob
from pathlib import Path
from time import time, sleep
from typing import Union, List, Any, Tuple
from urllib.parse import quote
from selenium.common.exceptions import NoAlertPresentException
from selenium.webdriver.chrome.webdriver import WebDriver
from selenium.webdriver.remote.webelement import WebElement
from selenium.webdriver.support.wait import WebDriverWait
from time import time, sleep
from typing import Union, List, Any, Tuple
from urllib.parse import quote
from .common import str_to_loc, get_available_file_name, translate_loc, format_html
from .driver_element import DriverElement, execute_driver_find
@ -33,6 +33,12 @@ class DriverPage(object):
self.retry_times = 3
self.retry_interval = 2
def __call__(self,
loc_or_str: Union[Tuple[str, str], str, DriverElement, WebElement],
mode: str = 'single',
timeout: float = None):
return self.ele(loc_or_str, mode, timeout)
@property
def driver(self) -> WebDriver:
return self._driver
@ -67,15 +73,18 @@ class DriverPage(object):
@property
def timeout(self) -> float:
"""返回查找元素时等待的秒数"""
return self._timeout
@timeout.setter
def timeout(self, second: float) -> None:
"""设置查找元素时等待的秒数"""
self._timeout = second
self._wait = None
@property
def wait(self) -> WebDriverWait:
def wait_object(self) -> WebDriverWait:
"""返回WebDriverWait对象重用避免每次新建对象"""
if self._wait is None:
self._wait = WebDriverWait(self.driver, timeout=self.timeout)

View File

@ -4,7 +4,7 @@
@Contact : g1879@qq.com
@File : session_element.py
"""
import re
from re import match, DOTALL, sub
from typing import Union, List, Tuple
from urllib.parse import urlparse, urljoin, urlunparse
@ -42,7 +42,7 @@ class SessionElement(DrissionElement):
@property
def inner_html(self) -> str:
"""返回元素innerHTML文本"""
r = re.match(r'<.*?>(.*)</.*?>', self.html, flags=re.DOTALL)
r = match(r'<.*?>(.*)</.*?>', self.html, flags=DOTALL)
return '' if not r else r.group(1)
@property
@ -79,7 +79,7 @@ class SessionElement(DrissionElement):
return str_list
re_str = ''.join(get_node(self))
re_str = re.sub(r' {2,}', ' ', re_str)
re_str = sub(r' {2,}', ' ', re_str)
return format_html(re_str, False)
@property
@ -120,15 +120,16 @@ class SessionElement(DrissionElement):
@property
def next(self):
"""返回后一个兄弟元素"""
return self._get_brother(1, 'ele', 'next')
return self.nexts()
@property
def prev(self):
"""返回前一个兄弟元素"""
return self._get_brother(1, 'ele', 'prev')
return self.prevs()
@property
def comments(self):
def comments(self) -> list:
"""返回元素注释文本组成的列表"""
return self.eles('xpath:.//comment()')
def texts(self, text_node_only: bool = False) -> list:

View File

@ -4,17 +4,15 @@
@Contact : g1879@qq.com
@File : session_page.py
"""
import re
from os import path as os_PATH
from pathlib import Path
from random import randint
from re import search as re_SEARCH
from re import sub as re_SUB
from re import search as re_SEARCH, sub as re_SUB
from time import time, sleep
from typing import Union, List, Tuple
from urllib.parse import urlparse, quote, unquote
from requests import Session, Response
from time import time, sleep
from tldextract import extract
from .common import str_to_loc, translate_loc, get_available_file_name, format_html
@ -36,6 +34,12 @@ class SessionPage(object):
self.retry_times = 3
self.retry_interval = 2
def __call__(self,
loc_or_str: Union[Tuple[str, str], str, SessionElement],
mode: str = 'single',
timeout: float = None):
return self.ele(loc_or_str, mode)
@property
def session(self) -> Session:
"""返回session对象"""
@ -368,7 +372,7 @@ class SessionPage(object):
# 使用header里的文件名
if content_disposition:
file_name = content_disposition.encode('ISO-8859-1').decode('utf-8')
file_name = re.search(r'filename *= *"?([^";]+)', file_name)
file_name = re_SEARCH(r'filename *= *"?([^";]+)', file_name)
if file_name:
file_name = file_name.group(1)
@ -569,7 +573,7 @@ class SessionPage(object):
# ----------------获取并设置编码开始-----------------
# 在headers中获取编码
content_type = r.headers.get('content-type', '').lower()
charset = re.search(r'charset[=: ]*(.*)?[;]', content_type)
charset = re_SEARCH(r'charset[=: ]*(.*)?[;]', content_type)
if charset:
r.encoding = charset.group(1)

View File

@ -36,7 +36,7 @@ class ShadowRootElement(DrissionElement):
return 'shadow-root'
@property
def html(self):
def html(self) -> str:
"""内部html文本"""
return format_html(self.inner_ele.get_attribute('innerHTML'))