用存根文件取代类型注解

This commit is contained in:
g1879 2022-12-13 17:08:34 +08:00
parent d210db2844
commit b0dc817ecd
31 changed files with 1184 additions and 1451 deletions

View File

@ -18,8 +18,7 @@ class ActionChains:
self.curr_x = 0 # 视口坐标
self.curr_y = 0
def move_to(self, ele_or_loc,
offset_x: int = 0, offset_y: int = 0) -> 'ActionChains':
def move_to(self, ele_or_loc, offset_x=0, offset_y=0):
"""鼠标移动到元素中点,或页面上的某个绝对坐标。可设置偏移量 \n
当带偏移量时偏移量相对于元素左上角坐标
:param ele_or_loc: 元素对象或绝对坐标坐标为tuple(int, int)形式
@ -40,13 +39,13 @@ class ActionChains:
if not _location_in_viewport(self.page, lx, ly):
self.page.scroll.to_location(lx, ly)
cx, cy = _location_to_client(self.page, lx, ly)
cx, cy = location_to_client(self.page, lx, ly)
self._dr.Input.dispatchMouseEvent(type='mouseMoved', x=cx, y=cy, modifiers=self.modifier)
self.curr_x = cx
self.curr_y = cy
return self
def move(self, offset_x: int = 0, offset_y: int = 0) -> 'ActionChains':
def move(self, offset_x=0, offset_y=0):
"""鼠标相对当前位置移动若干位置 \n
:param offset_x: 偏移量x
:param offset_y: 偏移量y
@ -57,7 +56,7 @@ class ActionChains:
self._dr.Input.dispatchMouseEvent(type='mouseMoved', x=self.curr_x, y=self.curr_y, modifiers=self.modifier)
return self
def hold(self, on_ele=None) -> 'ActionChains':
def hold(self, on_ele=None):
"""点击并按住当前坐标或指定元素 \n
:param on_ele: ChromiumElement对象
:return: self
@ -68,7 +67,7 @@ class ActionChains:
x=self.curr_x, y=self.curr_y, modifiers=self.modifier)
return self
def click(self, on_ele=None) -> 'ActionChains':
def click(self, on_ele=None):
"""点击鼠标左键,可先移动到元素上 \n
:param on_ele: ChromiumElement元素
:return: self
@ -81,7 +80,7 @@ class ActionChains:
x=self.curr_x, y=self.curr_y, modifiers=self.modifier)
return self
def r_click(self, on_ele=None) -> 'ActionChains':
def r_click(self, on_ele=None):
"""点击鼠标右键,可先移动到元素上 \n
:param on_ele: ChromiumElement元素
:return: self
@ -94,7 +93,7 @@ class ActionChains:
x=self.curr_x, y=self.curr_y, modifiers=self.modifier)
return self
def release(self, on_ele=None) -> 'ActionChains':
def release(self, on_ele=None):
"""释放鼠标左键,可先移动到元素再释放 \n
:param on_ele: ChromiumElement对象
:return: self
@ -105,7 +104,7 @@ class ActionChains:
x=self.curr_x, y=self.curr_y, modifiers=self.modifier)
return self
def scroll(self, delta_x: int = 0, delta_y: int = 0, on_ele=None) -> 'ActionChains':
def scroll(self, delta_x=0, delta_y=0, on_ele=None):
"""滚动鼠标滚轮,可先移动到元素上 \n
:param delta_x: 滚轮变化值x
:param delta_y: 滚轮变化值y
@ -118,23 +117,23 @@ class ActionChains:
deltaX=delta_x, deltaY=delta_y, modifiers=self.modifier)
return self
def up(self, pixel: int) -> 'ActionChains':
def up(self, pixel):
"""鼠标向上移动若干像素"""
return self.move(0, -pixel)
def down(self, pixel: int) -> 'ActionChains':
def down(self, pixel):
"""鼠标向下移动若干像素"""
return self.move(0, pixel)
def left(self, pixel: int) -> 'ActionChains':
def left(self, pixel):
"""鼠标向左移动若干像素"""
return self.move(-pixel, 0)
def right(self, pixel: int) -> 'ActionChains':
def right(self, pixel):
"""鼠标向右移动若干像素"""
return self.move(pixel, 0)
def key_down(self, key) -> 'ActionChains':
def key_down(self, key):
"""按下键盘上的按键 \n
:param key: 按键特殊字符见Keys
:return: self
@ -147,7 +146,7 @@ class ActionChains:
self.page.run_cdp('Input.dispatchKeyEvent', **data)
return self
def key_up(self, key) -> 'ActionChains':
def key_up(self, key):
"""提起键盘上的按键 \n
:param key: 按键特殊字符见Keys
:return: self
@ -160,12 +159,12 @@ class ActionChains:
self.page.run_cdp('Input.dispatchKeyEvent', **data)
return self
def wait(self, second: float) -> 'ActionChains':
def wait(self, second):
"""等待若干秒"""
sleep(second)
return self
def _get_key_data(self, key, action: str) -> dict:
def _get_key_data(self, key, action):
"""获取用于发送的按键信息 \n
:param key: 按键
:param action: 'keyDown' 'keyUp'
@ -187,7 +186,7 @@ class ActionChains:
'isKeypad': description['location'] == 3}
def _location_to_client(page, lx: int, ly: int) -> tuple:
def location_to_client(page, lx, ly):
"""绝对坐标转换为视口坐标"""
scrool_x = page.run_script('return document.documentElement.scrollLeft;')
scrool_y = page.run_script('return document.documentElement.scrollTop;')

View File

@ -1,6 +1,7 @@
# -*- coding:utf-8 -*-
from typing import Union, Tuple
from .chromium_base import ChromiumBase
from .tab import Tab
from .chromium_element import ChromiumElement
from .chromium_page import ChromiumPage
@ -9,7 +10,7 @@ from .chromium_page import ChromiumPage
class ActionChains:
"""用于实现动作链的类"""
def __init__(self, page):
def __init__(self, page:ChromiumBase):
self.page: ChromiumPage = ...
self._dr: Tab = ...
self.curr_x: int = ...
@ -21,15 +22,15 @@ class ActionChains:
def move(self, offset_x: int = ..., offset_y: int = ...) -> 'ActionChains': ...
def hold(self, on_ele=...) -> 'ActionChains': ...
def hold(self, on_ele:ChromiumElement=...) -> 'ActionChains': ...
def click(self, on_ele=...) -> 'ActionChains': ...
def click(self, on_ele:ChromiumElement=...) -> 'ActionChains': ...
def r_click(self, on_ele=...) -> 'ActionChains': ...
def r_click(self, on_ele:ChromiumElement=...) -> 'ActionChains': ...
def release(self, on_ele=...) -> 'ActionChains': ...
def release(self, on_ele:ChromiumElement=...) -> 'ActionChains': ...
def scroll(self, delta_x: int = ..., delta_y: int = ..., on_ele=...) -> 'ActionChains': ...
def scroll(self, delta_x: int = ..., delta_y: int = ..., on_ele:ChromiumElement=...) -> 'ActionChains': ...
def up(self, pixel: int) -> 'ActionChains': ...
@ -39,13 +40,13 @@ class ActionChains:
def right(self, pixel: int) -> 'ActionChains': ...
def key_down(self, key) -> 'ActionChains': ...
def key_down(self, key:str) -> 'ActionChains': ...
def key_up(self, key) -> 'ActionChains': ...
def key_up(self, key:str) -> 'ActionChains': ...
def wait(self, second: float) -> 'ActionChains': ...
def _get_key_data(self, key, action: str) -> dict: ...
def _get_key_data(self, key:str, action: str) -> dict: ...
def _location_to_client(page, lx: int, ly: int) -> tuple: ...
def location_to_client(page, lx: int, ly: int) -> tuple: ...

View File

@ -21,7 +21,7 @@ class BaseParser(object):
def ele(self, loc_or_ele, timeout=None):
return self._ele(loc_or_ele, timeout, True)
def eles(self, loc_or_str: Union[Tuple[str, str], str], timeout=None):
def eles(self, loc_or_str, timeout=None):
return self._ele(loc_or_str, timeout, False)
# ----------------以下属性或方法待后代实现----------------
@ -56,19 +56,19 @@ class BaseElement(BaseParser):
return True
@abstractmethod
def _ele(self, loc_or_ele, timeout=None, single=True, relative=False):
def _ele(self, loc_or_str, timeout=None, single=True, relative=False):
pass
def parent(self, level_or_loc: Union[tuple, str, int] = 1):
def parent(self, level_or_loc = 1):
pass
def prev(self, index: int = 1) -> None:
def prev(self, index = 1) -> None:
return None # ShadowRootElement直接继承
def prevs(self) -> None:
return None # ShadowRootElement直接继承
def next(self, index: int = 1):
def next(self, index = 1):
pass
def nexts(self):
@ -290,7 +290,7 @@ class DrissionElement(BaseElement):
class BasePage(BaseParser):
"""页面类的基类"""
def __init__(self, timeout: float = 10):
def __init__(self, timeout = 10):
"""初始化函数"""
self._url = None
self.timeout = timeout
@ -299,32 +299,32 @@ class BasePage(BaseParser):
self._url_available = None
@property
def title(self) -> Union[str, None]:
def title(self):
"""返回网页title"""
ele = self.ele('xpath://title')
return ele.text if ele else None
@property
def timeout(self) -> float:
def timeout(self):
"""返回查找元素时等待的秒数"""
return self._timeout
@timeout.setter
def timeout(self, second: float) -> None:
def timeout(self, second):
"""设置查找元素时等待的秒数"""
self._timeout = second
@property
def cookies(self) -> dict:
def cookies(self):
"""返回cookies"""
return self.get_cookies(True)
@property
def url_available(self) -> bool:
def url_available(self):
"""返回当前访问的url有效性"""
return self._url_available
def _before_connect(self, url: str, retry: int, interval: float) -> tuple:
def _before_connect(self, url, retry, interval):
"""连接前的准备 \n
:param url: 要访问的url
:param retry: 重试次数
@ -346,13 +346,9 @@ class BasePage(BaseParser):
return
@abstractmethod
def get_cookies(self, as_dict: bool = False):
def get_cookies(self, as_dict= False):
return {}
@abstractmethod
def get(self,
url: str,
show_errmsg: bool = False,
retry: int = None,
interval: float = None):
def get(self, url, show_errmsg= False, retry = None, interval= None):
pass

View File

@ -2,18 +2,13 @@
from abc import abstractmethod
from typing import Union, Tuple, List
from selenium.webdriver.remote.webelement import WebElement
from .driver_page import DriverPage
from .mix_page import MixPage
class BaseParser(object):
"""所有页面、元素类的基类"""
def __call__(self, loc_or_str): ...
def __call__(self, loc_or_str: Union[Tuple[str, str], str]): ...
def ele(self, loc_or_ele, timeout=...): ...
def ele(self, loc_or_ele: Union[Tuple[str, str], str, BaseElement], timeout:float=...): ...
def eles(self, loc_or_str: Union[Tuple[str, str], str], timeout=...): ...
@ -21,12 +16,12 @@ class BaseParser(object):
@property
def html(self) -> str: ...
def s_ele(self, loc_or_ele): ...
def s_ele(self, loc_or_ele: Union[Tuple[str, str], str, BaseElement]): ...
def s_eles(self, loc_or_str): ...
def s_eles(self, loc_or_str: Union[Tuple[str, str], str]): ...
@abstractmethod
def _ele(self, loc_or_ele, timeout=..., single=...): ...
def _ele(self, loc_or_ele, timeout:float=..., single:bool=...): ...
class BaseElement(BaseParser):
@ -37,31 +32,23 @@ class BaseElement(BaseParser):
# ----------------以下属性或方法由后代实现----------------
@property
def tag(self):
...
def tag(self)->str: ...
@property
def is_valid(self):
...
def is_valid(self)->bool: ...
@abstractmethod
def _ele(self, loc_or_ele, timeout=..., single=..., relative=...):
...
def _ele(self, loc_or_str: Union[Tuple[str, str], str], timeout:float=..., single:bool=..., relative:bool=...): ...
def parent(self, level_or_loc: Union[tuple, str, int] = ...):
...
def parent(self, level_or_loc: Union[tuple, str, int] = ...): ...
def prev(self, index: int = ...) -> None:
...
def prev(self, index: int = ...) -> None: ...
def prevs(self) -> None:
...
def prevs(self) -> None: ...
def next(self, index: int = ...):
...
def next(self, index: int = ...): ...
def nexts(self):
...
def nexts(self): ...
class DrissionElement(BaseElement):
@ -72,98 +59,78 @@ class DrissionElement(BaseElement):
self.page: BasePage = ...
@property
def link(self) -> str:
...
def link(self) -> str: ...
@property
def css_path(self) -> str:
...
def css_path(self) -> str: ...
@property
def xpath(self) -> str:
...
def xpath(self) -> str: ...
@property
def comments(self) -> list:
...
def comments(self) -> list: ...
def texts(self, text_node_only: bool = ...) -> list:
...
def texts(self, text_node_only: bool = ...) -> list: ...
def parent(self, level_or_loc: Union[tuple, str, int] = ...) -> Union['DrissionElement', None]:
...
def parent(self, level_or_loc: Union[tuple, str, int] = ...) -> Union['DrissionElement', None]: ...
def prev(self,
index: int = ...,
filter_loc: Union[tuple, str] = ...,
timeout: float = ...) -> Union['DrissionElement', str, None]:
...
timeout: float = ...) -> Union['DrissionElement', str, None]: ...
def next(self,
index: int = ...,
filter_loc: Union[tuple, str] = ...,
timeout: float = ...) -> Union['DrissionElement', str, None]:
...
timeout: float = ...) -> Union['DrissionElement', str, None]: ...
def before(self,
index: int = ...,
filter_loc: Union[tuple, str] = ...,
timeout: float = ...) -> Union['DrissionElement', str, None]:
...
timeout: float = ...) -> Union['DrissionElement', str, None]: ...
def after(self,
index: int = ...,
filter_loc: Union[tuple, str] = ...,
timeout: float = ...) -> Union['DrissionElement', str, None]:
...
timeout: float = ...) -> Union['DrissionElement', str, None]: ...
def prevs(self,
filter_loc: Union[tuple, str] = ...,
timeout: float = ...) -> List[Union['DrissionElement', str]]:
...
timeout: float = ...) -> List[Union['DrissionElement', str]]: ...
def nexts(self,
filter_loc: Union[tuple, str] = ...,
timeout: float = ...) -> List[Union['DrissionElement', str]]:
...
timeout: float = ...) -> List[Union['DrissionElement', str]]: ...
def befores(self,
filter_loc: Union[tuple, str] = ...,
timeout: float = ...) -> List[Union['DrissionElement', str]]:
...
timeout: float = ...) -> List[Union['DrissionElement', str]]: ...
def afters(self,
filter_loc: Union[tuple, str] = ...,
timeout: float = ...) -> List[Union['DrissionElement', str]]:
...
timeout: float = ...) -> List[Union['DrissionElement', str]]: ...
def _get_brothers(self,
index: int = ...,
filter_loc: Union[tuple, str] = ...,
direction: str = ...,
brother: bool = ...,
timeout: float = ...) -> List[Union['DrissionElement', str]]:
...
timeout: float = ...) -> List[Union['DrissionElement', str]]: ...
# ----------------以下属性或方法由后代实现----------------
@property
def attrs(self) -> dict:
...
def attrs(self) -> dict: ...
@property
def text(self) -> str:
...
def text(self) -> str: ...
@property
def raw_text(self) -> str:
...
def raw_text(self) -> str: ...
@abstractmethod
def attr(self, attr: str) -> str:
...
def attr(self, attr: str) -> str: ...
def _get_ele_path(self, mode) -> str:
...
def _get_ele_path(self, mode) -> str: ...
class BasePage(BaseParser):
@ -176,45 +143,35 @@ class BasePage(BaseParser):
self._timeout = float = ...
@property
def title(self) -> Union[str, None]:
...
def title(self) -> Union[str, None]: ...
@property
def timeout(self) -> float:
...
def timeout(self) -> float: ...
@timeout.setter
def timeout(self, second: float) -> None:
...
def timeout(self, second: float) -> None: ...
@property
def cookies(self) -> dict:
...
def cookies(self) -> dict: ...
@property
def url_available(self) -> bool:
...
def url_available(self) -> bool: ...
def _before_connect(self, url: str, retry: int, interval: float) -> tuple:
...
def _before_connect(self, url: str, retry: int, interval: float) -> tuple: ...
# ----------------以下属性或方法由后代实现----------------
@property
def url(self):
...
def url(self) -> str: ...
@property
def json(self):
...
def json(self) -> dict: ...
@abstractmethod
def get_cookies(self, as_dict: bool = ...):
...
def get_cookies(self, as_dict: bool = ...) -> Union[list, dict]: ...
@abstractmethod
def get(self,
url: str,
show_errmsg: bool = ...,
retry: int = ...,
interval: float = ...):
...
interval: float = ...): ...

View File

@ -2,29 +2,24 @@
from json import loads
from re import search
from time import perf_counter, sleep
from typing import Union, Tuple, List, Any
from urllib.parse import urlparse
from requests import Session
from requests.cookies import RequestsCookieJar
from .base import BasePage
from .chromium_element import ChromiumElementWaiter, ChromeScroll, ChromiumElement, _run_script
from .chromium_element import ChromiumElementWaiter, ChromeScroll, ChromiumElement, run_script
from .common import get_loc
from .config import DriverOptions, _cookies_to_tuple
from .session_element import SessionElement, make_session_ele
from .config import cookies_to_tuple
from .session_element import make_session_ele
from .tab import Tab
class ChromiumBase(BasePage):
"""标签页、frame、页面基类"""
def __init__(self,
address: str,
tab_id: str = None,
timeout: float = None):
def __init__(self, address, tab_id=None, timeout=None):
"""初始化 \n
:param address: 浏览器地址:端口
:param address: 浏览器 ip:port
:param tab_id: 要控制的标签页id不指定默认为激活的
:param timeout: 超时时间
"""
@ -34,9 +29,7 @@ class ChromiumBase(BasePage):
self._debug = False
self._connect_browser(address, tab_id)
def _connect_browser(self,
addr_tab_opts: Union[str, Tab, DriverOptions] = None,
tab_id: str = None) -> None:
def _connect_browser(self, addr_tab_opts=None, tab_id=None):
"""连接浏览器,在第一次时运行 \n
:param addr_tab_opts: 浏览器地址Tab对象或DriverOptions对象
:param tab_id: 要控制的标签页id不指定默认为激活的
@ -57,7 +50,7 @@ class ChromiumBase(BasePage):
self._init_page(tab_id)
self._get_document()
def _init_page(self, tab_id: str = None) -> None:
def _init_page(self, tab_id=None):
"""新建页面、页面刷新、切换标签页后要进行的cdp参数初始化
:param tab_id: 要跳转到的标签页id
:return: None
@ -77,7 +70,7 @@ class ChromiumBase(BasePage):
self._tab_obj.Page.loadEventFired = self._onLoadEventFired
self._tab_obj.Page.frameNavigated = self._onFrameNavigated
def _get_document(self) -> None:
def _get_document(self):
"""刷新cdp使用的document数据"""
if not self._is_reading:
self._is_reading = True
@ -89,7 +82,7 @@ class ChromiumBase(BasePage):
self._is_loading = False
self._is_reading = False
def _wait_loading(self, timeout: float = None) -> bool:
def _wait_loading(self, timeout=None):
"""等待页面加载完成
:param timeout: 超时时间
:return: 是否成功超时返回False
@ -147,11 +140,10 @@ class ChromiumBase(BasePage):
if self._debug and not kwargs['frame'].get('parentId', None):
print('navigated')
def _set_options(self) -> None:
def _set_options(self):
pass
def __call__(self, loc_or_str: Union[Tuple[str, str], str, 'ChromiumElement'],
timeout: float = None) -> Union['ChromiumElement', 'ChromiumFrame', None]:
def __call__(self, loc_or_str, timeout=None):
"""在内部查找元素 \n
ele = page('@id=ele_id') \n
:param loc_or_str: 元素的定位信息可以是loc元组或查询字符串
@ -161,7 +153,7 @@ class ChromiumBase(BasePage):
return self.ele(loc_or_str, timeout)
@property
def driver(self) -> Tab:
def driver(self):
"""返回用于控制浏览器的Tab对象"""
return self._tab_obj
@ -170,69 +162,69 @@ class ChromiumBase(BasePage):
return self._tab_obj
@property
def _wait_driver(self) -> Tab:
def _wait_driver(self):
"""返回用于控制浏览器的Tab对象会先等待页面加载完毕"""
while self._is_loading:
sleep(.1)
return self._tab_obj
@property
def is_loading(self) -> bool:
def is_loading(self):
"""返回页面是否正在加载状态"""
return self._is_loading
@property
def url(self) -> str:
def url(self):
"""返回当前页面url"""
json = self._control_session.get(f'http://{self.address}/json').json()
return [i['url'] for i in json if i['id'] == self._tab_obj.id][0] # change_mode要调用不能用_driver
@property
def html(self) -> str:
def html(self):
"""返回当前页面html文本"""
node_id = self._wait_driver.DOM.getDocument()['root']['nodeId']
return self._wait_driver.DOM.getOuterHTML(nodeId=node_id)['outerHTML']
@property
def json(self) -> dict:
def json(self):
"""当返回内容是json格式时返回对应的字典"""
return loads(self('t:pre').text)
@property
def tab_id(self) -> str:
def tab_id(self):
"""返回当前标签页id"""
return self.driver.id if self.driver.status == 'started' else ''
@property
def ready_state(self) -> str:
def ready_state(self):
"""返回当前页面加载状态,'loading' 'interactive' 'complete'"""
return self._tab_obj.Runtime.evaluate(expression='document.readyState;')['result']['value']
@property
def size(self) -> dict:
def size(self):
"""返回页面总长宽,{'height': int, 'width': int}"""
w = self.run_script('document.body.scrollWidth;', as_expr=True)
h = self.run_script('document.body.scrollHeight;', as_expr=True)
return {'height': h, 'width': w}
@property
def active_ele(self) -> ChromiumElement:
def active_ele(self):
"""返回当前焦点所在元素"""
return self.run_script('return document.activeElement;')
@property
def page_load_strategy(self) -> str:
def page_load_strategy(self):
"""返回页面加载策略"""
return self._page_load_strategy
@property
def scroll(self) -> 'ChromeScroll':
def scroll(self):
"""返回用于滚动滚动条的对象"""
if not hasattr(self, '_scroll'):
self._scroll = ChromeScroll(self)
return self._scroll
def set_page_load_strategy(self, value: str) -> None:
def set_page_load_strategy(self, value):
"""设置页面加载策略 \n
:param value: 可选'normal', 'eager', 'none'
:return: None
@ -241,7 +233,7 @@ class ChromiumBase(BasePage):
raise ValueError("只能选择'normal', 'eager', 'none'")
self._page_load_strategy = value
def set_timeouts(self, implicit: float = None, page_load: float = None, script: float = None) -> None:
def set_timeouts(self, implicit=None, page_load=None, script=None):
"""设置超时时间,单位为秒 \n
:param implicit: 查找元素超时时间
:param page_load: 页面加载超时时间
@ -257,16 +249,16 @@ class ChromiumBase(BasePage):
if script is not None:
self.timeouts.script = script
def run_script(self, script: str, as_expr: bool = False, *args: Any) -> Any:
def run_script(self, script, as_expr=False, *args):
"""运行javascript代码 \n
:param script: js文本
:param as_expr: 是否作为表达式运行为True时args无效
:param args: 参数按顺序在js文本中对应argument[0]argument[2]...
:return: 运行的结果
"""
return _run_script(self, script, as_expr, self.timeouts.script, args)
return run_script(self, script, as_expr, self.timeouts.script, args)
def run_async_script(self, script: str, as_expr: bool = False, *args: Any) -> None:
def run_async_script(self, script, as_expr=False, *args):
"""以异步方式执行js代码 \n
:param script: js文本
:param as_expr: 是否作为表达式运行为True时args无效
@ -274,14 +266,9 @@ class ChromiumBase(BasePage):
:return: None
"""
from threading import Thread
Thread(target=_run_script, args=(self, script, as_expr, self.timeouts.script, args)).start()
Thread(target=run_script, args=(self, script, as_expr, self.timeouts.script, args)).start()
def get(self,
url: str,
show_errmsg: bool = False,
retry: int = None,
interval: float = None,
timeout: float = None) -> Union[None, bool]:
def get(self, url, show_errmsg=False, retry=None, interval=None, timeout=None):
"""访问url \n
:param url: 目标url
:param show_errmsg: 是否显示和抛出异常
@ -293,13 +280,7 @@ class ChromiumBase(BasePage):
self._url_available = self._get(url, show_errmsg, retry, interval, timeout)
return self._url_available
def _get(self,
url: str,
show_errmsg: bool = False,
retry: int = None,
interval: float = None,
timeout: float = None,
frame_id: str = None) -> Union[None, bool]:
def _get(self, url: str, show_errmsg=False, retry=None, interval=None, timeout=None, frame_id=None):
"""访问url \n
:param url: 目标url
:param show_errmsg: 是否显示和抛出异常
@ -316,7 +297,7 @@ class ChromiumBase(BasePage):
timeout=timeout,
frame_id=frame_id)
def get_cookies(self, as_dict: bool = False) -> Union[list, dict]:
def get_cookies(self, as_dict=False):
"""获取cookies信息 \n
:param as_dict: 为True时返回由{name: value}键值对组成的dict
:return: cookies信息
@ -327,12 +308,12 @@ class ChromiumBase(BasePage):
else:
return cookies
def set_cookies(self, cookies: Union[RequestsCookieJar, list, tuple, str, dict]) -> None:
def set_cookies(self, cookies):
"""设置cookies值 \n
:param cookies: cookies信息
:return: None
"""
cookies = _cookies_to_tuple(cookies)
cookies = cookies_to_tuple(cookies)
result_cookies = []
for cookie in cookies:
if not cookie.get('domain', None):
@ -350,9 +331,7 @@ class ChromiumBase(BasePage):
# """
# self.run_cdp('Network.setExtraHTTPHeaders', headers=headers)
def ele(self,
loc_or_ele: Union[Tuple[str, str], str, ChromiumElement, 'ChromiumFrame'],
timeout: float = None) -> Union[ChromiumElement, 'ChromiumFrame', None]:
def ele(self, loc_or_ele, timeout=None):
"""获取第一个符合条件的元素对象 \n
:param loc_or_ele: 定位符或元素对象
:param timeout: 查找超时时间
@ -360,9 +339,7 @@ class ChromiumBase(BasePage):
"""
return self._ele(loc_or_ele, timeout=timeout)
def eles(self,
loc_or_ele: Union[Tuple[str, str], str],
timeout: float = None) -> List[Union[ChromiumElement, 'ChromiumFrame']]:
def eles(self, loc_or_ele, timeout=None):
"""获取所有符合条件的元素对象 \n
:param loc_or_ele: 定位符或元素对象
:param timeout: 查找超时时间
@ -370,8 +347,7 @@ class ChromiumBase(BasePage):
"""
return self._ele(loc_or_ele, timeout=timeout, single=False)
def s_ele(self, loc_or_ele: Union[Tuple[str, str], str, ChromiumElement] = None) \
-> Union[SessionElement, str, None]:
def s_ele(self, loc_or_ele=None):
"""查找第一个符合条件的元素以SessionElement形式返回处理复杂页面时效率很高 \n
:param loc_or_ele: 元素的定位信息可以是loc元组或查询字符串
:return: SessionElement对象或属性文本
@ -381,17 +357,14 @@ class ChromiumBase(BasePage):
else:
return make_session_ele(self, loc_or_ele)
def s_eles(self, loc_or_str: Union[Tuple[str, str], str] = None) -> List[Union[SessionElement, str]]:
def s_eles(self, loc_or_str=None):
"""查找所有符合条件的元素以SessionElement列表形式返回 \n
:param loc_or_str: 元素的定位信息可以是loc元组或查询字符串
:return: SessionElement对象组成的列表
"""
return make_session_ele(self, loc_or_str, single=False)
def _ele(self,
loc_or_ele: Union[Tuple[str, str], str, ChromiumElement, 'ChromiumFrame'],
timeout: float = None, single: bool = True, relative: bool = False) \
-> Union[ChromiumElement, 'ChromiumFrame', None, List[Union[ChromiumElement, 'ChromiumFrame']]]:
def _ele(self, loc_or_ele, timeout=None, single=True, relative=False):
"""执行元素查找
:param loc_or_ele: 定位符或元素对象
:param timeout: 查找超时时间
@ -434,9 +407,7 @@ class ChromiumBase(BasePage):
return eles[0] if single else eles
def wait_ele(self,
loc_or_ele: Union[str, tuple, ChromiumElement],
timeout: float = None) -> 'ChromiumElementWaiter':
def wait_ele(self, loc_or_ele, timeout=None):
"""返回用于等待元素到达某个状态的等待器对象 \n
:param loc_or_ele: 可以是元素查询字符串loc元组
:param timeout: 等待超时时间
@ -444,7 +415,7 @@ class ChromiumBase(BasePage):
"""
return ChromiumElementWaiter(self, loc_or_ele, timeout)
def scroll_to_see(self, loc_or_ele: Union[str, tuple, ChromiumElement]) -> None:
def scroll_to_see(self, loc_or_ele):
"""滚动页面直到元素可见 \n
:param loc_or_ele: 元素的定位信息可以是loc元组或查询字符串详见ele函数注释
:return: None
@ -455,7 +426,7 @@ class ChromiumBase(BasePage):
except Exception:
self.ele(loc_or_ele).run_script("this.scrollIntoView();")
def refresh(self, ignore_cache: bool = False) -> None:
def refresh(self, ignore_cache=False):
"""刷新当前页面 \n
:param ignore_cache: 是否忽略缓存
:return: None
@ -463,21 +434,21 @@ class ChromiumBase(BasePage):
self._is_loading = True
self._driver.Page.reload(ignoreCache=ignore_cache)
def forward(self, steps: int = 1) -> None:
def forward(self, steps=1):
"""在浏览历史中前进若干步 \n
:param steps: 前进步数
:return: None
"""
self._forward_or_back(steps)
def back(self, steps: int = 1) -> None:
def back(self, steps=1):
"""在浏览历史中后退若干步 \n
:param steps: 后退步数
:return: None
"""
self._forward_or_back(-steps)
def _forward_or_back(self, steps: int) -> None:
def _forward_or_back(self, steps):
"""执行浏览器前进或后退会跳过url相同的历史记录
:param steps: 步数
:return: None
@ -503,7 +474,7 @@ class ChromiumBase(BasePage):
self._is_loading = True
self.run_cdp('Page.navigateToHistoryEntry', entryId=nid)
def stop_loading(self) -> None:
def stop_loading(self):
"""页面停止加载"""
if self._debug:
print('阻止页面加载')
@ -512,7 +483,7 @@ class ChromiumBase(BasePage):
sleep(.1)
# self._get_document()
def run_cdp(self, cmd: str, **cmd_args) -> dict:
def run_cdp(self, cmd, **cmd_args):
"""执行Chrome DevTools Protocol语句 \n
:param cmd: 协议项目
:param cmd_args: 参数
@ -525,14 +496,14 @@ class ChromiumBase(BasePage):
raise RuntimeError('该元素已不在当前页面中。')
raise
def set_user_agent(self, ua: str) -> None:
def set_user_agent(self, ua):
"""为当前tab设置user agent只在当前tab有效 \n
:param ua: user agent字符串
:return: None
"""
self._wait_driver.Network.setUserAgentOverride(userAgent=ua)
def get_session_storage(self, item: str = None) -> Union[str, dict, None]:
def get_session_storage(self, item=None):
"""获取sessionStorage信息不设置item则获取全部 \n
:param item: 要获取的项不设置则返回全部
:return: sessionStorage一个或所有项内容
@ -540,7 +511,7 @@ class ChromiumBase(BasePage):
js = f'sessionStorage.getItem("{item}");' if item else 'sessionStorage;'
return self.run_script(js, as_expr=True)
def get_local_storage(self, item: str = None) -> Union[str, dict, None]:
def get_local_storage(self, item=None):
"""获取localStorage信息不设置item则获取全部 \n
:param item: 要获取的项目不设置则返回全部
:return: localStorage一个或所有项内容
@ -548,7 +519,7 @@ class ChromiumBase(BasePage):
js = f'localStorage.getItem("{item}");' if item else 'localStorage;'
return self.run_script(js, as_expr=True)
def set_session_storage(self, item: str, value: Union[str, bool]) -> None:
def set_session_storage(self, item, value):
"""设置或删除某项sessionStorage信息 \n
:param item: 要设置的项
:param value: 项的值设置为False时删除该项
@ -557,7 +528,7 @@ class ChromiumBase(BasePage):
js = f'sessionStorage.removeItem("{item}");' if item is False else f'sessionStorage.setItem("{item}","{value}");'
return self.run_script(js, as_expr=True)
def set_local_storage(self, item: str, value: Union[str, bool]) -> None:
def set_local_storage(self, item, value):
"""设置或删除某项localStorage信息 \n
:param item: 要设置的项
:param value: 项的值设置为False时删除该项
@ -566,11 +537,7 @@ class ChromiumBase(BasePage):
js = f'localStorage.removeItem("{item}");' if item is False else f'localStorage.setItem("{item}","{value}");'
return self.run_script(js, as_expr=True)
def clear_cache(self,
session_storage: bool = True,
local_storage: bool = True,
cache: bool = True,
cookies: bool = True) -> None:
def clear_cache(self, session_storage=True, local_storage=True, cache=True, cookies=True):
"""清除缓存,可选要清除的项 \n
:param session_storage: 是否清除sessionStorage
:param local_storage: 是否清除localStorage
@ -587,13 +554,7 @@ class ChromiumBase(BasePage):
if cookies:
self._wait_driver.Network.clearBrowserCookies()
def _d_connect(self,
to_url: str,
times: int = 0,
interval: float = 1,
show_errmsg: bool = False,
timeout: float = None,
frame_id: str = None) -> Union[bool, None]:
def _d_connect(self, to_url, times=0, interval=1, show_errmsg=False, timeout=None, frame_id=None):
"""尝试连接,重试若干次 \n
:param to_url: 要访问的url
:param times: 重试次数
@ -644,10 +605,9 @@ class ChromiumBase(BasePage):
class ChromiumFrame(ChromiumBase):
"""实现浏览器frame的类"""
def __init__(self, page,
ele: ChromiumElement):
def __init__(self, page, ele):
"""初始化 \n
:param page: 浏览器地址:端口Tab对象或DriverOptions对象
:param page: 页面对象
:param ele: 页面上的frame元素
"""
self.page = page
@ -655,18 +615,18 @@ class ChromiumFrame(ChromiumBase):
frame_id = page.run_cdp('DOM.describeNode', nodeId=ele.node_id)['node'].get('frameId', None)
super().__init__(page.address, frame_id, page.timeout)
def __repr__(self) -> str:
def __repr__(self):
attrs = self.attrs
attrs = [f"{attr}='{attrs[attr]}'" for attr in attrs]
return f'<ChromiumFrame {self.tag} {" ".join(attrs)}>'
@property
def tag(self) -> str:
def tag(self):
"""返回元素tag"""
return self._inner_ele.tag
@property
def html(self) -> str:
def html(self):
"""返回元素outerHTML文本"""
tag = self.tag
out_html = self.page.run_cdp('DOM.getOuterHTML', nodeId=self._inner_ele.node_id)['outerHTML']
@ -675,53 +635,53 @@ class ChromiumFrame(ChromiumBase):
return f'{sign}{in_html}</{tag}>'
@property
def inner_html(self) -> str:
def inner_html(self):
"""返回元素innerHTML文本"""
return super().html
@property
def attrs(self) -> dict:
def attrs(self):
return self._inner_ele.attrs
@property
def frame_size(self) -> dict:
def frame_size(self):
"""返回frame元素大小"""
return self._inner_ele.size
def _set_options(self) -> None:
def _set_options(self):
self.set_timeouts(page_load=self.page.timeouts.page_load,
script=self.page.timeouts.script,
implicit=self.page.timeouts.implicit if self.timeout is None else self.timeout)
self._page_load_strategy = self.page.page_load_strategy
@property
def obj_id(self) -> str:
def obj_id(self):
"""返回js中的object id"""
return self._inner_ele.obj_id
@property
def node_id(self) -> str:
def node_id(self):
"""返回cdp中的node id"""
return self._inner_ele.node_id
@property
def location(self) -> dict:
def location(self):
"""返回frame元素左上角的绝对坐标"""
return self._inner_ele.location
@property
def is_displayed(self) -> bool:
def is_displayed(self):
"""返回frame元素是否显示"""
return self._inner_ele.is_displayed
def attr(self, attr: str) -> Union[str, None]:
def attr(self, attr):
"""返回frame元素attribute属性值 \n
:param attr: 属性名
:return: 属性值文本没有该属性返回None
"""
return self._inner_ele.attr(attr)
def set_attr(self, attr: str, value: str) -> None:
def set_attr(self, attr, value):
"""设置frame元素attribute属性 \n
:param attr: 属性名
:param value: 属性值
@ -729,24 +689,21 @@ class ChromiumFrame(ChromiumBase):
"""
self._inner_ele.set_attr(attr, value)
def remove_attr(self, attr: str) -> None:
def remove_attr(self, attr):
"""删除frame元素attribute属性 \n
:param attr: 属性名
:return: None
"""
self._inner_ele.remove_attr(attr)
def parent(self, level_or_loc: Union[tuple, str, int] = 1) -> Union['ChromiumElement', None]:
def parent(self, level_or_loc=1):
"""返回上面某一级父元素,可指定层数或用查询语法定位 \n
:param level_or_loc: 第几级父元素或定位符
:return: 上级元素对象
"""
return self._inner_ele.parent(level_or_loc)
def prev(self,
index: int = 1,
filter_loc: Union[tuple, str] = '',
timeout: float = 0) -> Union['ChromiumElement', str, None]:
def prev(self, index=1, filter_loc='', timeout=0):
"""返回前面的一个兄弟元素,可用查询语法筛选,可指定返回筛选结果的第几个 \n
:param index: 前面第几个查询结果元素
:param filter_loc: 用于筛选元素的查询语法
@ -755,10 +712,7 @@ class ChromiumFrame(ChromiumBase):
"""
return self._inner_ele.prev(index, filter_loc, timeout)
def next(self,
index: int = 1,
filter_loc: Union[tuple, str] = '',
timeout: float = 0) -> Union['ChromiumElement', str, None]:
def next(self, index=1, filter_loc='', timeout=0):
"""返回后面的一个兄弟元素,可用查询语法筛选,可指定返回筛选结果的第几个 \n
:param index: 后面第几个查询结果元素
:param filter_loc: 用于筛选元素的查询语法
@ -767,10 +721,7 @@ class ChromiumFrame(ChromiumBase):
"""
return self._inner_ele.next(index, filter_loc, timeout)
def before(self,
index: int = 1,
filter_loc: Union[tuple, str] = '',
timeout: float = None) -> Union['ChromiumElement', str, None]:
def before(self, index=1, filter_loc='', timeout=None):
"""返回当前元素前面的一个元素可指定筛选条件和第几个。查找范围不限兄弟元素而是整个DOM文档 \n
:param index: 前面第几个查询结果元素
:param filter_loc: 用于筛选元素的查询语法
@ -779,10 +730,7 @@ class ChromiumFrame(ChromiumBase):
"""
return self._inner_ele.before(index, filter_loc, timeout)
def after(self,
index: int = 1,
filter_loc: Union[tuple, str] = '',
timeout: float = None) -> Union['ChromiumElement', str, None]:
def after(self, index=1, filter_loc='', timeout=None):
"""返回当前元素后面的一个元素可指定筛选条件和第几个。查找范围不限兄弟元素而是整个DOM文档 \n
:param index: 后面第几个查询结果元素
:param filter_loc: 用于筛选元素的查询语法
@ -791,9 +739,7 @@ class ChromiumFrame(ChromiumBase):
"""
return self._inner_ele.after(index, filter_loc, timeout)
def prevs(self,
filter_loc: Union[tuple, str] = '',
timeout: float = 0) -> List[Union['ChromiumElement', str]]:
def prevs(self, filter_loc='', timeout=0):
"""返回前面全部兄弟元素或节点组成的列表,可用查询语法筛选 \n
:param filter_loc: 用于筛选元素的查询语法
:param timeout: 查找元素的超时时间
@ -801,9 +747,7 @@ class ChromiumFrame(ChromiumBase):
"""
return self._inner_ele.prevs(filter_loc, timeout)
def nexts(self,
filter_loc: Union[tuple, str] = '',
timeout: float = 0) -> List[Union['ChromiumElement', str]]:
def nexts(self, filter_loc='', timeout=0):
"""返回后面全部兄弟元素或节点组成的列表,可用查询语法筛选 \n
:param filter_loc: 用于筛选元素的查询语法
:param timeout: 查找元素的超时时间
@ -811,9 +755,7 @@ class ChromiumFrame(ChromiumBase):
"""
return self._inner_ele.nexts(filter_loc, timeout)
def befores(self,
filter_loc: Union[tuple, str] = '',
timeout: float = None) -> List[Union['ChromiumElement', str]]:
def befores(self, filter_loc='', timeout=None):
"""返回当前元素后面符合条件的全部兄弟元素或节点组成的列表可用查询语法筛选。查找范围不限兄弟元素而是整个DOM文档 \n
:param filter_loc: 用于筛选元素的查询语法
:param timeout: 查找元素的超时时间

View File

@ -30,6 +30,7 @@ class ChromiumBase(BasePage):
self._page_load_strategy: str = ...
self._scroll: ChromeScroll = ...
self._url: str = ...
self._root_id: str = ...
def _connect_browser(self,
addr_tab_opts: Union[str, Tab, DriverOptions] = ...,
@ -60,7 +61,7 @@ class ChromiumBase(BasePage):
def driver(self) -> Tab: ...
@property
def _driver(self): ...
def _driver(self) -> Tab: ...
@property
def _wait_driver(self) -> Tab: ...
@ -186,7 +187,7 @@ class ChromiumBase(BasePage):
class ChromiumFrame(ChromiumBase):
"""实现浏览器frame的类"""
def __init__(self, page,
def __init__(self, page: ChromiumBase,
ele: ChromiumElement):
self._inner_ele: ChromiumElement = ...
self.page: ChromiumBase = ...

File diff suppressed because it is too large Load Diff

View File

@ -19,8 +19,8 @@ class ChromiumElement(DrissionElement):
def __init__(self,
page: ChromiumBase,
node_id: str = None,
obj_id: str = None):
node_id: str = ...,
obj_id: str = ...):
self._tag: str = ...
self.page: Union[ChromiumPage, WebPage] = ...
self._node_id: str = ...
@ -181,9 +181,8 @@ class ChromiumElement(DrissionElement):
def _ele(self,
loc_or_str: Union[Tuple[str, str], str],
timeout: float = ..., single: bool = ..., relative=...) \
-> Union['ChromiumElement', str, None,
List[Union['ChromiumElement', str]]]: ...
timeout: float = ..., single: bool = ..., relative: bool = ...) \
-> Union['ChromiumElement', str, None, List[Union['ChromiumElement', str]]]: ...
def style(self, style: str, pseudo_ele: str = ...) -> str: ...
@ -236,11 +235,10 @@ class ChromiumShadowRootElement(BaseElement):
parent_ele: ChromiumElement,
obj_id: str = ...,
backend_id: str = ...):
self._obj_id:str=...
self._node_id:str=...
self.page:ChromiumPage=...
self.parent_ele:ChromiumElement=...
self._obj_id: str = ...
self._node_id: str = ...
self.page: ChromiumPage = ...
self.parent_ele: ChromiumElement = ...
def __repr__(self) -> str: ...
@ -300,34 +298,34 @@ class ChromiumShadowRootElement(BaseElement):
loc_or_str: Union[Tuple[str, str], str],
timeout: float = ...) -> List[ChromiumElement]: ...
def s_ele(self, loc_or_ele=...) -> Union[SessionElement, str, None]: ...
def s_ele(self, loc_or_str: Union[Tuple[str, str], str]=...) -> Union[SessionElement, str, None]: ...
def s_eles(self, loc_or_ele) -> List[SessionElement]: ...
def s_eles(self, loc_or_str: Union[Tuple[str, str], str]) -> List[SessionElement]: ...
def _ele(self,
loc_or_str: Union[Tuple[str, str], str],
timeout: float = ...,
single: bool = ..., relative=...) -> Union['ChromiumElement', None, List[ChromiumElement]]: ...
single: bool = ..., relative: bool =...) -> Union['ChromiumElement', None, List[ChromiumElement]]: ...
def _get_node_id(self, obj_id) -> str: ...
def _get_node_id(self, obj_id:str) -> str: ...
def _get_obj_id(self, back_id) -> str: ...
def _get_obj_id(self, back_id:str) -> str: ...
def _get_backend_id(self, node_id) -> str: ...
def _get_backend_id(self, node_id:str) -> str: ...
def make_chromium_ele(ele: ChromiumElement,
loc: Union[str, Tuple[str, str]],
single: bool = ...,
timeout: float = ...,
relative=...) -> Union[ChromiumElement, str, None, List[Union[ChromiumElement, str]]]: ...
relative: bool =...) -> Union[ChromiumElement, str, None, List[Union[ChromiumElement, str]]]: ...
def _find_by_xpath(ele: ChromiumElement,
xpath: str,
single: bool,
timeout: float,
relative=...) -> Union[ChromiumElement, List[ChromiumElement], None]: ...
relative: bool = ...) -> Union[ChromiumElement, List[ChromiumElement], None]: ...
def _find_by_css(ele: ChromiumElement,
@ -336,16 +334,17 @@ def _find_by_css(ele: ChromiumElement,
timeout: float) -> Union[ChromiumElement, List[ChromiumElement], None]: ...
def _make_chromium_ele(page, node_id: str = ..., obj_id: str = ...): ...
def _make_chromium_ele(page: ChromiumBase, node_id: str = ..., obj_id: str = ...) -> ChromiumElement: ...
def _make_js_for_find_ele_by_xpath(xpath: str, type_txt: str, node_txt: str) -> str: ...
def _run_script(page_or_ele, script: str, as_expr: bool = ..., timeout: float = ..., args: tuple = ...) -> Any: ...
def run_script(page_or_ele: Union[ChromiumBase, ChromiumElement, ChromiumShadowRootElement], script: str, as_expr: bool = ...,
timeout: float = ..., args: tuple = ...) -> Any: ...
def _parse_js_result(page, ele, result: dict): ...
def _parse_js_result(page: ChromiumBase, ele: ChromiumElement, result: dict): ...
def _convert_argument(arg: Any) -> dict: ...
@ -363,11 +362,11 @@ def _offset_scroll(ele: ChromiumElement, offset_x: int, offset_y: int) -> tuple:
class ChromeScroll(object):
"""用于滚动的对象"""
def __init__(self, page_or_ele):
self.t1 :str=...
self.t2 :str=...
self.obj_id:str=...
self.page:ChromiumPage=...
def __init__(self, page_or_ele: Union[ChromiumBase, ChromiumElement]):
self.t1: str = ...
self.t2: str = ...
self.obj_id: str = ...
self.page: ChromiumPage = ...
def _run_script(self, js: str): ...
@ -396,10 +395,9 @@ class ChromeSelect(object):
"""ChromeSelect 类专门用于处理 d 模式下 select 标签"""
def __init__(self, ele: ChromiumElement):
self._ele:ChromiumElement=...
self._ele: ChromiumElement = ...
def __call__(self, text_or_index: Union[str, int, list, tuple], timeout=None) -> bool: ...
def __call__(self, text_or_index: Union[str, int, list, tuple], timeout: float = None) -> bool: ...
@property
def is_multi(self) -> bool: ...
@ -415,17 +413,17 @@ class ChromeSelect(object):
def clear(self) -> None: ...
def by_text(self, text: Union[str, list, tuple], timeout=...) -> bool: ...
def by_text(self, text: Union[str, list, tuple], timeout: float = ...) -> bool: ...
def by_value(self, value: Union[str, list, tuple], timeout=...) -> bool: ...
def by_value(self, value: Union[str, list, tuple], timeout: float = ...) -> bool: ...
def by_index(self, index: Union[int, list, tuple], timeout=...) -> bool: ...
def by_index(self, index: Union[int, list, tuple], timeout: float = ...) -> bool: ...
def cancel_by_text(self, text: Union[str, list, tuple], timeout=...) -> bool: ...
def cancel_by_text(self, text: Union[str, list, tuple], timeout: float = ...) -> bool: ...
def cancel_by_value(self, value: Union[str, list, tuple], timeout=...) -> bool: ...
def cancel_by_value(self, value: Union[str, list, tuple], timeout: float = ...) -> bool: ...
def cancel_by_index(self, index: Union[int, list, tuple], timeout=...) -> bool: ...
def cancel_by_index(self, index: Union[int, list, tuple], timeout: float = ...) -> bool: ...
def invert(self) -> None: ...
@ -433,7 +431,7 @@ class ChromeSelect(object):
text_value_index: Union[str, int, list, tuple] = ...,
para_type: str = ...,
deselect: bool = ...,
timeout=...) -> bool: ...
timeout: float = ...) -> bool: ...
def _select_multi(self,
text_value_index: Union[list, tuple] = ...,
@ -448,9 +446,9 @@ class ChromiumElementWaiter(object):
page_or_ele,
loc_or_ele: Union[str, tuple, ChromiumElement],
timeout: float = ...):
self.loc_or_ele: Union[str, tuple, ChromiumElement]=...
self.timeout:float=...
self.driver:Union[ChromiumPage, ChromiumPage]=...
self.loc_or_ele: Union[str, tuple, ChromiumElement] = ...
self.timeout: float = ...
self.driver: Union[ChromiumPage, ChromiumPage] = ...
def delete(self) -> bool: ...

View File

@ -3,24 +3,20 @@ from pathlib import Path
from platform import system
from re import search
from time import perf_counter, sleep
from typing import Union, Tuple, List
from requests import Session
from .chromium_base import Timeout, ChromiumBase
from .chromium_tab import ChromiumTab
from .config import DriverOptions
from .common import connect_chrome
from .config import DriverOptions
from .tab import Tab
class ChromiumPage(ChromiumBase):
"""用于管理浏览器的类"""
def __init__(self,
addr_tab_opts: Union[str, Tab, DriverOptions] = None,
tab_id: str = None,
timeout: float = None):
def __init__(self, addr_tab_opts=None, tab_id=None, timeout=None):
"""初始化 \n
:param addr_tab_opts: 浏览器地址:端口Tab对象或DriverOptions对象
:param tab_id: 要控制的标签页id不指定默认为激活的
@ -28,9 +24,7 @@ class ChromiumPage(ChromiumBase):
"""
super().__init__(addr_tab_opts, tab_id, timeout)
def _connect_browser(self,
addr_tab_opts: Union[str, Tab, DriverOptions] = None,
tab_id: str = None) -> None:
def _connect_browser(self, addr_tab_opts=None, tab_id=None):
"""连接浏览器,在第一次时运行 \n
:param addr_tab_opts: 浏览器地址Tab对象或DriverOptions对象
:param tab_id: 要控制的标签页id不指定默认为激活的
@ -79,7 +73,7 @@ class ChromiumPage(ChromiumBase):
self._first_run = False
self.main_tab: str = self.tab_id
def _init_page(self, tab_id: str = None) -> None:
def _init_page(self, tab_id=None):
"""新建页面、页面刷新、切换标签页后要进行的cdp参数初始化
:param tab_id: 要跳转到的标签页id
:return: None
@ -89,26 +83,26 @@ class ChromiumPage(ChromiumBase):
self._tab_obj.Page.javascriptDialogOpening = self._on_alert_open
self._tab_obj.Page.javascriptDialogClosed = self._on_alert_close
def _set_options(self) -> None:
def _set_options(self):
self.set_timeouts(page_load=self.options.timeouts['pageLoad'] / 1000,
script=self.options.timeouts['script'] / 1000,
implicit=self.options.timeouts['implicit'] / 1000 if self.timeout is None else self.timeout)
self._page_load_strategy = self.options.page_load_strategy
@property
def tabs_count(self) -> int:
def tabs_count(self):
"""返回标签页数量"""
return len(self.tabs)
@property
def tabs(self) -> list:
def tabs(self):
"""返回所有标签页id"""
self._driver
json = self._control_session.get(f'http://{self.address}/json').json()
return [i['id'] for i in json if i['type'] == 'page']
@property
def process_id(self) -> Union[None, int]:
def process_id(self):
"""返回浏览器进程id"""
try:
return self._driver.SystemInfo.getProcessInfo()['id']
@ -116,13 +110,13 @@ class ChromiumPage(ChromiumBase):
return None
@property
def set_window(self) -> 'WindowSizeSetter':
def set_window(self):
"""返回用于设置窗口大小的对象"""
if not hasattr(self, '_window_setter'):
self._window_setter = WindowSizeSetter(self)
return self._window_setter
def get_tab(self, tab_id: str = None) -> ChromiumTab:
def get_tab(self, tab_id=None):
"""获取一个标签页对象 \n
:param tab_id: 要获取的标签页id为None时获取当前tab
:return: 标签页对象
@ -130,11 +124,7 @@ class ChromiumPage(ChromiumBase):
tab_id = tab_id or self.tab_id
return ChromiumTab(self, tab_id)
def get_screenshot(self, path: [str, Path] = None,
as_bytes: [bool, str] = None,
full_page: bool = False,
left_top: Tuple[int, int] = None,
right_bottom: Tuple[int, int] = None) -> Union[str, bytes]:
def get_screenshot(self, path=None, as_bytes=None, full_page=False, left_top=None, right_bottom=None):
"""对页面进行截图可对整个网页、可见网页、指定范围截图。对可视范围外截图需要90以上版本浏览器支持 \n
:param path: 完整路径后缀可选'jpg','jpeg','png','webp'
:param as_bytes: 是否已字节形式返回图片可选'jpg','jpeg','png','webp'生效时path参数无效
@ -186,11 +176,11 @@ class ChromiumPage(ChromiumBase):
f.write(png)
return str(path.absolute())
def to_front(self) -> None:
def to_front(self):
"""激活当前标签页使其处于最前面"""
self._control_session.get(f'http://{self.address}/json/activate/{self.tab_id}')
def new_tab(self, url: str = None, switch_to: bool = True) -> None:
def new_tab(self, url=None, switch_to=True):
"""新建并定位到一个标签页,该标签页在最后面 \n
:param url: 新标签页跳转到的网址
:param switch_to: 新建标签页后是否把焦点移过去
@ -214,11 +204,11 @@ class ChromiumPage(ChromiumBase):
else:
self._control_session.get(f'http://{self.address}/json/new')
def to_main_tab(self) -> None:
def to_main_tab(self):
"""跳转到主标签页"""
self.to_tab(self.main_tab)
def to_tab(self, tab_id: str = None, activate: bool = True) -> None:
def to_tab(self, tab_id=None, activate=True):
"""跳转到标签页 \n
:param tab_id: 标签页id字符串默认跳转到main_tab
:param activate: 切换后是否变为活动状态
@ -226,7 +216,7 @@ class ChromiumPage(ChromiumBase):
"""
self._to_tab(tab_id, activate)
def _to_tab(self, tab_id: str = None, activate: bool = True, read_doc: bool = True) -> None:
def _to_tab(self, tab_id=None, activate=True, read_doc=True):
"""跳转到标签页 \n
:param tab_id: 标签页id字符串默认跳转到main_tab
:param activate: 切换后是否变为活动状态
@ -250,7 +240,7 @@ class ChromiumPage(ChromiumBase):
if read_doc and self.ready_state == 'complete':
self._get_document()
def close_tabs(self, tab_ids: Union[str, List[str], Tuple[str]] = None, others: bool = False) -> None:
def close_tabs(self, tab_ids=None, others=False):
"""关闭传入的标签页,默认关闭当前页。可传入多个 \n
:param tab_ids: 要关闭的标签页id可传入id组成的列表或元组为None时关闭当前页
:param others: 是否关闭指定标签页之外的
@ -285,14 +275,14 @@ class ChromiumPage(ChromiumBase):
self.to_tab()
def close_other_tabs(self, tab_ids: Union[str, List[str], Tuple[str]] = None) -> None:
def close_other_tabs(self, tab_ids=None):
"""关闭传入的标签页以外标签页,默认保留当前页。可传入多个 \n
:param tab_ids: 要保留的标签页id可传入id组成的列表或元组为None时保存当前页
:return: None
"""
self.close_tabs(tab_ids, True)
def handle_alert(self, accept: bool = True, send: str = None, timeout: float = None) -> Union[str, None]:
def handle_alert(self, accept=True, send=None, timeout=None):
"""处理提示框,可以自动等待提示框出现 \n
:param accept: True表示确认False表示取消其它值不会按按钮但依然返回文本值
:param send: 处理prompt提示框时可输入文本
@ -313,15 +303,15 @@ class ChromiumPage(ChromiumBase):
self._driver.Page.handleJavaScriptDialog(accept=accept)
return res_text
def hide_browser(self) -> None:
def hide_browser(self):
"""隐藏浏览器窗口只在Windows系统可用"""
_show_or_hide_browser(self, hide=True)
show_or_hide_browser(self, hide=True)
def show_browser(self) -> None:
def show_browser(self):
"""显示浏览器窗口只在Windows系统可用"""
_show_or_hide_browser(self, hide=False)
show_or_hide_browser(self, hide=False)
def quit(self) -> None:
def quit(self):
"""关闭浏览器"""
self._tab_obj.Browser.close()
self._tab_obj.stop()
@ -360,27 +350,27 @@ class Alert(object):
class WindowSizeSetter(object):
"""用于设置窗口大小的类"""
def __init__(self, page: ChromiumPage):
def __init__(self, page):
self.driver = page._driver
self.window_id = self._get_info()['windowId']
def maximized(self) -> None:
def maximized(self):
"""窗口最大化"""
self._perform({'windowState': 'maximized'})
def minimized(self) -> None:
def minimized(self):
"""窗口最小化"""
self._perform({'windowState': 'minimized'})
def fullscreen(self) -> None:
def fullscreen(self):
"""设置窗口为全屏"""
self._perform({'windowState': 'fullscreen'})
def normal(self) -> None:
def normal(self):
"""设置窗口为常规模式"""
self._perform({'windowState': 'normal'})
def new_size(self, width: int = None, height: int = None) -> None:
def new_size(self, width=None, height=None):
"""设置窗口大小 \n
:param width: 窗口宽度
:param height: 窗口高度
@ -392,7 +382,7 @@ class WindowSizeSetter(object):
height = height or info['height']
self._perform({'width': width, 'height': height})
def to_location(self, x: int = None, y: int = None) -> None:
def to_location(self, x=None, y=None):
"""设置窗口在屏幕中的位置,相对左上角坐标 \n
:param x: 距离顶部距离
:param y: 距离左边距离
@ -405,11 +395,11 @@ class WindowSizeSetter(object):
y = y or info['top']
self._perform({'left': x, 'top': y})
def _get_info(self) -> dict:
def _get_info(self):
"""获取窗口位置及大小信息"""
return self.driver.Browser.getWindowBounds()
def _perform(self, bounds: dict) -> None:
def _perform(self, bounds):
"""执行改变窗口大小操作
:param bounds: 控制数据
:return: None
@ -417,7 +407,7 @@ class WindowSizeSetter(object):
self.driver.Browser.setWindowBounds(windowId=self.window_id, bounds=bounds)
def _show_or_hide_browser(page: ChromiumPage, hide: bool = True) -> None:
def show_or_hide_browser(page, hide=True):
"""执行显示或隐藏浏览器窗口
:param page: ChromePage对象
:param hide: 是否隐藏
@ -435,20 +425,20 @@ def _show_or_hide_browser(page: ChromiumPage, hide: bool = True) -> None:
except ImportError:
raise ImportError('请先安装pip install pypiwin32')
pid = page.process_id or _get_browser_progress_id(page.process, page.address)
pid = page.process_id or get_browser_progress_id(page.process, page.address)
if not pid:
return None
hds = _get_chrome_hwnds_from_pid(pid, page.title)
hds = get_chrome_hwnds_from_pid(pid, page.title)
sw = SW_HIDE if hide else SW_SHOW
for hd in hds:
ShowWindow(hd, sw)
def _get_browser_progress_id(progress, address: str) -> Union[str, None]:
def get_browser_progress_id(progress, address):
"""获取浏览器进程id
:param progress: 已知的进程对象没有时传入None
:param address: 浏览器管理地址含端口
:return: 进程id
:return: 进程id或None
"""
if progress:
return progress.pid
@ -467,7 +457,7 @@ def _get_browser_progress_id(progress, address: str) -> Union[str, None]:
return txt.split(' ')[-1]
def _get_chrome_hwnds_from_pid(pid, title) -> list:
def get_chrome_hwnds_from_pid(pid, title):
"""通过PID查询句柄ID
:param pid: 进程id
:param title: 窗口标题

View File

@ -1,4 +1,5 @@
# -*- coding:utf-8 -*-
from os import popen
from pathlib import Path
from typing import Union, Tuple, List
@ -16,6 +17,7 @@ class ChromiumPage(ChromiumBase):
tab_id: str = ...,
timeout: float = ...):
self.options: DriverOptions = ...
self.process: popen = ...
self._window_setter: WindowSizeSetter = ...
self.main_tab: str = ...
self._alert: Alert = ...
@ -111,10 +113,10 @@ class WindowSizeSetter(object):
def _perform(self, bounds: dict) -> None: ...
def _show_or_hide_browser(page: ChromiumPage, hide: bool = ...) -> None: ...
def show_or_hide_browser(page: ChromiumPage, hide: bool = ...) -> None: ...
def _get_browser_progress_id(progress, address: str) -> Union[str, None]: ...
def get_browser_progress_id(progress: Union[popen, None], address: str) -> Union[str, None]: ...
def _get_chrome_hwnds_from_pid(pid, title) -> list: ...
def get_chrome_hwnds_from_pid(pid: str, title: str) -> list: ...

View File

@ -5,9 +5,7 @@ from .chromium_base import ChromiumBase
class ChromiumTab(ChromiumBase):
"""实现浏览器标签页的类"""
def __init__(self,
page,
tab_id=None):
def __init__(self, page, tab_id=None):
"""初始化 \n
:param page: ChromiumPage对象
:param tab_id: 要控制的标签页id不指定默认为激活的
@ -15,7 +13,7 @@ class ChromiumTab(ChromiumBase):
self.page = page
super().__init__(page.address, tab_id, page.timeout)
def _set_options(self) -> None:
def _set_options(self):
self.set_timeouts(page_load=self.page.timeouts.page_load,
script=self.page.timeouts.script,
implicit=self.page.timeouts.implicit if self.timeout is None else self.timeout)

View File

@ -1,5 +1,4 @@
# -*- coding:utf-8 -*-
from .chromium_base import ChromiumBase
from .chromium_page import ChromiumPage

View File

@ -15,7 +15,6 @@ from typing import Union
from zipfile import ZipFile
from urllib.parse import urlparse, urljoin, urlunparse
from requests import get as requests_get
from requests.exceptions import ConnectionError as requests_connection_err
from .config import DriverOptions

View File

@ -8,7 +8,6 @@
from configparser import RawConfigParser, NoSectionError, NoOptionError
from http.cookiejar import Cookie
from pathlib import Path
from typing import Any, Union, List
from requests.cookies import RequestsCookieJar
from selenium.webdriver.chrome.options import Options
@ -17,7 +16,7 @@ from selenium.webdriver.chrome.options import Options
class OptionsManager(object):
"""管理配置文件内容的类"""
def __init__(self, path: str = None):
def __init__(self, path=None):
"""初始化,读取配置文件,如没有设置临时文件夹,则设置并新建 \n
:param path: ini文件的路径默认读取模块文件夹下的
"""
@ -31,7 +30,7 @@ class OptionsManager(object):
self._chrome_options = None
self._session_options = None
def __text__(self) -> str:
def __text__(self):
"""打印ini文件内容"""
return (f"paths:\n"
f"{self.get_option('paths')}\n\n"
@ -41,7 +40,7 @@ class OptionsManager(object):
f"{self.get_option('session_options')}")
@property
def paths(self) -> dict:
def paths(self):
"""返回paths设置"""
if self._paths is None:
self._paths = self.get_option('paths')
@ -49,7 +48,7 @@ class OptionsManager(object):
return self._paths
@property
def chrome_options(self) -> dict:
def chrome_options(self):
"""返回chrome设置"""
if self._chrome_options is None:
self._chrome_options = self.get_option('chrome_options')
@ -57,14 +56,14 @@ class OptionsManager(object):
return self._chrome_options
@property
def session_options(self) -> dict:
def session_options(self):
"""返回session设置"""
if self._session_options is None:
self._session_options = self.get_option('session_options')
return self._session_options
def get_value(self, section: str, item: str) -> Any:
def get_value(self, section, item):
"""获取配置的值 \n
:param section: 段名
:param item: 项名
@ -77,7 +76,7 @@ class OptionsManager(object):
except NoSectionError and NoOptionError:
return None
def get_option(self, section: str) -> dict:
def get_option(self, section):
"""把section内容以字典方式返回 \n
:param section: 段名
:return: 段内容生成的字典
@ -93,7 +92,7 @@ class OptionsManager(object):
return option
def set_item(self, section: str, item: str, value: Any):
def set_item(self, section, item, value):
"""设置配置值 \n
:param section: 段名
:param item: 项名
@ -104,7 +103,7 @@ class OptionsManager(object):
self.__setattr__(f'_{section}', None)
return self
def save(self, path: str = None) -> str:
def save(self, path=None):
"""保存配置文件 \n
:param path: ini文件的路径传入 'default' 保存到默认ini文件
:return: 保存路径
@ -128,13 +127,13 @@ class OptionsManager(object):
return path
def save_to_default(self) -> str:
def save_to_default(self):
"""保存当前配置到默认ini文件"""
return self.save('default')
class SessionOptions(object):
def __init__(self, read_file: bool = True, ini_path: str = None):
def __init__(self, read_file=True, ini_path=None):
"""requests的Session对象配置类 \n
:param read_file: 是否从文件读取配置
:param ini_path: ini文件路径
@ -195,14 +194,14 @@ class SessionOptions(object):
self._max_redirects = options_dict['max_redirects']
@property
def headers(self) -> dict:
def headers(self):
"""返回headers设置信息"""
if self._headers is None:
self._headers = {}
return self._headers
@property
def cookies(self) -> list:
def cookies(self):
"""返回cookies设置信息"""
if self._cookies is None:
self._cookies = []
@ -210,12 +209,12 @@ class SessionOptions(object):
return self._cookies
@property
def auth(self) -> tuple:
def auth(self):
"""返回auth设置信息"""
return self._auth
@property
def proxies(self) -> dict:
def proxies(self):
"""返回proxies设置信息"""
if self._proxies is None:
self._proxies = {}
@ -223,7 +222,7 @@ class SessionOptions(object):
return self._proxies
@property
def hooks(self) -> dict:
def hooks(self):
"""返回hooks设置信息"""
if self._hooks is None:
self._hooks = {}
@ -231,19 +230,19 @@ class SessionOptions(object):
return self._hooks
@property
def params(self) -> dict:
def params(self):
"""返回params设置信息"""
if self._params is None:
self._params = {}
return self._params
@property
def verify(self) -> bool:
def verify(self):
"""返回verify设置信息"""
return self._verify
@property
def cert(self) -> Union[str, tuple]:
def cert(self):
"""返回cert设置信息"""
return self._cert
@ -253,22 +252,22 @@ class SessionOptions(object):
return self._adapters
@property
def stream(self) -> bool:
def stream(self):
"""返回stream设置信息"""
return self._stream
@property
def trust_env(self) -> bool:
def trust_env(self):
"""返回trust_env设置信息"""
return self._trust_env
@property
def max_redirects(self) -> int:
def max_redirects(self):
"""返回max_redirects设置信息"""
return self._max_redirects
@headers.setter
def headers(self, headers: dict) -> None:
def headers(self, headers):
"""设置headers参数 \n
:param headers: 参数值
:return: None
@ -276,7 +275,7 @@ class SessionOptions(object):
self.set_headers(headers)
@cookies.setter
def cookies(self, cookies: Union[RequestsCookieJar, list, tuple, str, dict]) -> None:
def cookies(self, cookies):
"""设置cookies参数 \n
:param cookies: 参数值
:return: None
@ -284,7 +283,7 @@ class SessionOptions(object):
self._cookies = cookies
@auth.setter
def auth(self, auth: tuple) -> None:
def auth(self, auth):
"""设置auth参数 \n
:param auth: 参数值
:return: None
@ -292,7 +291,7 @@ class SessionOptions(object):
self._auth = auth
@proxies.setter
def proxies(self, proxies: dict) -> None:
def proxies(self, proxies):
"""设置proxies参数 \n
:param proxies: 参数值
:return: None
@ -300,7 +299,7 @@ class SessionOptions(object):
self.set_proxies(proxies)
@hooks.setter
def hooks(self, hooks: dict) -> None:
def hooks(self, hooks):
"""设置hooks参数 \n
:param hooks: 参数值
:return: None
@ -308,7 +307,7 @@ class SessionOptions(object):
self._hooks = hooks
@params.setter
def params(self, params: dict) -> None:
def params(self, params):
"""设置params参数 \n
:param params: 参数值
:return: None
@ -316,7 +315,7 @@ class SessionOptions(object):
self._params = params
@verify.setter
def verify(self, verify: bool) -> None:
def verify(self, verify):
"""设置verify参数 \n
:param verify: 参数值
:return: None
@ -324,7 +323,7 @@ class SessionOptions(object):
self._verify = verify
@cert.setter
def cert(self, cert: Union[str, tuple]) -> None:
def cert(self, cert):
"""设置cert参数 \n
:param cert: 参数值
:return: None
@ -332,7 +331,7 @@ class SessionOptions(object):
self._cert = cert
@adapters.setter
def adapters(self, adapters) -> None:
def adapters(self, adapters):
"""设置 \n
:param adapters: 参数值
:return: None
@ -340,7 +339,7 @@ class SessionOptions(object):
self._adapters = adapters
@stream.setter
def stream(self, stream: bool) -> None:
def stream(self, stream):
"""设置stream参数 \n
:param stream: 参数值
:return: None
@ -348,7 +347,7 @@ class SessionOptions(object):
self._stream = stream
@trust_env.setter
def trust_env(self, trust_env: bool) -> None:
def trust_env(self, trust_env):
"""设置trust_env参数 \n
:param trust_env: 参数值
:return: None
@ -356,14 +355,14 @@ class SessionOptions(object):
self._trust_env = trust_env
@max_redirects.setter
def max_redirects(self, max_redirects: int) -> None:
def max_redirects(self, max_redirects):
"""设置max_redirects参数 \n
:param max_redirects: 参数值
:return: None
"""
self._max_redirects = max_redirects
def set_headers(self, headers: dict) -> 'SessionOptions':
def set_headers(self, headers):
"""设置headers参数 \n
:param headers: 参数值
:return: 返回当前对象
@ -371,7 +370,7 @@ class SessionOptions(object):
self._headers = {key.lower(): headers[key] for key in headers}
return self
def set_a_header(self, attr: str, value: str) -> 'SessionOptions':
def set_a_header(self, attr, value):
"""设置headers中一个项 \n
:param attr: 设置名称
:param value: 设置值
@ -383,7 +382,7 @@ class SessionOptions(object):
self._headers[attr.lower()] = value
return self
def remove_a_header(self, attr: str) -> 'SessionOptions':
def remove_a_header(self, attr):
"""从headers中删除一个设置 \n
:param attr: 要删除的设置
:return: 返回当前对象
@ -397,7 +396,7 @@ class SessionOptions(object):
return self
def set_proxies(self, proxies: dict) -> 'SessionOptions':
def set_proxies(self, proxies):
"""设置proxies参数 \n
{'http': 'http://xx.xx.xx.xx:xxxx',
'https': 'http://xx.xx.xx.xx:xxxx'}
@ -407,7 +406,7 @@ class SessionOptions(object):
self._proxies = proxies
return self
def save(self, path: str = None) -> str:
def save(self, path=None):
"""保存设置到文件 \n
:param path: ini文件的路径传入 'default' 保存到默认ini文件
:return: 保存文件的绝对路径
@ -431,7 +430,7 @@ class SessionOptions(object):
else:
om = OptionsManager(self.ini_path or str(Path(__file__).parent / 'configs.ini'))
options = _session_options_to_dict(self)
options = session_options_to_dict(self)
for i in options:
om.set_item('session_options', i, options[i])
@ -441,13 +440,13 @@ class SessionOptions(object):
return path
def save_to_default(self) -> str:
def save_to_default(self):
"""保存当前配置到默认ini文件"""
return self.save('default')
def as_dict(self) -> dict:
def as_dict(self):
"""以字典形式返回本对象"""
return _session_options_to_dict(self)
return session_options_to_dict(self)
class DriverOptions(Options):
@ -455,7 +454,7 @@ class DriverOptions(Options):
增加了删除配置和保存到文件方法
"""
def __init__(self, read_file: bool = True, ini_path: str = None):
def __init__(self, read_file=True, ini_path=None):
"""初始化,默认从文件读取设置 \n
:param read_file: 是否从默认ini文件中读取配置信息
:param ini_path: ini文件路径为None则读取默认ini文件
@ -493,22 +492,22 @@ class DriverOptions(Options):
self._arguments.append('--no-sandbox')
@property
def driver_path(self) -> str:
def driver_path(self):
"""chromedriver文件路径"""
return self._driver_path
@property
def chrome_path(self) -> str:
def chrome_path(self):
"""浏览器启动文件路径"""
return self.binary_location or 'chrome'
@property
def user_data_path(self) -> str:
def user_data_path(self):
"""返回用户文件夹路径"""
return self._user_data_path
# -------------重写父类方法,实现链式操作-------------
def add_argument(self, argument) -> 'DriverOptions':
def add_argument(self, argument):
"""添加一个配置项 \n
:param argument: 配置项内容
:return: 当前对象
@ -516,7 +515,7 @@ class DriverOptions(Options):
super().add_argument(argument)
return self
def set_capability(self, name, value) -> 'DriverOptions':
def set_capability(self, name, value):
"""设置一个capability \n
:param name: capability名称
:param value: capability值
@ -525,7 +524,7 @@ class DriverOptions(Options):
super().set_capability(name, value)
return self
def add_extension(self, extension: str) -> 'DriverOptions':
def add_extension(self, extension):
"""添加插件 \n
:param extension: crx文件路径
:return: 当前对象
@ -533,7 +532,7 @@ class DriverOptions(Options):
super().add_extension(extension)
return self
def add_encoded_extension(self, extension: str) -> 'DriverOptions':
def add_encoded_extension(self, extension):
"""将带有扩展数据的 Base64 编码字符串添加到将用于将其提取到 ChromeDriver 的列表中 \n
:param extension: 带有扩展数据的 Base64 编码字符串
:return: 当前对象
@ -541,7 +540,7 @@ class DriverOptions(Options):
super().add_encoded_extension(extension)
return self
def add_experimental_option(self, name: str, value: Union[str, int, dict, List[str]]) -> 'DriverOptions':
def add_experimental_option(self, name, value):
"""添加一个实验选项到浏览器 \n
:param name: 选项名称
:param value: 选项值
@ -552,7 +551,7 @@ class DriverOptions(Options):
# -------------重写父类方法结束-------------
def save(self, path: str = None) -> str:
def save(self, path=None):
"""保存设置到文件 \n
:param path: ini文件的路径 None 保存到当前读取的配置文件传入 'default' 保存到默认ini文件
:return: 保存文件的绝对路径
@ -589,11 +588,11 @@ class DriverOptions(Options):
return path
def save_to_default(self) -> str:
def save_to_default(self):
"""保存当前配置到默认ini文件"""
return self.save('default')
def remove_argument(self, value: str) -> 'DriverOptions':
def remove_argument(self, value):
"""移除一个argument项 \n
:param value: 设置项名有值的设置项传入设置名称即可
:return: 当前对象
@ -609,7 +608,7 @@ class DriverOptions(Options):
return self
def remove_experimental_option(self, key: str) -> 'DriverOptions':
def remove_experimental_option(self, key):
"""移除一个实验设置传入key值删除 \n
:param key: 实验设置的名称
:return: 当前对象
@ -619,7 +618,7 @@ class DriverOptions(Options):
return self
def remove_all_extensions(self) -> 'DriverOptions':
def remove_all_extensions(self):
"""移除所有插件 \n
:return: 当前对象
"""
@ -627,7 +626,7 @@ class DriverOptions(Options):
self._extensions = []
return self
def set_argument(self, arg: str, value: Union[bool, str]) -> 'DriverOptions':
def set_argument(self, arg, value):
"""设置浏览器配置的argument属性 \n
:param arg: 属性名
:param value: 属性值有值的属性传入值没有的传入bool
@ -641,7 +640,7 @@ class DriverOptions(Options):
return self
def set_timeouts(self, implicit: float = None, pageLoad: float = None, script: float = None) -> 'DriverOptions':
def set_timeouts(self, implicit=None, pageLoad=None, script=None):
"""设置超时时间设置单位为秒selenium4以上版本有效 \n
:param implicit: 查找元素超时时间
:param pageLoad: 页面加载超时时间
@ -659,7 +658,7 @@ class DriverOptions(Options):
return self
def set_headless(self, on_off: bool = True) -> 'DriverOptions':
def set_headless(self, on_off=True):
"""设置是否隐藏浏览器界面 \n
:param on_off: 开或关
:return: 当前对象
@ -667,7 +666,7 @@ class DriverOptions(Options):
on_off = True if on_off else False
return self.set_argument('--headless', on_off)
def set_no_imgs(self, on_off: bool = True) -> 'DriverOptions':
def set_no_imgs(self, on_off=True):
"""设置是否加载图片 \n
:param on_off: 开或关
:return: 当前对象
@ -675,7 +674,7 @@ class DriverOptions(Options):
on_off = True if on_off else False
return self.set_argument('--blink-settings=imagesEnabled=false', on_off)
def set_no_js(self, on_off: bool = True) -> 'DriverOptions':
def set_no_js(self, on_off=True):
"""设置是否禁用js \n
:param on_off: 开或关
:return: 当前对象
@ -683,7 +682,7 @@ class DriverOptions(Options):
on_off = True if on_off else False
return self.set_argument('--disable-javascript', on_off)
def set_mute(self, on_off: bool = True) -> 'DriverOptions':
def set_mute(self, on_off=True):
"""设置是否静音 \n
:param on_off: 开或关
:return: 当前对象
@ -691,21 +690,21 @@ class DriverOptions(Options):
on_off = True if on_off else False
return self.set_argument('--mute-audio', on_off)
def set_user_agent(self, user_agent: str) -> 'DriverOptions':
def set_user_agent(self, user_agent):
"""设置user agent \n
:param user_agent: user agent文本
:return: 当前对象
"""
return self.set_argument('--user-agent', user_agent)
def set_proxy(self, proxy: str) -> 'DriverOptions':
def set_proxy(self, proxy):
"""设置代理 \n
:param proxy: 代理url和端口
:return: 当前对象
"""
return self.set_argument('--proxy-server', proxy)
def set_page_load_strategy(self, value: str) -> 'DriverOptions':
def set_page_load_strategy(self, value):
"""设置page_load_strategy可接收 'normal', 'eager', 'none' \n
selenium4以上版本才支持此功能
normal默认情况下使用, 等待所有资源下载完成
@ -719,14 +718,8 @@ class DriverOptions(Options):
self.page_load_strategy = value.lower()
return self
def set_paths(self,
driver_path: str = None,
chrome_path: str = None,
local_port: Union[int, str] = None,
debugger_address: str = None,
download_path: str = None,
user_data_path: str = None,
cache_path: str = None) -> 'DriverOptions':
def set_paths(self, driver_path=None, chrome_path=None, local_port=None, debugger_address=None, download_path=None,
user_data_path=None, cache_path=None):
"""快捷的路径设置函数 \n
:param driver_path: chromedriver.exe路径
:param chrome_path: chrome.exe路径
@ -761,12 +754,12 @@ class DriverOptions(Options):
return self
def as_dict(self) -> dict:
def as_dict(self):
"""已dict方式返回所有配置信息"""
return _chrome_options_to_dict(self)
return chrome_options_to_dict(self)
def _chrome_options_to_dict(options: Union[dict, DriverOptions, Options, None, bool]) -> Union[dict, None]:
def chrome_options_to_dict(options):
"""把chrome配置对象转换为字典 \n
:param options: chrome配置对象字典或DriverOptions对象
:return: 配置字典
@ -798,7 +791,7 @@ def _chrome_options_to_dict(options: Union[dict, DriverOptions, Options, None, b
return re_dict
def _session_options_to_dict(options: Union[dict, SessionOptions, None]) -> Union[dict, None]:
def session_options_to_dict(options):
"""把session配置对象转换为字典 \n
:param options: session配置对象或字典
:return: 配置字典
@ -815,7 +808,7 @@ def _session_options_to_dict(options: Union[dict, SessionOptions, None]) -> Unio
cookies = options.__getattribute__('_cookies')
if cookies is not None:
re_dict['cookies'] = _cookies_to_tuple(cookies)
re_dict['cookies'] = cookies_to_tuple(cookies)
for attr in attrs:
val = options.__getattribute__(f'_{attr}')
@ -829,7 +822,7 @@ def _session_options_to_dict(options: Union[dict, SessionOptions, None]) -> Unio
return re_dict
def _cookie_to_dict(cookie: Union[Cookie, str, dict]) -> dict:
def cookie_to_dict(cookie):
"""把Cookie对象转为dict格式 \n
:param cookie: Cookie对象
:return: cookie字典
@ -864,16 +857,16 @@ def _cookie_to_dict(cookie: Union[Cookie, str, dict]) -> dict:
return cookie_dict
def _cookies_to_tuple(cookies: Union[RequestsCookieJar, list, tuple, str, dict]) -> tuple:
def cookies_to_tuple(cookies):
"""把cookies转为tuple格式 \n
:param cookies: cookies信息可为CookieJar, list, tuple, str, dict
:return: 返回tuple形式的cookies
"""
if isinstance(cookies, (list, tuple, RequestsCookieJar)):
cookies = tuple(_cookie_to_dict(cookie) for cookie in cookies)
cookies = tuple(cookie_to_dict(cookie) for cookie in cookies)
elif isinstance(cookies, str):
cookies = tuple(_cookie_to_dict(cookie.lstrip()) for cookie in cookies.split(";"))
cookies = tuple(cookie_to_dict(cookie.lstrip()) for cookie in cookies.split(";"))
elif isinstance(cookies, dict):
cookies = tuple({'name': cookie, 'value': cookies[cookie]} for cookie in cookies)

226
DrissionPage/config.pyi Normal file
View File

@ -0,0 +1,226 @@
# -*- coding:utf-8 -*-
from configparser import RawConfigParser
from http.cookiejar import Cookie
from typing import Any, Union, List
from requests.cookies import RequestsCookieJar
from selenium.webdriver.chrome.options import Options
class OptionsManager(object):
"""管理配置文件内容的类"""
def __init__(self, path: str = ...):
self.ini_path: str = ...
self._conf: RawConfigParser = ...
self._paths: dict = ...
self._chrome_options: dict = ...
self._session_options: dict = ...
def __text__(self) -> str: ...
@property
def paths(self) -> dict: ...
@property
def chrome_options(self) -> dict: ...
@property
def session_options(self) -> dict: ...
def get_value(self, section: str, item: str) -> Any: ...
def get_option(self, section: str) -> dict: ...
def set_item(self, section: str, item: str, value: Any) -> OptionsManager: ...
def save(self, path: str = ...) -> str: ...
def save_to_default(self) -> str: ...
class SessionOptions(object):
def __init__(self, read_file: bool = ..., ini_path: str = ...):
self.ini_path: str = ...
self._headers: dict = ...
self._cookies: list = ...
self._auth: tuple = ...
self._proxies: dict = ...
self._hooks: dict = ...
self._params: dict = ...
self._verify: bool = ...
self._cert: Union[str, tuple] = ...
self._adapters: str = ...
self._stream: bool = ...
self._trust_env: bool = ...
self._max_redirects: int = ...
@property
def headers(self) -> dict: ...
@property
def cookies(self) -> list: ...
@property
def auth(self) -> tuple: ...
@property
def proxies(self) -> dict: ...
@property
def hooks(self) -> dict: ...
@property
def params(self) -> dict: ...
@property
def verify(self) -> bool: ...
@property
def cert(self) -> Union[str, tuple]: ...
@property
def adapters(self): ...
@property
def stream(self) -> bool: ...
@property
def trust_env(self) -> bool: ...
@property
def max_redirects(self) -> int: ...
@headers.setter
def headers(self, headers: dict) -> None: ...
@cookies.setter
def cookies(self, cookies: Union[RequestsCookieJar, list, tuple, str, dict]) -> None: ...
@auth.setter
def auth(self, auth: tuple) -> None: ...
@proxies.setter
def proxies(self, proxies: dict) -> None: ...
@hooks.setter
def hooks(self, hooks: dict) -> None: ...
@params.setter
def params(self, params: dict) -> None: ...
@verify.setter
def verify(self, verify: bool) -> None: ...
@cert.setter
def cert(self, cert: Union[str, tuple]) -> None: ...
@adapters.setter
def adapters(self, adapters) -> None: ...
@stream.setter
def stream(self, stream: bool) -> None: ...
@trust_env.setter
def trust_env(self, trust_env: bool) -> None: ...
@max_redirects.setter
def max_redirects(self, max_redirects: int) -> None: ...
def set_headers(self, headers: dict) -> 'SessionOptions': ...
def set_a_header(self, attr: str, value: str) -> 'SessionOptions': ...
def remove_a_header(self, attr: str) -> 'SessionOptions': ...
def set_proxies(self, proxies: dict) -> 'SessionOptions': ...
def save(self, path: str = ...) -> str: ...
def save_to_default(self) -> str: ...
def as_dict(self) -> dict: ...
class DriverOptions(Options):
"""chrome浏览器配置类继承自selenium.webdriver.chrome.options的Options类
增加了删除配置和保存到文件方法
"""
def __init__(self, read_file: bool = ..., ini_path: str = ...):
self.ini_path: str = ...
self._driver_path: str = ...
self._user_data_path: str = ...
@property
def driver_path(self) -> str: ...
@property
def chrome_path(self) -> str: ...
@property
def user_data_path(self) -> str: ...
# -------------重写父类方法,实现链式操作-------------
def add_argument(self, argument: str) -> 'DriverOptions': ...
def set_capability(self, name: str, value: str) -> 'DriverOptions': ...
def add_extension(self, extension: str) -> 'DriverOptions': ...
def add_encoded_extension(self, extension: str) -> 'DriverOptions': ...
def add_experimental_option(self, name: str, value: Union[str, int, dict, List[str]]) -> 'DriverOptions': ...
# -------------重写父类方法结束-------------
def save(self, path: str = ...) -> str: ...
def save_to_default(self) -> str: ...
def remove_argument(self, value: str) -> 'DriverOptions': ...
def remove_experimental_option(self, key: str) -> 'DriverOptions': ...
def remove_all_extensions(self) -> 'DriverOptions': ...
def set_argument(self, arg: str, value: Union[bool, str]) -> 'DriverOptions': ...
def set_timeouts(self, implicit: float = ..., pageLoad: float = ..., script: float = ...) -> 'DriverOptions': ...
def set_headless(self, on_off: bool = ...) -> 'DriverOptions': ...
def set_no_imgs(self, on_off: bool = ...) -> 'DriverOptions': ...
def set_no_js(self, on_off: bool = ...) -> 'DriverOptions': ...
def set_mute(self, on_off: bool = ...) -> 'DriverOptions': ...
def set_user_agent(self, user_agent: str) -> 'DriverOptions': ...
def set_proxy(self, proxy: str) -> 'DriverOptions': ...
def set_page_load_strategy(self, value: str) -> 'DriverOptions': ...
def set_paths(self,
driver_path: str = ...,
chrome_path: str = ...,
local_port: Union[int, str] = ...,
debugger_address: str = ...,
download_path: str = ...,
user_data_path: str = ...,
cache_path: str = ...) -> 'DriverOptions': ...
def as_dict(self) -> dict: ...
def chrome_options_to_dict(options: Union[dict, DriverOptions, Options, None, bool]) -> Union[dict, None]: ...
def session_options_to_dict(options: Union[dict, SessionOptions, None]) -> Union[dict, None]: ...
def cookie_to_dict(cookie: Union[Cookie, str, dict]) -> dict: ...
def cookies_to_tuple(cookies: Union[RequestsCookieJar, list, tuple, str, dict]) -> tuple: ...

View File

@ -4,32 +4,25 @@
@Contact : g1879@qq.com
@File : drission.py
"""
from sys import exit
from typing import Union
from platform import system
from sys import exit
from requests import Session
from requests.cookies import RequestsCookieJar
from requests.structures import CaseInsensitiveDict
from selenium import webdriver
from selenium.common.exceptions import SessionNotCreatedException, WebDriverException
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.chrome.webdriver import WebDriver
from selenium.webdriver.remote.webdriver import WebDriver as RemoteWebDriver
from tldextract import extract
from .common import get_pid_from_port, connect_chrome
from .config import _session_options_to_dict, SessionOptions, DriverOptions, _cookies_to_tuple
from .config import SessionOptions, DriverOptions, cookies_to_tuple, session_options_to_dict
class Drission(object):
"""Drission类用于管理WebDriver对象和Session对象是驱动器的角色"""
def __init__(self,
driver_or_options: Union[RemoteWebDriver, Options, DriverOptions, bool] = None,
session_or_options: Union[Session, dict, SessionOptions, bool] = None,
ini_path: str = None,
proxy: dict = None):
def __init__(self, driver_or_options=None, session_or_options=None, ini_path=None, proxy=None):
"""初始化可接收现成的WebDriver和Session对象或接收它们的配置信息生成对象 \n
:param driver_or_options: driver对象或DriverOptionsOptions类传入False则创建空配置对象
:param session_or_options: Session对象或设置字典传入False则创建空配置对象
@ -86,7 +79,7 @@ class Drission(object):
pass
@property
def session(self) -> Session:
def session(self):
"""返回Session对象如未初始化则按配置信息创建"""
if self._session is None:
self._set_session(self._session_options)
@ -97,7 +90,7 @@ class Drission(object):
return self._session
@property
def driver(self) -> WebDriver:
def driver(self):
"""返回WebDriver对象如未初始化则按配置信息创建。 \n
如设置了本地调试浏览器可自动接入或打开浏览器进程
"""
@ -114,7 +107,7 @@ class Drission(object):
chrome_path, self._debugger = connect_chrome(self.driver_options)
# -----------创建WebDriver对象-----------
self._driver = _create_driver(chrome_path, driver_path, self.driver_options)
self._driver = create_driver(chrome_path, driver_path, self.driver_options)
# -----------解决接管新版浏览器不能定位到正确的标签页的问题-----------
active_tab = self._driver.window_handles[0]
@ -130,31 +123,31 @@ class Drission(object):
return self._driver
@property
def driver_options(self) -> Union[DriverOptions, Options]:
def driver_options(self):
"""返回driver配置信息"""
return self._driver_options
@property
def session_options(self) -> dict:
def session_options(self):
"""返回session配置信息"""
return self._session_options
@session_options.setter
def session_options(self, options: Union[dict, SessionOptions]) -> None:
def session_options(self, options):
"""设置session配置 \n
:param options: session配置字典
:return: None
"""
self._session_options = _session_options_to_dict(options)
self._session_options = session_options_to_dict(options)
self._set_session(self._session_options)
@property
def proxy(self) -> Union[None, dict]:
def proxy(self):
"""返回代理信息"""
return self._proxy
@proxy.setter
def proxy(self, proxies: dict = None) -> None:
def proxy(self, proxies=None):
"""设置代理信息 \n
:param proxies: 代理信息字典
:return: None
@ -180,13 +173,13 @@ class Drission(object):
"""调试浏览器进程"""
return self._debugger
def kill_browser(self) -> None:
def kill_browser(self):
"""关闭浏览器进程(如果可以)"""
pid = self.get_browser_progress_id()
if not _kill_progress(pid):
if not kill_progress(pid):
self._driver.quit()
def get_browser_progress_id(self) -> Union[str, None]:
def get_browser_progress_id(self):
"""获取浏览器进程id"""
if self.debugger_progress:
return self.debugger_progress.pid
@ -209,15 +202,15 @@ class Drission(object):
return txt.split(' ')[-1]
def hide_browser(self) -> None:
def hide_browser(self):
"""隐藏浏览器界面"""
self._show_or_hide_browser()
def show_browser(self) -> None:
def show_browser(self):
"""显示浏览器界面"""
self._show_or_hide_browser(False)
def _show_or_hide_browser(self, hide: bool = True) -> None:
def _show_or_hide_browser(self, hide=True):
if system().lower() != 'windows':
raise OSError('该方法只能在Windows系统使用。')
@ -231,22 +224,19 @@ class Drission(object):
if not pid:
print('只有设置了debugger_address参数才能使用 show_browser() 和 hide_browser()')
return
hds = _get_chrome_hwnds_from_pid(pid)
hds = get_chrome_hwnds_from_pid(pid)
sw = SW_HIDE if hide else SW_SHOW
for hd in hds:
ShowWindow(hd, sw)
def set_cookies(self,
cookies: Union[RequestsCookieJar, list, tuple, str, dict],
set_session: bool = False,
set_driver: bool = False) -> None:
def set_cookies(self, cookies, set_session=False, set_driver=False):
"""设置cookies \n
:param cookies: cookies信息可为CookieJar, list, tuple, str, dict
:param set_session: 是否设置session的cookies
:param set_driver: 是否设置driver的cookies
:return: None
"""
cookies = _cookies_to_tuple(cookies)
cookies = cookies_to_tuple(cookies)
for cookie in cookies:
if cookie['value'] is None:
@ -296,7 +286,7 @@ class Drission(object):
self.driver.add_cookie(cookie)
def _set_session(self, data: dict) -> None:
def _set_session(self, data):
"""根据传入字典对session进行设置 \n
:param data: session配置字典
:return: None
@ -315,7 +305,7 @@ class Drission(object):
if i in data:
self._session.__setattr__(i, data[i])
def cookies_to_session(self, copy_user_agent: bool = False) -> None:
def cookies_to_session(self, copy_user_agent=False):
"""把driver对象的cookies复制到session对象 \n
:param copy_user_agent: 是否复制ua信息
:return: None
@ -325,7 +315,7 @@ class Drission(object):
self.set_cookies(self.driver.get_cookies(), set_session=True)
def cookies_to_driver(self, url: str) -> None:
def cookies_to_driver(self, url):
"""把session对象的cookies复制到driver对象 \n
:param url: 作用域
:return: None
@ -348,10 +338,10 @@ class Drission(object):
self.set_cookies(cookies, set_driver=True)
def close_driver(self, kill: bool = False) -> None:
def close_driver(self, kill=False):
"""关闭driver和浏览器"""
if self._driver:
_kill_progress(port=self._driver.service.port) # 关闭chromedriver.exe进程
kill_progress(port=self._driver.service.port) # 关闭chromedriver.exe进程
if kill:
self.kill_browser()
@ -360,13 +350,13 @@ class Drission(object):
self._driver = None
def close_session(self) -> None:
def close_session(self):
"""关闭session"""
if self._session:
self._session.close()
self._session = None
def close(self) -> None:
def close(self):
"""关闭session、driver和浏览器"""
if self._driver:
self.close_driver()
@ -375,7 +365,7 @@ class Drission(object):
self.close_session()
def user_agent_to_session(driver: RemoteWebDriver, session: Session) -> None:
def user_agent_to_session(driver, session):
"""把driver的user-agent复制到session \n
:param driver: 来源driver对象
:param session: 目标session对象
@ -387,7 +377,7 @@ def user_agent_to_session(driver: RemoteWebDriver, session: Session) -> None:
session.headers.update({"User-Agent": selenium_user_agent})
def _create_driver(chrome_path: str, driver_path: str, options: Options) -> WebDriver:
def create_driver(chrome_path, driver_path, options):
"""创建 WebDriver 对象 \n
:param chrome_path: chrome.exe 路径
:param driver_path: chromedriver.exe 路径
@ -424,7 +414,7 @@ def _create_driver(chrome_path: str, driver_path: str, options: Options) -> WebD
exit(0)
def _get_chrome_hwnds_from_pid(pid) -> list:
def get_chrome_hwnds_from_pid(pid):
"""通过PID查询句柄ID"""
try:
from win32gui import IsWindow, GetWindowText, EnumWindows
@ -444,7 +434,7 @@ def _get_chrome_hwnds_from_pid(pid) -> list:
return hwnds
def _kill_progress(pid: str = None, port: int = None) -> bool:
def kill_progress(pid=None, port=None):
"""关闭浏览器进程 \n
:param pid: 进程id
:param port: 端口号如没有进程id从端口号获取

View File

@ -83,10 +83,10 @@ class Drission(object):
def user_agent_to_session(driver: RemoteWebDriver, session: Session) -> None: ...
def _create_driver(chrome_path: str, driver_path: str, options: Options) -> WebDriver: ...
def create_driver(chrome_path: str, driver_path: str, options: Options) -> WebDriver: ...
def _get_chrome_hwnds_from_pid(pid) -> list: ...
def get_chrome_hwnds_from_pid(pid:str) -> list: ...
def _kill_progress(pid: str = ..., port: int = ...) -> bool: ...
def kill_progress(pid: str = ..., port: int = ...) -> bool: ...

View File

@ -7,7 +7,6 @@
from os import sep
from pathlib import Path
from time import time, perf_counter, sleep
from typing import Union, List, Any, Tuple
from selenium.common.exceptions import TimeoutException, JavascriptException, InvalidElementStateException, \
NoSuchElementException
@ -18,13 +17,13 @@ from selenium.webdriver.support.wait import WebDriverWait
from .base import DrissionElement, BaseElement
from .common import str_to_loc, get_usable_path, format_html, get_ele_txt, get_loc
from .session_element import make_session_ele, SessionElement
from .session_element import make_session_ele
class DriverElement(DrissionElement):
"""driver模式的元素对象包装了一个WebElement对象并封装了常用功能"""
def __init__(self, ele: WebElement, page=None):
def __init__(self, ele, page=None):
"""初始化对象 \n
:param ele: 被包装的WebElement元素
:param page: 元素所在页面
@ -34,13 +33,11 @@ class DriverElement(DrissionElement):
self._scroll = None
self._inner_ele = ele
def __repr__(self) -> str:
def __repr__(self):
attrs = [f"{attr}='{self.attrs[attr]}'" for attr in self.attrs]
return f'<DriverElement {self.tag} {" ".join(attrs)}>'
def __call__(self,
loc_or_str: Union[Tuple[str, str], str],
timeout: float = None) -> Union['DriverElement', str, None]:
def __call__(self, loc_or_str, timeout=None):
"""在内部查找元素 \n
ele2 = ele1('@id=ele_id') \n
:param loc_or_str: 元素的定位信息可以是loc元组或查询字符串
@ -51,26 +48,26 @@ class DriverElement(DrissionElement):
# -----------------共有属性和方法-------------------
@property
def inner_ele(self) -> WebElement:
def inner_ele(self):
return self._inner_ele
@property
def tag(self) -> str:
def tag(self):
"""返回元素类型"""
return self._inner_ele.tag_name.lower()
@property
def html(self) -> str:
def html(self):
"""返回元素outerHTML文本"""
return self.inner_ele.get_attribute('outerHTML')
@property
def inner_html(self) -> str:
def inner_html(self):
"""返回元素innerHTML文本"""
return self.inner_ele.get_attribute('innerHTML')
@property
def attrs(self) -> dict:
def attrs(self):
"""返回元素所有属性及值"""
js = '''
var dom=arguments[0];
@ -89,16 +86,16 @@ class DriverElement(DrissionElement):
return {attr: self.attr(attr) for attr in eval(self.run_script(js))}
@property
def text(self) -> str:
def text(self):
"""返回元素内所有文本"""
return get_ele_txt(make_session_ele(self.html))
@property
def raw_text(self) -> str:
def raw_text(self):
"""返回未格式化处理的元素内文本"""
return self.inner_ele.get_attribute('innerText')
def attr(self, attr: str) -> str:
def attr(self, attr):
"""获取attribute属性值 \n
:param attr: 属性名
:return: 属性值文本
@ -114,9 +111,7 @@ class DriverElement(DrissionElement):
else:
return format_html(self.inner_ele.get_attribute(attr))
def ele(self,
loc_or_str: Union[Tuple[str, str], str],
timeout: float = None) -> Union['DriverElement', str, None]:
def ele(self, loc_or_str, timeout=None):
"""返回当前元素下级符合条件的第一个元素、属性或节点文本 \n
:param loc_or_str: 元素的定位信息可以是loc元组或查询字符串
:param timeout: 查找元素超时时间默认与元素所在页面等待时间一致
@ -124,9 +119,7 @@ class DriverElement(DrissionElement):
"""
return self._ele(loc_or_str, timeout)
def eles(self,
loc_or_str: Union[Tuple[str, str], str],
timeout: float = None) -> List[Union['DriverElement', str]]:
def eles(self, loc_or_str, timeout=None):
"""返回当前元素下级所有符合条件的子元素、属性或节点文本 \n
:param loc_or_str: 元素的定位信息可以是loc元组或查询字符串
:param timeout: 查找元素超时时间默认与元素所在页面等待时间一致
@ -134,25 +127,21 @@ class DriverElement(DrissionElement):
"""
return self._ele(loc_or_str, timeout=timeout, single=False)
def s_ele(self, loc_or_str: Union[Tuple[str, str], str] = None) -> Union[SessionElement, str, None]:
def s_ele(self, loc_or_str=None):
"""查找第一个符合条件的元素以SessionElement形式返回处理复杂页面时效率很高 \n
:param loc_or_str: 元素的定位信息可以是loc元组或查询字符串
:return: SessionElement对象或属性文本
"""
return make_session_ele(self, loc_or_str)
def s_eles(self, loc_or_str: Union[Tuple[str, str], str] = None) -> List[Union[SessionElement, str]]:
def s_eles(self, loc_or_str=None):
"""查找所有符合条件的元素以SessionElement列表形式返回 \n
:param loc_or_str: 定位符
:return: SessionElement或属性文本组成的列表
"""
return make_session_ele(self, loc_or_str, single=False)
def _ele(self,
loc_or_str: Union[Tuple[str, str], str],
timeout: float = None,
single: bool = True,
relative: bool = False) -> Union['DriverElement', str, None, List[Union['DriverElement', str]]]:
def _ele(self, loc_or_str, timeout=None, single=True, relative=False):
"""返回当前元素下级符合条件的子元素、属性或节点文本,默认返回第一个 \n
:param loc_or_str: 元素的定位信息可以是loc元组或查询字符串
:param timeout: 查找元素超时时间
@ -162,7 +151,7 @@ class DriverElement(DrissionElement):
"""
return make_driver_ele(self, loc_or_str, single, timeout)
def _get_ele_path(self, mode) -> str:
def _get_ele_path(self, mode):
"""返获取css路径或xpath路径"""
if mode == 'xpath':
txt1 = 'var tag = el.nodeName.toLowerCase();'
@ -206,12 +195,12 @@ class DriverElement(DrissionElement):
# -----------------driver独有属性和方法-------------------
@property
def size(self) -> dict:
def size(self):
"""返回元素宽和高"""
return self.inner_ele.size
@property
def location(self) -> dict:
def location(self):
"""返回元素左上角坐标"""
return self.inner_ele.location
@ -229,12 +218,12 @@ class DriverElement(DrissionElement):
return self.shadow_root
@property
def pseudo_before(self) -> str:
def pseudo_before(self):
"""返回当前元素的::before伪元素内容"""
return self.style('content', 'before')
@property
def pseudo_after(self) -> str:
def pseudo_after(self):
"""返回当前元素的::after伪元素内容"""
return self.style('content', 'after')
@ -250,23 +239,20 @@ class DriverElement(DrissionElement):
return self._select
@property
def scroll(self) -> 'Scroll':
def scroll(self):
"""用于滚动滚动条的对象"""
if self._scroll is None:
self._scroll = Scroll(self)
return self._scroll
def parent(self, level_or_loc: Union[tuple, str, int] = 1) -> Union['DriverElement', None]:
def parent(self, level_or_loc=1):
"""返回上面某一级父元素,可指定层数或用查询语法定位 \n
:param level_or_loc: 第几级父元素或定位符
:return: 上级元素对象
"""
return super().parent(level_or_loc)
def prev(self,
index: int = 1,
filter_loc: Union[tuple, str] = '',
timeout: float = 0) -> Union['DriverElement', str, None]:
def prev(self, index=1, filter_loc='', timeout=0):
"""返回前面的一个兄弟元素,可用查询语法筛选,可指定返回筛选结果的第几个 \n
:param index: 前面第几个查询结果元素
:param filter_loc: 用于筛选元素的查询语法
@ -275,10 +261,7 @@ class DriverElement(DrissionElement):
"""
return super().prev(index, filter_loc, timeout)
def next(self,
index: int = 1,
filter_loc: Union[tuple, str] = '',
timeout: float = 0) -> Union['DriverElement', str, None]:
def next(self, index=1, filter_loc='', timeout=0):
"""返回后面的一个兄弟元素,可用查询语法筛选,可指定返回筛选结果的第几个 \n
:param index: 后面第几个查询结果元素
:param filter_loc: 用于筛选元素的查询语法
@ -287,10 +270,7 @@ class DriverElement(DrissionElement):
"""
return super().next(index, filter_loc, timeout)
def before(self,
index: int = 1,
filter_loc: Union[tuple, str] = '',
timeout: float = None) -> Union['DriverElement', str, None]:
def before(self, index=1, filter_loc='', timeout=None):
"""返回当前元素前面的一个元素可指定筛选条件和第几个。查找范围不限兄弟元而是整个DOM文档 \n
:param index: 前面第几个查询结果元素
:param filter_loc: 用于筛选元素的查询语法
@ -299,10 +279,7 @@ class DriverElement(DrissionElement):
"""
return super().before(index, filter_loc, timeout)
def after(self,
index: int = 1,
filter_loc: Union[tuple, str] = '',
timeout: float = None) -> Union['DriverElement', str, None]:
def after(self, index=1, filter_loc='', timeout=None):
"""返回当前元素后面的一个元素可指定筛选条件和第几个。查找范围不限兄弟元而是整个DOM文档 \n
:param index: 后面第几个查询结果元素
:param filter_loc: 用于筛选元素的查询语法
@ -311,9 +288,7 @@ class DriverElement(DrissionElement):
"""
return super().after(index, filter_loc, timeout)
def prevs(self,
filter_loc: Union[tuple, str] = '',
timeout: float = 0) -> List[Union['DriverElement', str]]:
def prevs(self, filter_loc='', timeout=0):
"""返回前面全部兄弟元素或节点组成的列表,可用查询语法筛选 \n
:param filter_loc: 用于筛选元素的查询语法
:param timeout: 查找元素的超时时间
@ -321,9 +296,7 @@ class DriverElement(DrissionElement):
"""
return super().prevs(filter_loc, timeout)
def nexts(self,
filter_loc: Union[tuple, str] = '',
timeout: float = 0) -> List[Union['DriverElement', str]]:
def nexts(self, filter_loc='', timeout=0):
"""返回后面全部兄弟元素或节点组成的列表,可用查询语法筛选 \n
:param filter_loc: 用于筛选元素的查询语法
:param timeout: 查找元素的超时时间
@ -331,9 +304,7 @@ class DriverElement(DrissionElement):
"""
return super().nexts(filter_loc, timeout)
def befores(self,
filter_loc: Union[tuple, str] = '',
timeout: float = None) -> List[Union['DriverElement', str]]:
def befores(self, filter_loc='', timeout=None):
"""返回当前元素后面符合条件的全部兄弟元素或节点组成的列表可用查询语法筛选。查找范围不限兄弟元而是整个DOM文档 \n
:param filter_loc: 用于筛选元素的查询语法
:param timeout: 查找元素的超时时间
@ -341,9 +312,7 @@ class DriverElement(DrissionElement):
"""
return super().befores(filter_loc, timeout)
def afters(self,
filter_loc: Union[tuple, str] = '',
timeout: float = None) -> List[Union['DriverElement', str]]:
def afters(self, filter_loc='', timeout=None):
"""返回当前元素前面符合条件的全部兄弟元素或节点组成的列表可用查询语法筛选。查找范围不限兄弟元而是整个DOM文档 \n
:param filter_loc: 用于筛选元素的查询语法
:param timeout: 查找元素的超时时间
@ -351,7 +320,7 @@ class DriverElement(DrissionElement):
"""
return super().afters(filter_loc, timeout)
def left(self, index: int = 1, filter_loc: Union[tuple, str] = '') -> 'DriverElement':
def left(self, index=1, filter_loc=''):
"""获取网页上显示在当前元素左边的某个元素,可设置选取条件,可指定结果中第几个 \n
:param index: 获取第几个
:param filter_loc: 筛选条件可用selenium的(By, str)也可用本库定位语法
@ -360,7 +329,7 @@ class DriverElement(DrissionElement):
eles = self._get_relative_eles('left', filter_loc)
return eles[index - 1] if index <= len(eles) else None
def right(self, index: int = 1, filter_loc: Union[tuple, str] = '') -> 'DriverElement':
def right(self, index=1, filter_loc=''):
"""获取网页上显示在当前元素右边的某个元素,可设置选取条件,可指定结果中第几个 \n
:param index: 获取第几个
:param filter_loc: 筛选条件可用selenium的(By, str)也可用本库定位语法
@ -369,7 +338,7 @@ class DriverElement(DrissionElement):
eles = self._get_relative_eles('right', filter_loc)
return eles[index - 1] if index <= len(eles) else None
def above(self, index: int = 1, filter_loc: Union[tuple, str] = '') -> 'DriverElement':
def above(self, index=1, filter_loc=''):
"""获取网页上显示在当前元素上边的某个元素,可设置选取条件,可指定结果中第几个 \n
:param index: 获取第几个
:param filter_loc: 筛选条件可用selenium的(By, str)也可用本库定位语法
@ -378,7 +347,7 @@ class DriverElement(DrissionElement):
eles = self._get_relative_eles('left', filter_loc)
return eles[index - 1] if index <= len(eles) else None
def below(self, index: int = 1, filter_loc: Union[tuple, str] = '') -> 'DriverElement':
def below(self, index=1, filter_loc=''):
"""获取网页上显示在当前元素下边的某个元素,可设置选取条件,可指定结果中第几个 \n
:param index: 获取第几个
:param filter_loc: 筛选条件可用selenium的(By, str)也可用本库定位语法
@ -387,7 +356,7 @@ class DriverElement(DrissionElement):
eles = self._get_relative_eles('left', filter_loc)
return eles[index - 1] if index <= len(eles) else None
def near(self, index: int = 1, filter_loc: Union[tuple, str] = '') -> 'DriverElement':
def near(self, index=1, filter_loc=''):
"""获取网页上显示在当前元素最近的某个元素,可设置选取条件,可指定结果中第几个 \n
:param index: 获取第几个
:param filter_loc: 筛选条件可用selenium的(By, str)也可用本库定位语法
@ -396,44 +365,42 @@ class DriverElement(DrissionElement):
eles = self._get_relative_eles('near', filter_loc)
return eles[index - 1] if index <= len(eles) else None
def lefts(self, filter_loc: Union[tuple, str] = '') -> List['DriverElement']:
def lefts(self, filter_loc=''):
"""获取网页上显示在当前元素左边的所有元素,可设置选取条件,从近到远排列 \n
:param filter_loc: 筛选条件可用selenium的(By, str)也可用本库定位语法
:return: DriverElement对象组成的列表
"""
return self._get_relative_eles('left', filter_loc)
def rights(self, filter_loc: Union[tuple, str] = '') -> List['DriverElement']:
def rights(self, filter_loc=''):
"""获取网页上显示在当前元素右边的所有元,可设置选取条件,从近到远排列 \n
:param filter_loc: 筛选条件可用selenium的(By, str)也可用本库定位语法
:return: DriverElement对象组成的列表
"""
return self._get_relative_eles('right', filter_loc)
def aboves(self, filter_loc: Union[tuple, str] = '') -> List['DriverElement']:
def aboves(self, filter_loc=''):
"""获取网页上显示在当前元素上边的所有元素,可设置选取条件,从近到远排列 \n
:param filter_loc: 筛选条件可用selenium的(By, str)也可用本库定位语法
:return: DriverElement对象组成的列表
"""
return self._get_relative_eles('left', filter_loc)
def belows(self, filter_loc: Union[tuple, str] = '') -> List['DriverElement']:
def belows(self, filter_loc=''):
"""获取网页上显示在当前元素下边的所有元素,可设置选取条件,从近到远排列 \n
:param filter_loc: 筛选条件可用selenium的(By, str)也可用本库定位语法
:return: DriverElement对象组成的列表
"""
return self._get_relative_eles('left', filter_loc)
def nears(self, filter_loc: Union[tuple, str] = '') -> List['DriverElement']:
def nears(self, filter_loc=''):
"""获取网页上显示在当前元素附近元素,可设置选取条件,从近到远排列 \n
:param filter_loc: 筛选条件可用selenium的(By, str)也可用本库定位语法
:return: DriverElement对象组成的列表
"""
return self._get_relative_eles('near', filter_loc)
def wait_ele(self,
loc_or_ele: Union[str, tuple, DrissionElement, WebElement],
timeout: float = None) -> 'ElementWaiter':
def wait_ele(self, loc_or_ele, timeout=None):
"""等待子元素从dom删除、显示、隐藏 \n
:param loc_or_ele: 可以是元素查询字符串loc元组
:param timeout: 等待超时时间
@ -441,7 +408,7 @@ class DriverElement(DrissionElement):
"""
return ElementWaiter(self, loc_or_ele, timeout)
def style(self, style: str, pseudo_ele: str = '') -> str:
def style(self, style, pseudo_ele=''):
"""返回元素样式属性值,可获取伪元素属性值 \n
:param style: 样式属性名称
:param pseudo_ele: 伪元素名称如有
@ -453,7 +420,7 @@ class DriverElement(DrissionElement):
return None if r == 'none' else r
def click(self, by_js: bool = None, timeout: float = None) -> bool:
def click(self, by_js=None, timeout=None):
"""点击元素 \n
尝试点击直到超时若都失败就改用js点击 \n
:param by_js: 是否用js点击为True时直接用js点击为False时重试失败也不会改用js
@ -485,10 +452,7 @@ class DriverElement(DrissionElement):
return False
def click_at(self,
x: Union[int, str] = None,
y: Union[int, str] = None,
by_js: bool = False) -> None:
def click_at(self, x=None, y=None, by_js=False):
"""带偏移量点击本元素相对于左上角坐标。不传入x或y值时点击元素中点 \n
:param x: 相对元素左上角坐标的x轴偏移量
:param y: 相对元素左上角坐标的y轴偏移量
@ -514,12 +478,12 @@ 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 r_click(self) -> None:
def r_click(self):
"""右键单击"""
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:
def r_click_at(self, x=None, y=None):
"""带偏移量右键单击本元素相对于左上角坐标。不传入x或y值时点击元素中点 \n
:param x: 相对元素左上角坐标的x轴偏移量
:param y: 相对元素左上角坐标的y轴偏移量
@ -530,11 +494,7 @@ class DriverElement(DrissionElement):
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,
vals: Union[str, tuple],
clear: bool = True,
insure: bool = True,
timeout: float = None) -> bool:
def input(self, vals, clear=True, insure=True, timeout=None):
"""输入文本或组合键也可用于输入文件路径到input元素文件间用\n间隔) \n
:param vals: 文本值或按键组合
:param clear: 输入前是否清空文本框
@ -580,7 +540,7 @@ class DriverElement(DrissionElement):
self.inner_ele.send_keys(enter)
return True
def run_script(self, script: str, *args) -> Any:
def run_script(self, script, *args):
"""执行js代码代码中用arguments[0]表示自己 \n
:param script: js文本
:param args: 传入的参数
@ -588,7 +548,7 @@ class DriverElement(DrissionElement):
"""
return self.inner_ele.parent.execute_script(script, self.inner_ele, *args)
def submit(self) -> Union[bool, None]:
def submit(self):
"""提交表单"""
try:
self.inner_ele.submit()
@ -596,7 +556,7 @@ class DriverElement(DrissionElement):
except Exception:
pass
def clear(self, insure: bool = True) -> Union[None, bool]:
def clear(self, insure=True):
"""清空元素文本 \n
:param insure: 是否确保清空
:return: 是否清空成功不能清空的元素返回None
@ -611,19 +571,19 @@ class DriverElement(DrissionElement):
except InvalidElementStateException:
return None
def is_selected(self) -> bool:
def is_selected(self):
"""是否选中"""
return self.inner_ele.is_selected()
def is_enabled(self) -> bool:
def is_enabled(self):
"""是否可用"""
return self.inner_ele.is_enabled()
def is_displayed(self) -> bool:
def is_displayed(self):
"""是否可见"""
return self.inner_ele.is_displayed()
def is_valid(self) -> bool:
def is_valid(self):
"""用于判断元素是否还在DOM内应对页面跳转元素不能用的情况"""
try:
self.is_enabled()
@ -631,7 +591,7 @@ class DriverElement(DrissionElement):
except Exception:
return False
def screenshot(self, path: str = None, filename: str = None, as_bytes: bool = False) -> Union[str, bytes]:
def screenshot(self, path=None, filename=None, as_bytes=False):
"""对元素进行截图 \n
:param path: 保存路径
:param filename: 图片文件名不传入时以元素tag name命名
@ -661,14 +621,14 @@ class DriverElement(DrissionElement):
return img_path
def prop(self, prop: str) -> str:
def prop(self, prop):
"""获取property属性值 \n
:param prop: 属性名
:return: 属性值文本
"""
return format_html(self.inner_ele.get_property(prop))
def set_prop(self, prop: str, value: str) -> bool:
def set_prop(self, prop, value):
"""设置元素property属性 \n
:param prop: 属性名
:param value: 属性值
@ -681,7 +641,7 @@ class DriverElement(DrissionElement):
except Exception:
return False
def set_attr(self, attr: str, value: str) -> bool:
def set_attr(self, attr, value):
"""设置元素attribute属性 \n
:param attr: 属性名
:param value: 属性值
@ -693,7 +653,7 @@ class DriverElement(DrissionElement):
except Exception:
return False
def remove_attr(self, attr: str) -> bool:
def remove_attr(self, attr):
"""删除元素attribute属性 \n
:param attr: 属性名
:return: 是否删除成功
@ -704,7 +664,7 @@ class DriverElement(DrissionElement):
except Exception:
return False
def drag(self, x: int, y: int, speed: int = 40, shake: bool = True) -> None:
def drag(self, x, y, speed=40, shake=True):
"""拖拽当前元素到相对位置 \n
:param x: x变化值
:param y: y变化值
@ -716,10 +676,7 @@ class DriverElement(DrissionElement):
y += self.location['y'] + self.size['height'] // 2
self.drag_to((x, y), speed, shake)
def drag_to(self,
ele_or_loc: Union[tuple, WebElement, DrissionElement],
speed: int = 40,
shake: bool = True) -> None:
def drag_to(self, ele_or_loc, speed=40, shake=True):
"""拖拽当前元素,目标为另一个元素或坐标元组 \n
:param ele_or_loc: 另一个元素或坐标元组坐标为元素中点的坐标
:param speed: 拖动的速度传入0即瞬间到达
@ -759,7 +716,7 @@ class DriverElement(DrissionElement):
current_x, current_y = x, y
actions.release().perform()
def hover(self, x: int = None, y: int = None) -> None:
def hover(self, x=None, y=None):
"""鼠标悬停可接受偏移量偏移量相对于元素左上角坐标。不传入x或y值时悬停在元素中点 \n
:param x: 相对元素左上角坐标的x轴偏移量
:param y: 相对元素左上角坐标的y轴偏移量
@ -770,9 +727,7 @@ class DriverElement(DrissionElement):
y = int(y) if y is not None else self.size['height'] // 2
ActionChains(self.page.driver).move_to_element_with_offset(self.inner_ele, x, y).perform()
def _get_relative_eles(self,
mode: str,
loc: Union[tuple, str] = '') -> Union[List['DriverElement'], 'DriverElement']:
def _get_relative_eles(self, mode, loc=''):
"""获取网页上相对于当前元素周围的某个元素,可设置选取条件 \n
:param mode: 可选'left', 'right', 'above', 'below', 'near'
:param loc: 筛选条件可用selenium的(By, str)也可用本库定位语法
@ -801,10 +756,7 @@ class DriverElement(DrissionElement):
raise ValueError('未找到元素,请检查浏览器版本,低版本的浏览器无法使用此方法。')
def make_driver_ele(page_or_ele,
loc: Union[str, Tuple[str, str]],
single: bool = True,
timeout: float = None) -> Union[DriverElement, str, None, List[Union[DriverElement, str]]]:
def make_driver_ele(page_or_ele, loc, single=True, timeout=None):
"""执行driver模式元素的查找 \n
页面查找元素及元素查找下级元素皆使用此方法 \n
:param page_or_ele: DriverPage对象或DriverElement对象
@ -873,7 +825,7 @@ def make_driver_ele(page_or_ele,
class ElementsByXpath(object):
"""用js通过xpath获取元素、节点或属性与WebDriverWait配合使用"""
def __init__(self, page, xpath: str = None, single: bool = False, timeout: float = 10):
def __init__(self, page, xpath=None, single=False, timeout=10):
"""
:param page: DrissionPage对象
:param xpath: xpath文本
@ -885,8 +837,7 @@ class ElementsByXpath(object):
self.single = single
self.timeout = timeout
def __call__(self, ele_or_driver: Union[RemoteWebDriver, WebElement]) \
-> Union[str, DriverElement, None, List[str or DriverElement]]:
def __call__(self, ele_or_driver):
def get_nodes(node=None, xpath_txt=None, type_txt='7'):
"""用js通过xpath获取元素、节点或属性
@ -982,7 +933,7 @@ class Select(object):
self.inner_ele = ele
self.select_ele = SeleniumSelect(ele.inner_ele)
def __call__(self, text_or_index: Union[str, int, list, tuple], timeout=None) -> bool:
def __call__(self, text_or_index, timeout=None):
"""选定下拉列表中子元素 \n
:param text_or_index: 根据文本值选或序号择选项若允许多选传入list或tuple可多选
:param timeout: 超时时间不输入默认实用页面超时时间
@ -992,17 +943,17 @@ class Select(object):
return self.select(text_or_index, timeout=timeout)
@property
def is_multi(self) -> bool:
def is_multi(self):
"""返回是否多选表单"""
return self.select_ele.is_multiple
@property
def options(self) -> List[DriverElement]:
def options(self):
"""返回所有选项元素组成的列表"""
return self.inner_ele.eles('tag:option')
@property
def selected_option(self) -> Union[DriverElement, None]:
def selected_option(self):
"""返回第一个被选中的option元素 \n
:return: DriverElement对象或None
"""
@ -1010,17 +961,17 @@ class Select(object):
return None if ele is None else DriverElement(ele, self.inner_ele.page)
@property
def selected_options(self) -> List[DriverElement]:
def selected_options(self):
"""返回所有被选中的option元素列表 \n
:return: DriverElement对象组成的列表
"""
return [x for x in self.options if x.is_selected()]
def clear(self) -> None:
def clear(self):
"""清除所有已选项"""
self.select_ele.deselect_all()
def select(self, text_or_index: Union[str, int, list, tuple], timeout=None) -> bool:
def select(self, text_or_index, timeout=None):
"""选定下拉列表中子元素 \n
:param text_or_index: 根据文本值选或序号择选项若允许多选传入list或tuple可多选
:param timeout: 超时时间不输入默认实用页面超时时间
@ -1030,7 +981,7 @@ class Select(object):
timeout = timeout if timeout is not None else self.inner_ele.page.timeout
return self._select(text_or_index, i, False, timeout)
def select_by_value(self, value: Union[str, list, tuple], timeout=None) -> bool:
def select_by_value(self, value, timeout=None):
"""此方法用于根据value值选择项。当元素是多选列表时可以接收list或tuple \n
:param value: value属性值传入list或tuple可选择多项
:param timeout: 超时时间不输入默认实用页面超时时间
@ -1039,7 +990,7 @@ class Select(object):
timeout = timeout if timeout is not None else self.inner_ele.page.timeout
return self._select(value, 'value', False, timeout)
def deselect(self, text_or_index: Union[str, int, list, tuple], timeout=None) -> bool:
def deselect(self, text_or_index, timeout=None):
"""取消选定下拉列表中子元素 \n
:param text_or_index: 根据文本或序号取消择选项若允许多选传入list或tuple可取消多项
:param timeout: 超时时间不输入默认实用页面超时时间
@ -1049,7 +1000,7 @@ class Select(object):
timeout = timeout if timeout is not None else self.inner_ele.page.timeout
return self._select(text_or_index, i, True, timeout)
def deselect_by_value(self, value: Union[str, list, tuple], timeout=None) -> bool:
def deselect_by_value(self, value, timeout=None):
"""此方法用于根据value值取消选择项。当元素是多选列表时可以接收list或tuple \n
:param value: value属性值传入list或tuple可取消多项
:param timeout: 超时时间不输入默认实用页面超时时间
@ -1058,7 +1009,7 @@ class Select(object):
timeout = timeout if timeout is not None else self.inner_ele.page.timeout
return self._select(value, 'value', True, timeout)
def invert(self) -> None:
def invert(self):
"""反选"""
if not self.is_multi:
raise NotImplementedError("只能对多项选框执行反选。")
@ -1066,11 +1017,7 @@ class Select(object):
for i in self.options:
i.click(by_js=True)
def _select(self,
text_value_index: Union[str, int, list, tuple] = None,
para_type: str = 'text',
deselect: bool = False,
timeout=None) -> bool:
def _select(self, text_value_index, para_type='text', deselect=False, timeout=None):
"""选定或取消选定下拉列表中子元素 \n
:param text_value_index: 根据文本值选或序号择选项若允许多选传入list或tuple可多选
:param para_type: 参数类型可选 'text''value''index'
@ -1119,10 +1066,7 @@ class Select(object):
else:
raise TypeError('只能传入str、int、list和tuple类型。')
def _select_multi(self,
text_value_index: Union[list, tuple] = None,
para_type: str = 'text',
deselect: bool = False) -> bool:
def _select_multi(self, text_value_index=None, para_type='text', deselect=False) -> bool:
"""选定或取消选定下拉列表中多个子元素 \n
:param text_value_index: 根据文本值选或序号择选多项
:param para_type: 参数类型可选 'text''value''index'
@ -1150,10 +1094,7 @@ class Select(object):
class ElementWaiter(object):
"""等待元素在dom中某种状态如删除、显示、隐藏"""
def __init__(self,
page_or_ele,
loc_or_ele: Union[str, tuple, DriverElement, WebElement],
timeout: float = None):
def __init__(self, page_or_ele, loc_or_ele, timeout=None):
"""等待元素在dom中某种状态如删除、显示、隐藏 \n
:param page_or_ele: 页面或父元素
:param loc_or_ele: 要等待的元素可以是已有元素定位符
@ -1183,19 +1124,19 @@ class ElementWaiter(object):
self.timeout = timeout if timeout is not None else page.timeout
def delete(self) -> bool:
def delete(self):
"""等待元素从dom删除"""
return self._wait_ele('del')
def display(self) -> bool:
def display(self):
"""等待元素从dom显示"""
return self._wait_ele('display')
def hidden(self) -> bool:
def hidden(self):
"""等待元素从dom隐藏"""
return self._wait_ele('hidden')
def _wait_ele(self, mode: str) -> bool:
def _wait_ele(self, mode):
"""执行等待
:param mode: 等待模式
:return: 是否等待成功
@ -1248,27 +1189,27 @@ class Scroll(object):
self.t1 = 'window'
self.t2 = 'document.documentElement'
def to_top(self) -> None:
def to_top(self):
"""滚动到顶端,水平位置不变"""
self.driver.run_script(f'{self.t1}.scrollTo({self.t2}.scrollLeft,0);')
def to_bottom(self) -> None:
def to_bottom(self):
"""滚动到底端,水平位置不变"""
self.driver.run_script(f'{self.t1}.scrollTo({self.t2}.scrollLeft,{self.t2}.scrollHeight);')
def to_half(self) -> None:
def to_half(self):
"""滚动到垂直中间位置,水平位置不变"""
self.driver.run_script(f'{self.t1}.scrollTo({self.t2}.scrollLeft,{self.t2}.scrollHeight/2);')
def to_rightmost(self) -> None:
def to_rightmost(self):
"""滚动到最右边,垂直位置不变"""
self.driver.run_script(f'{self.t1}.scrollTo({self.t2}.scrollWidth,{self.t2}.scrollTop);')
def to_leftmost(self) -> None:
def to_leftmost(self):
"""滚动到最左边,垂直位置不变"""
self.driver.run_script(f'{self.t1}.scrollTo(0,{self.t2}.scrollTop);')
def to_location(self, x: int, y: int) -> None:
def to_location(self, x, y):
"""滚动到指定位置 \n
:param x: 水平距离
:param y: 垂直距离
@ -1276,7 +1217,7 @@ class Scroll(object):
"""
self.driver.run_script(f'{self.t1}.scrollTo({x},{y});')
def up(self, pixel: int = 300) -> None:
def up(self, pixel=300):
"""向上滚动若干像素,水平位置不变 \n
:param pixel: 滚动的像素
:return: None
@ -1284,14 +1225,14 @@ class Scroll(object):
pixel = -pixel
self.driver.run_script(f'{self.t1}.scrollBy(0,{pixel});')
def down(self, pixel: int = 300) -> None:
def down(self, pixel=300):
"""向下滚动若干像素,水平位置不变 \n
:param pixel: 滚动的像素
:return: None
"""
self.driver.run_script(f'{self.t1}.scrollBy(0,{pixel});')
def left(self, pixel: int = 300) -> None:
def left(self, pixel=300):
"""向左滚动若干像素,垂直位置不变 \n
:param pixel: 滚动的像素
:return: None
@ -1299,7 +1240,7 @@ class Scroll(object):
pixel = -pixel
self.driver.run_script(f'{self.t1}.scrollBy({pixel},0);')
def right(self, pixel: int = 300) -> None:
def right(self, pixel=300):
"""向右滚动若干像素,垂直位置不变 \n
:param pixel: 滚动的像素
:return: None

View File

@ -15,281 +15,207 @@ from .session_element import SessionElement
class DriverElement(DrissionElement):
"""driver模式的元素对象包装了一个WebElement对象并封装了常用功能"""
def __init__(self, ele: WebElement, page=...):
def __init__(self, ele: WebElement, page:Union[DriverPage, MixPage]=...):
self._inner_ele: WebElement = ...
self._select: Select = ...
self._scroll: Scroll = ...
self.page: Union[DriverPage, MixPage] = ...
def __repr__(self) -> str:
...
def __repr__(self) -> str: ...
def __call__(self,
loc_or_str: Union[Tuple[str, str], str],
timeout: float = ...) -> Union['DriverElement', str, None]:
...
timeout: float = ...) -> Union['DriverElement', str, None]: ...
# -----------------共有属性和方法-------------------
@property
def inner_ele(self) -> WebElement:
...
def inner_ele(self) -> WebElement: ...
@property
def tag(self) -> str:
...
def tag(self) -> str: ...
@property
def html(self) -> str:
...
def html(self) -> str: ...
@property
def inner_html(self) -> str:
...
def inner_html(self) -> str: ...
@property
def attrs(self) -> dict:
...
def attrs(self) -> dict: ...
@property
def text(self) -> str:
...
def text(self) -> str: ...
@property
def raw_text(self) -> str:
...
def raw_text(self) -> str: ...
def attr(self, attr: str) -> str:
...
def attr(self, attr: str) -> str: ...
def ele(self,
loc_or_str: Union[Tuple[str, str], str],
timeout: float = ...) -> Union['DriverElement', str, None]:
...
timeout: float = ...) -> Union['DriverElement', str, None]: ...
def eles(self,
loc_or_str: Union[Tuple[str, str], str],
timeout: float = ...) -> List[Union['DriverElement', str]]:
...
timeout: float = ...) -> List[Union['DriverElement', str]]: ...
def s_ele(self, loc_or_str: Union[Tuple[str, str], str] = ...) -> Union[SessionElement, str, None]:
...
def s_ele(self, loc_or_str: Union[Tuple[str, str], str] = ...) -> Union[SessionElement, str, None]: ...
def s_eles(self, loc_or_str: Union[Tuple[str, str], str] = ...) -> List[Union[SessionElement, str]]:
...
def s_eles(self, loc_or_str: Union[Tuple[str, str], str] = ...) -> List[Union[SessionElement, str]]: ...
def _ele(self,
loc_or_str: Union[Tuple[str, str], str],
timeout: float = ...,
single: bool = ...,
relative: bool = ...) -> Union['DriverElement', str, None, List[Union['DriverElement', str]]]:
...
relative: bool = ...) -> Union['DriverElement', str, None, List[Union['DriverElement', str]]]: ...
def _get_ele_path(self, mode) -> str:
...
def _get_ele_path(self, mode) -> str: ...
# -----------------driver独有属性和方法-------------------
@property
def size(self) -> dict:
...
def size(self) -> dict: ...
@property
def location(self) -> dict:
...
def location(self) -> dict: ...
@property
def shadow_root(self) -> ShadowRootElement:
...
def shadow_root(self) -> ShadowRootElement: ...
@property
def sr(self) -> ShadowRootElement:
...
def sr(self) -> ShadowRootElement: ...
@property
def pseudo_before(self) -> str:
...
def pseudo_before(self) -> str: ...
@property
def pseudo_after(self) -> str:
...
def pseudo_after(self) -> str: ...
@property
def select(self) -> Select:
...
def select(self) -> Select: ...
@property
def scroll(self) -> Scroll:
...
def scroll(self) -> Scroll: ...
def parent(self, level_or_loc: Union[tuple, str, int] = ...) -> Union['DriverElement', None]:
...
def parent(self, level_or_loc: Union[tuple, str, int] = ...) -> Union['DriverElement', None]: ...
def prev(self,
index: int = ...,
filter_loc: Union[tuple, str] = ...,
timeout: float = ...) -> Union['DriverElement', str, None]:
...
timeout: float = ...) -> Union['DriverElement', str, None]: ...
def next(self,
index: int = ...,
filter_loc: Union[tuple, str] = ...,
timeout: float = ...) -> Union['DriverElement', str, None]:
...
timeout: float = ...) -> Union['DriverElement', str, None]: ...
def before(self,
index: int = ...,
filter_loc: Union[tuple, str] = ...,
timeout: float = ...) -> Union['DriverElement', str, None]:
...
timeout: float = ...) -> Union['DriverElement', str, None]: ...
def after(self,
index: int = ...,
filter_loc: Union[tuple, str] = ...,
timeout: float = ...) -> Union['DriverElement', str, None]:
...
timeout: float = ...) -> Union['DriverElement', str, None]: ...
def prevs(self,
filter_loc: Union[tuple, str] = ...,
timeout: float = ...) -> List[Union['DriverElement', str]]:
...
timeout: float = ...) -> List[Union['DriverElement', str]]: ...
def nexts(self,
filter_loc: Union[tuple, str] = ...,
timeout: float = ...) -> List[Union['DriverElement', str]]:
...
timeout: float = ...) -> List[Union['DriverElement', str]]: ...
def befores(self,
filter_loc: Union[tuple, str] = ...,
timeout: float = ...) -> List[Union['DriverElement', str]]:
...
timeout: float = ...) -> List[Union['DriverElement', str]]: ...
def afters(self,
filter_loc: Union[tuple, str] = ...,
timeout: float = ...) -> List[Union['DriverElement', str]]:
...
timeout: float = ...) -> List[Union['DriverElement', str]]: ...
def left(self, index: int = ..., filter_loc: Union[tuple, str] = ...) -> DriverElement:
...
def left(self, index: int = ..., filter_loc: Union[tuple, str] = ...) -> DriverElement: ...
def right(self, index: int = ..., filter_loc: Union[tuple, str] = ...) -> 'DriverElement':
...
def right(self, index: int = ..., filter_loc: Union[tuple, str] = ...) -> 'DriverElement': ...
def above(self, index: int = ..., filter_loc: Union[tuple, str] = ...) -> 'DriverElement':
...
def above(self, index: int = ..., filter_loc: Union[tuple, str] = ...) -> 'DriverElement': ...
def below(self, index: int = ..., filter_loc: Union[tuple, str] = ...) -> 'DriverElement':
...
def below(self, index: int = ..., filter_loc: Union[tuple, str] = ...) -> 'DriverElement': ...
def near(self, index: int = ..., filter_loc: Union[tuple, str] = ...) -> 'DriverElement':
...
def near(self, index: int = ..., filter_loc: Union[tuple, str] = ...) -> 'DriverElement': ...
def lefts(self, filter_loc: Union[tuple, str] = ...) -> List['DriverElement']:
...
def lefts(self, filter_loc: Union[tuple, str] = ...) -> List['DriverElement']: ...
def rights(self, filter_loc: Union[tuple, str] = ...) -> List['DriverElement']:
...
def rights(self, filter_loc: Union[tuple, str] = ...) -> List['DriverElement']: ...
def aboves(self, filter_loc: Union[tuple, str] = ...) -> List['DriverElement']:
...
def aboves(self, filter_loc: Union[tuple, str] = ...) -> List['DriverElement']: ...
def belows(self, filter_loc: Union[tuple, str] = ...) -> List['DriverElement']:
...
def belows(self, filter_loc: Union[tuple, str] = ...) -> List['DriverElement']: ...
def nears(self, filter_loc: Union[tuple, str] = ...) -> List['DriverElement']:
...
def nears(self, filter_loc: Union[tuple, str] = ...) -> List['DriverElement']: ...
def wait_ele(self,
loc_or_ele: Union[str, tuple, DrissionElement, WebElement],
timeout: float = ...) -> 'ElementWaiter':
...
timeout: float = ...) -> 'ElementWaiter': ...
def style(self, style: str, pseudo_ele: str = ...) -> str:
...
def style(self, style: str, pseudo_ele: str = ...) -> str: ...
def click(self, by_js: bool = ..., timeout: float = ...) -> bool:
...
def click(self, by_js: bool = ..., timeout: float = ...) -> bool: ...
def click_at(self,
x: Union[int, str] = ...,
y: Union[int, str] = ...,
by_js: bool = ...) -> None:
...
by_js: bool = ...) -> None: ...
def r_click(self) -> None:
...
def r_click(self) -> None: ...
def r_click_at(self, x: Union[int, str] = ..., y: Union[int, str] = ...) -> None:
...
def r_click_at(self, x: Union[int, str] = ..., y: Union[int, str] = ...) -> None: ...
def input(self,
vals: Union[str, tuple],
clear: bool = ...,
insure: bool = ...,
timeout: float = ...) -> bool:
...
timeout: float = ...) -> bool: ...
def run_script(self, script: str, *args) -> Any:
...
def run_script(self, script: str, *args) -> Any: ...
def submit(self) -> Union[bool, None]:
...
def submit(self) -> Union[bool, None]: ...
def clear(self, insure: bool = ...) -> Union[None, bool]:
...
def clear(self, insure: bool = ...) -> Union[None, bool]: ...
def is_selected(self) -> bool:
...
def is_selected(self) -> bool: ...
def is_enabled(self) -> bool:
...
def is_enabled(self) -> bool: ...
def is_displayed(self) -> bool:
...
def is_displayed(self) -> bool: ...
def is_valid(self) -> bool:
...
def is_valid(self) -> bool: ...
def screenshot(self, path: str = ..., filename: str = ..., as_bytes: bool = ...) -> Union[str, bytes]:
...
def screenshot(self, path: str = ..., filename: str = ..., as_bytes: bool = ...) -> Union[str, bytes]: ...
def prop(self, prop: str) -> str:
...
def prop(self, prop: str) -> str: ...
def set_prop(self, prop: str, value: str) -> bool:
...
def set_prop(self, prop: str, value: str) -> bool: ...
def set_attr(self, attr: str, value: str) -> bool:
...
def set_attr(self, attr: str, value: str) -> bool: ...
def remove_attr(self, attr: str) -> bool:
"""删除元素attribute属性 \n
:param attr: 属性名
:return: 是否删除成功
"""
try:
self.run_script(f'arguments[0].removeAttribute("{attr}");')
return True
except Exception:
return False
def remove_attr(self, attr: str) -> bool: ...
def drag(self, x: int, y: int, speed: int = ..., shake: bool = ...) -> None:
...
def drag(self, x: int, y: int, speed: int = ..., shake: bool = ...) -> None: ...
def drag_to(self,
ele_or_loc: Union[tuple, WebElement, DrissionElement],
speed: int = ...,
shake: bool = ...) -> None:
...
shake: bool = ...) -> None: ...
def hover(self, x: int = ..., y: int = ...) -> None:
...
def hover(self, x: int = ..., y: int = ...) -> None: ...
def _get_relative_eles(self,
mode: str,
loc: Union[tuple, str] = ...) -> Union[List['DriverElement'], 'DriverElement']:
...
loc: Union[tuple, str] = ...) -> Union[List['DriverElement'], 'DriverElement']: ...
def make_driver_ele(page_or_ele,
def make_driver_ele(page_or_ele: Union[DriverPage, MixPage,DriverElement, ShadowRootElement],
loc: Union[str, Tuple[str, str]],
single: bool = ...,
timeout: float = ...) -> Union[DriverElement, str, None, List[Union[DriverElement, str]]]: ...
@ -314,7 +240,7 @@ class Select(object):
self.select_ele: SeleniumSelect = ...
self.inner_ele: DriverElement = ...
def __call__(self, text_or_index: Union[str, int, list, tuple], timeout=...) -> bool: ...
def __call__(self, text_or_index: Union[str, int, list, tuple], timeout: float = ...) -> bool: ...
@property
def is_multi(self) -> bool: ...
@ -330,13 +256,13 @@ class Select(object):
def clear(self) -> None: ...
def select(self, text_or_index: Union[str, int, list, tuple], timeout=...) -> bool: ...
def select(self, text_or_index: Union[str, int, list, tuple], timeout: float = ...) -> bool: ...
def select_by_value(self, value: Union[str, list, tuple], timeout=...) -> bool: ...
def select_by_value(self, value: Union[str, list, tuple], timeout: float = ...) -> bool: ...
def deselect(self, text_or_index: Union[str, int, list, tuple], timeout=...) -> bool: ...
def deselect(self, text_or_index: Union[str, int, list, tuple], timeout: float = ...) -> bool: ...
def deselect_by_value(self, value: Union[str, list, tuple], timeout=...) -> bool: ...
def deselect_by_value(self, value: Union[str, list, tuple], timeout: float = ...) -> bool: ...
def invert(self) -> None: ...

View File

@ -8,32 +8,28 @@ from glob import glob
from os import sep
from pathlib import Path
from time import sleep, perf_counter
from typing import Union, List, Any, Tuple
from selenium.common.exceptions import NoAlertPresentException
from selenium.webdriver.chrome.webdriver import WebDriver
from selenium.webdriver.remote.webdriver import WebDriver as RemoteWebDriver
from selenium.webdriver.remote.webelement import WebElement
from selenium.webdriver.support.wait import WebDriverWait
from .base import BasePage
from .common import get_usable_path
from .driver_element import DriverElement, make_driver_ele, Scroll, ElementWaiter
from .session_element import make_session_ele, SessionElement
from .session_element import make_session_ele
class DriverPage(BasePage):
"""DriverPage封装了页面操作的常用功能使用selenium来获取、解析、操作网页"""
def __init__(self, driver: RemoteWebDriver, timeout: float = 10) -> None:
def __init__(self, driver, timeout=10):
"""初始化函数接收一个WebDriver对象用来操作网页"""
super().__init__(timeout)
self._driver = driver
self._wait_object = None
self._scroll = None
def __call__(self, loc_or_str: Union[Tuple[str, str], str, DriverElement, WebElement],
timeout: float = None) -> Union[DriverElement, str, None]:
def __call__(self, loc_or_str, timeout=None):
"""在内部查找元素 \n
ele = page('@id=ele_id') \n
:param loc_or_str: 元素的定位信息可以是loc元组或查询字符串
@ -44,7 +40,7 @@ class DriverPage(BasePage):
# -----------------共有属性和方法-------------------
@property
def url(self) -> Union[str, None]:
def url(self):
"""返回当前网页url"""
if not self._driver or not self.driver.current_url.startswith('http'):
return None
@ -52,21 +48,17 @@ class DriverPage(BasePage):
return self.driver.current_url
@property
def html(self) -> str:
def html(self):
"""返回页面的html文本"""
return self.driver.find_element('xpath', "//*").get_attribute("outerHTML")
@property
def json(self) -> dict:
def json(self):
"""当返回内容是json格式时返回对应的字典"""
from json import loads
return loads(self('t:pre').text)
def get(self,
url: str,
show_errmsg: bool = False,
retry: int = None,
interval: float = None) -> Union[None, bool]:
def get(self, url, show_errmsg=False, retry=None, interval=None):
"""访问url \n
:param url: 目标url
:param show_errmsg: 是否显示和抛出异常
@ -84,9 +76,7 @@ class DriverPage(BasePage):
return self._url_available
def ele(self,
loc_or_ele: Union[Tuple[str, str], str, DriverElement, WebElement],
timeout: float = None) -> Union[DriverElement, str, None]:
def ele(self, loc_or_ele, timeout=None):
"""返回页面中符合条件的第一个元素 \n
:param loc_or_ele: 元素的定位信息可以是元素对象loc元组或查询字符串
:param timeout: 查找元素超时时间默认与页面等待时间一致
@ -94,9 +84,7 @@ class DriverPage(BasePage):
"""
return self._ele(loc_or_ele, timeout)
def eles(self,
loc_or_str: Union[Tuple[str, str], str],
timeout: float = None) -> List[Union[DriverElement, str]]:
def eles(self, loc_or_str, timeout=None):
"""返回页面中所有符合条件的元素 \n
:param loc_or_str: 元素的定位信息可以是loc元组或查询字符串
:param timeout: 查找元素超时时间默认与页面等待时间一致
@ -104,7 +92,7 @@ class DriverPage(BasePage):
"""
return self._ele(loc_or_str, timeout, single=False)
def s_ele(self, loc_or_ele: Union[Tuple[str, str], str, DriverElement] = None) -> Union[SessionElement, str, None]:
def s_ele(self, loc_or_ele=None):
"""查找第一个符合条件的元素以SessionElement形式返回处理复杂页面时效率很高 \n
:param loc_or_ele: 元素的定位信息可以是loc元组或查询字符串
:return: SessionElement对象或属性文本
@ -114,17 +102,14 @@ class DriverPage(BasePage):
else:
return make_session_ele(self, loc_or_ele)
def s_eles(self, loc_or_str: Union[Tuple[str, str], str] = None) -> List[Union[SessionElement, str]]:
def s_eles(self, loc_or_str=None):
"""查找所有符合条件的元素以SessionElement列表形式返回 \n
:param loc_or_str: 元素的定位信息可以是loc元组或查询字符串
:return: SessionElement对象组成的列表
"""
return make_session_ele(self, loc_or_str, single=False)
def _ele(self,
loc_or_ele: Union[Tuple[str, str], str, DriverElement, WebElement],
timeout: float = None,
single: bool = True) -> Union[DriverElement, str, None, List[Union[DriverElement, str]]]:
def _ele(self, loc_or_ele, timeout=None, single=True):
"""返回页面中符合条件的元素,默认返回第一个 \n
:param loc_or_ele: 元素的定位信息可以是元素对象loc元组或查询字符串
:param timeout: 查找元素超时时间
@ -147,7 +132,7 @@ class DriverPage(BasePage):
else:
raise ValueError('loc_or_str参数只能是tuple、str、DriverElement 或 WebElement类型。')
def get_cookies(self, as_dict: bool = False) -> Union[list, dict]:
def get_cookies(self, as_dict=False):
"""返回当前网站cookies"""
if as_dict:
return {cookie['name']: cookie['value'] for cookie in self.driver.get_cookies()}
@ -155,21 +140,17 @@ class DriverPage(BasePage):
return self.driver.get_cookies()
@property
def timeout(self) -> float:
def timeout(self):
"""返回查找元素时等待的秒数"""
return self._timeout
@timeout.setter
def timeout(self, second: float) -> None:
def timeout(self, second):
"""设置查找元素时等待的秒数"""
self._timeout = second
self._wait_object = None
def _d_connect(self,
to_url: str,
times: int = 0,
interval: float = 1,
show_errmsg: bool = False) -> Union[bool, None]:
def _d_connect(self, to_url, times=0, interval=1, show_errmsg=False):
"""尝试连接,重试若干次 \n
:param to_url: 要访问的url
:param times: 重试次数
@ -205,11 +186,11 @@ class DriverPage(BasePage):
# ----------------driver独有属性和方法-----------------------
@property
def driver(self) -> WebDriver:
def driver(self):
return self._driver
@property
def wait_object(self) -> WebDriverWait:
def wait_object(self):
"""返回WebDriverWait对象重用避免每次新建对象"""
if self._wait_object is None:
self._wait_object = WebDriverWait(self.driver, timeout=self.timeout)
@ -217,14 +198,14 @@ class DriverPage(BasePage):
return self._wait_object
@property
def timeouts(self) -> dict:
def timeouts(self):
"""返回三种超时时间selenium4以上版本可用"""
return {'implicit': self.timeout,
'pageLoad': self.driver.timeouts.page_load,
'script': self.driver.timeouts.script}
@property
def tabs_count(self) -> int:
def tabs_count(self):
"""返回标签页数量"""
try:
return len(self.driver.window_handles)
@ -232,34 +213,34 @@ class DriverPage(BasePage):
return 0
@property
def tab_handles(self) -> list:
def tab_handles(self):
"""返回所有标签页handle列表"""
return self.driver.window_handles
@property
def current_tab_index(self) -> int:
def current_tab_index(self):
"""返回当前标签页序号"""
return self.driver.window_handles.index(self.driver.current_window_handle)
@property
def current_tab_handle(self) -> str:
def current_tab_handle(self):
"""返回当前标签页handle"""
return self.driver.current_window_handle
@property
def active_ele(self) -> DriverElement:
def active_ele(self):
"""返回当前焦点所在元素"""
return DriverElement(self.driver.switch_to.active_element, self)
@property
def scroll(self) -> Scroll:
def scroll(self):
"""用于滚动滚动条的对象"""
if self._scroll is None:
self._scroll = Scroll(self)
return self._scroll
@property
def to_frame(self) -> 'ToFrame':
def to_frame(self):
"""用于跳转到frame的对象调用其方法实现跳转 \n
示例 \n
page.to_frame.by_loc('tag:iframe') - 通过传入frame的查询字符串定位 \n
@ -273,7 +254,7 @@ class DriverPage(BasePage):
"""
return ToFrame(self)
def set_timeouts(self, implicit: float = None, pageLoad: float = None, script: float = None) -> None:
def set_timeouts(self, implicit=None, pageLoad=None, script=None):
"""设置超时时间单位为秒selenium4以上版本有效 \n
:param implicit: 查找元素超时时间
:param pageLoad: 页面加载超时时间
@ -289,9 +270,7 @@ class DriverPage(BasePage):
if script is not None:
self.driver.set_script_timeout(script)
def wait_ele(self,
loc_or_ele: Union[str, tuple, DriverElement, WebElement],
timeout: float = None) -> 'ElementWaiter':
def wait_ele(self, loc_or_ele, timeout=None):
"""等待元素从dom删除、显示、隐藏 \n
:param loc_or_ele: 可以是元素查询字符串loc元组
:param timeout: 等待超时时间
@ -299,13 +278,13 @@ class DriverPage(BasePage):
"""
return ElementWaiter(self, loc_or_ele, timeout)
def check_page(self) -> Union[bool, None]:
def check_page(self):
"""检查页面是否符合预期 \n
由子类自行实现各页面的判定规则
"""
return None
def run_script(self, script: str, *args) -> Any:
def run_script(self, script, *args):
"""执行js代码 \n
:param script: js文本
:param args: 传入的参数
@ -313,7 +292,7 @@ class DriverPage(BasePage):
"""
return self.driver.execute_script(script, *args)
def run_async_script(self, script: str, *args) -> Any:
def run_async_script(self, script, *args):
"""以异步方式执行js代码 \n
:param script: js文本
:param args: 传入的参数
@ -321,7 +300,7 @@ class DriverPage(BasePage):
"""
return self.driver.execute_async_script(script, *args)
def run_cdp(self, cmd: str, **cmd_args) -> Any:
def run_cdp(self, cmd, **cmd_args):
"""执行Chrome DevTools Protocol语句
:param cmd: 协议项目
:param cmd_args: 参数
@ -329,7 +308,7 @@ class DriverPage(BasePage):
"""
return self.driver.execute_cdp_cmd(cmd, cmd_args)
def create_tab(self, url: str = '') -> None:
def create_tab(self, url=''):
"""新建并定位到一个标签页,该标签页在最后面 \n
:param url: 新标签页跳转到的网址
:return: None
@ -338,27 +317,27 @@ class DriverPage(BasePage):
if url:
self.get(url)
def close_tabs(self, num_or_handles: Union[int, str, list, tuple] = None) -> None:
def close_tabs(self, num_or_handles=None):
"""关闭传入的标签页,默认关闭当前页。可传入多个 \n
注意当程序使用的是接管的浏览器获取到的 handle 顺序和视觉效果不一致不能按序号关闭 \n
:param num_or_handles:要关闭的标签页序号或handle可传入handle和序号组成的列表或元组为None时关闭当前页
:return: None
"""
tabs = (self.current_tab_handle,) if num_or_handles is None else _get_handles(self.tab_handles, num_or_handles)
tabs = (self.current_tab_handle,) if num_or_handles is None else get_handles(self.tab_handles, num_or_handles)
for i in tabs:
self.driver.switch_to.window(i)
self.driver.close()
self.to_tab(0)
def close_other_tabs(self, num_or_handles: Union[int, str, list, tuple] = None) -> None:
def close_other_tabs(self, num_or_handles=None):
"""关闭传入的标签页以外标签页,默认保留当前页。可传入多个 \n
注意当程序使用的是接管的浏览器获取到的 handle 顺序和视觉效果不一致不能按序号关闭 \n
:param num_or_handles: 要保留的标签页序号或handle可传入handle和序号组成的列表或元组为None时保存当前页
:return: None
"""
all_tabs = self.driver.window_handles
reserve_tabs = {self.current_tab_handle} if num_or_handles is None else _get_handles(all_tabs, num_or_handles)
reserve_tabs = {self.current_tab_handle} if num_or_handles is None else get_handles(all_tabs, num_or_handles)
for i in set(all_tabs) - reserve_tabs:
self.driver.switch_to.window(i)
@ -366,7 +345,7 @@ class DriverPage(BasePage):
self.to_tab(0)
def to_tab(self, num_or_handle: Union[int, str] = 0) -> None:
def to_tab(self, num_or_handle=0):
"""跳转到标签页 \n
注意当程序使用的是接管的浏览器获取到的 handle 顺序和视觉效果不一致 \n
:param num_or_handle: 标签页序号或handle字符串序号第一个为0最后为-1
@ -380,14 +359,14 @@ class DriverPage(BasePage):
tab = self.driver.window_handles[tab] if isinstance(tab, int) else tab
self.driver.switch_to.window(tab)
def set_ua_to_tab(self, ua: str) -> None:
def set_ua_to_tab(self, ua):
"""为当前tab设置user agent只在当前tab有效 \n
:param ua: user agent字符串
:return: None
"""
self.driver.execute_cdp_cmd("Network.setUserAgentOverride", {"userAgent": ua})
def get_session_storage(self, item: str = None) -> Union[str, dict, None]:
def get_session_storage(self, item=None):
"""获取sessionStorage信息不设置item则获取全部 \n
:param item: 要获取的项不设置则返回全部
:return: sessionStorage一个或所有项内容
@ -395,7 +374,7 @@ class DriverPage(BasePage):
js = f'return sessionStorage.getItem("{item}");' if item else 'return sessionStorage;'
return self.run_script(js)
def get_local_storage(self, item: str = None) -> Union[str, dict, None]:
def get_local_storage(self, item=None):
"""获取localStorage信息不设置item则获取全部 \n
:param item: 要获取的项目不设置则返回全部
:return: localStorage一个或所有项内容
@ -403,7 +382,7 @@ class DriverPage(BasePage):
js = f'return localStorage.getItem("{item}");' if item else 'return localStorage;'
return self.run_script(js)
def set_session_storage(self, item: str, value: Union[str, bool]) -> None:
def set_session_storage(self, item, value):
"""设置或删除某项sessionStorage信息 \n
:param item: 要设置的项
:param value: 项的值设置为False时删除该项
@ -412,7 +391,7 @@ class DriverPage(BasePage):
s = f'sessionStorage.removeItem("{item}");' if item is False else f'sessionStorage.setItem("{item}","{value}");'
self.run_script(s)
def set_local_storage(self, item: str, value: Union[str, bool]) -> None:
def set_local_storage(self, item, value):
"""设置或删除某项localStorage信息 \n
:param item: 要设置的项
:param value: 项的值设置为False时删除该项
@ -421,11 +400,7 @@ class DriverPage(BasePage):
s = f'localStorage.removeItem("{item}");' if item is False else f'localStorage.setItem("{item}","{value}");'
self.run_script(s)
def clean_cache(self,
session_storage: bool = True,
local_storage: bool = True,
cache: bool = True,
cookies: bool = True) -> None:
def clean_cache(self, session_storage=True, local_storage=True, cache=True, cookies=True):
"""清除缓存,可选要清除的项 \n
:param session_storage: 是否清除sessionStorage
:param local_storage: 是否清除localStorage
@ -442,7 +417,7 @@ class DriverPage(BasePage):
if cookies:
self.run_cdp('Network.clearBrowserCookies')
def screenshot(self, path: str = None, filename: str = None, as_bytes: bool = False) -> Union[str, bytes]:
def screenshot(self, path=None, filename=None, as_bytes=False):
"""截取页面可见范围截图 \n
:param path: 保存路径
:param filename: 图片文件名不传入时以页面title命名
@ -461,7 +436,7 @@ class DriverPage(BasePage):
self.driver.save_screenshot(img_path)
return img_path
def scroll_to_see(self, loc_or_ele: Union[str, tuple, WebElement, DriverElement]) -> None:
def scroll_to_see(self, loc_or_ele):
"""滚动页面直到元素可见 \n
:param loc_or_ele: 元素的定位信息可以是loc元组或查询字符串详见ele函数注释
:return: None
@ -469,23 +444,23 @@ class DriverPage(BasePage):
ele = self.ele(loc_or_ele)
ele.run_script("arguments[0].scrollIntoView();")
def refresh(self) -> None:
def refresh(self):
"""刷新当前页面"""
self.driver.refresh()
def stop_loading(self) -> None:
def stop_loading(self):
"""强制停止页面加载"""
self.run_cdp('Page.stopLoading')
def back(self) -> None:
def back(self):
"""在浏览历史中后退一步"""
self.driver.back()
def forward(self) -> None:
def forward(self):
"""在浏览历史中前进一步"""
self.driver.forward()
def set_window_size(self, width: int = None, height: int = None) -> None:
def set_window_size(self, width=None, height=None):
"""设置浏览器窗口大小默认最大化任一参数为0最小化 \n
:param width: 浏览器窗口高
:param height: 浏览器窗口宽
@ -505,14 +480,14 @@ class DriverPage(BasePage):
new_y = height or self.driver.get_window_size()['height']
self.driver.set_window_size(new_x, new_y)
def chrome_downloading(self, download_path: str) -> list:
def chrome_downloading(self, download_path):
"""返回浏览器下载中的文件列表 \n
:param download_path: 下载文件夹路径
:return: 文件列表
"""
return glob(f'{download_path}{sep}*.crdownload')
def process_alert(self, ok: bool = True, send: str = None, timeout: float = None) -> Union[str, None]:
def process_alert(self, ok=True, send=None, timeout=None):
"""处理提示框 \n
:param ok: True表示确认False表示取消其它值不会按按钮但依然返回文本值
:param send: 处理prompt提示框时可输入文本
@ -551,10 +526,10 @@ class DriverPage(BasePage):
class ToFrame(object):
"""用于处理焦点跳转到页面框架的类"""
def __init__(self, page: DriverPage):
def __init__(self, page):
self.page = page
def __call__(self, condition: Union[int, str, tuple, WebElement, DriverElement] = 'main'):
def __call__(self, condition='main'):
"""跳转到(i)frame可传入id、name、序号、元素对象、定位符 \n
:param condition: (i)frame可传入idname序号元素对象定位符
:return: 当前页面对象
@ -570,12 +545,12 @@ class ToFrame(object):
return self.page
def main(self) -> DriverPage:
def main(self):
"""焦点跳转到最高层级框架"""
self.page.driver.switch_to.default_content()
return self.page
def parent(self, level: int = 1) -> DriverPage:
def parent(self, level=1):
"""焦点跳转到上级框架,可指定上级层数 \n
:param level: 上面第几层框架
:return: 框架所在页面对象
@ -586,7 +561,7 @@ class ToFrame(object):
self.page.driver.switch_to.parent_frame()
return self.page
def by_id(self, id_: str) -> DriverPage:
def by_id(self, id_):
"""焦点跳转到id为该值的(i)frame \n
:param id_: (i)frame的id属性值
:return: 框架所在页面对象
@ -594,7 +569,7 @@ class ToFrame(object):
self.page.driver.switch_to.frame(id_)
return self.page
def by_name(self, name: str) -> DriverPage:
def by_name(self, name):
"""焦点跳转到name为该值的(i)frame \n
:param name: (i)frame的name属性值
:return: 框架所在页面对象
@ -602,7 +577,7 @@ class ToFrame(object):
self.page.driver.switch_to.frame(name)
return self.page
def by_index(self, index: int) -> DriverPage:
def by_index(self, index):
"""焦点跳转到页面中第几个(i)frame \n
:param index: 页面中第几个(i)frame
:return: 框架所在页面对象
@ -610,7 +585,7 @@ class ToFrame(object):
self.page.driver.switch_to.frame(index)
return self.page
def by_loc(self, loc: Union[str, tuple]) -> DriverPage:
def by_loc(self, loc):
"""焦点跳转到根据定位符获取到的(i)frame \n
:param loc: 定位符支持selenium原生和DriverPage定位符
:return: 框架所在页面对象
@ -618,7 +593,7 @@ class ToFrame(object):
self.page.driver.switch_to.frame(self.page(loc).inner_ele)
return self.page
def by_ele(self, ele: Union[DriverElement, WebElement]) -> DriverPage:
def by_ele(self, ele):
"""焦点跳转到传入的(i)frame元素对象 \n
:param ele: (i)frame元素对象
:return: 框架所在页面对象
@ -629,7 +604,7 @@ class ToFrame(object):
return self.page
def _get_handles(handles: list, num_or_handles: Union[int, str, list, tuple]) -> set:
def get_handles(handles, num_or_handles):
"""返回指定标签页组成的set
:param handles: handles列表
:param num_or_handles: 指定的标签页可以是多个

View File

@ -1,20 +1,15 @@
# -*- coding:utf-8 -*-
from glob import glob
from os import sep
from pathlib import Path
from time import sleep, perf_counter
from typing import Union, List, Any, Tuple
from selenium.common.exceptions import NoAlertPresentException
from selenium.webdriver.chrome.webdriver import WebDriver
from selenium.webdriver.remote.webdriver import WebDriver as RemoteWebDriver
from selenium.webdriver.remote.webelement import WebElement
from selenium.webdriver.support.wait import WebDriverWait
from .base import BasePage
from .common import get_usable_path
from .driver_element import DriverElement, make_driver_ele, Scroll, ElementWaiter
from .session_element import make_session_ele, SessionElement
from .driver_element import DriverElement, Scroll, ElementWaiter
from .mix_page import MixPage
from .session_element import SessionElement
class DriverPage(BasePage):
@ -171,7 +166,7 @@ class ToFrame(object):
def __init__(self, page: DriverPage):
self.page: DriverPage = ...
def __call__(self, condition: Union[int, str, tuple, WebElement, DriverElement] = ...): ...
def __call__(self, condition: Union[int, str, tuple, WebElement, DriverElement] = ...)->Union[DriverPage, MixPage]: ...
def main(self) -> DriverPage: ...
@ -188,4 +183,4 @@ class ToFrame(object):
def by_ele(self, ele: Union[DriverElement, WebElement]) -> DriverPage: ...
def _get_handles(handles: list, num_or_handles: Union[int, str, list, tuple]) -> set: ...
def get_handles(handles: list, num_or_handles: Union[int, str, list, tuple]) -> set: ...

View File

@ -4,21 +4,9 @@
@Contact : g1879@qq.com
@File : mix_page.py
"""
from typing import Union, List, Tuple
from DownloadKit import DownloadKit
from requests import Response, Session
from requests.cookies import RequestsCookieJar
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.chrome.webdriver import WebDriver
from selenium.webdriver.remote.webelement import WebElement
from .base import BasePage
from .config import DriverOptions, SessionOptions
from .drission import Drission
from .driver_element import DriverElement
from .driver_page import DriverPage
from .session_element import SessionElement
from .session_page import SessionPage
@ -30,12 +18,7 @@ class MixPage(SessionPage, DriverPage, BasePage):
调用某种模式独有的功能会自动切换到该模式
"""
def __init__(self,
mode: str = 'd',
drission: Union[Drission, str] = None,
timeout: float = None,
driver_options: Union[Options, DriverOptions, bool] = None,
session_options: Union[dict, SessionOptions, bool] = None) -> None:
def __init__(self, mode='d', drission=None, timeout=None, driver_options=None, session_options=None):
"""初始化函数 \n
:param mode: 'd' 's'即driver模式和session模式
:param drission: Drission对象不传入时会自动创建有传入时driver_options和session_options参数无效
@ -63,9 +46,7 @@ class MixPage(SessionPage, DriverPage, BasePage):
except Exception:
self.timeout = timeout if timeout is not None else 10
def __call__(self,
loc_or_str: Union[Tuple[str, str], str, DriverElement, SessionElement, WebElement],
timeout: float = None) -> Union[DriverElement, SessionElement, str, None]:
def __call__(self, loc_or_str, timeout=None):
"""在内部查找元素 \n
ele = page('@id=ele_id') \n
:param loc_or_str: 元素的定位信息可以是loc元组或查询字符串
@ -79,7 +60,7 @@ class MixPage(SessionPage, DriverPage, BasePage):
# -----------------共有属性和方法-------------------
@property
def url(self) -> Union[str, None]:
def url(self):
"""返回当前url"""
if self._mode == 'd':
return self._drission.driver.current_url if self._driver else None
@ -87,7 +68,7 @@ class MixPage(SessionPage, DriverPage, BasePage):
return self._session_url
@property
def title(self) -> str:
def title(self):
"""返回网页title"""
if self._mode == 's':
return super().title
@ -95,7 +76,7 @@ class MixPage(SessionPage, DriverPage, BasePage):
return super(SessionPage, self).title
@property
def html(self) -> str:
def html(self):
"""返回页面html文本"""
if self._mode == 's':
return super().html
@ -103,19 +84,14 @@ class MixPage(SessionPage, DriverPage, BasePage):
return super(SessionPage, self).html
@property
def json(self) -> dict:
def json(self):
"""当返回内容是json格式时返回对应的字典"""
if self._mode == 's':
return super().json
elif self._mode == 'd':
return super(SessionPage, self).json
def get(self,
url: str,
show_errmsg: bool = False,
retry: int = None,
interval: float = None,
**kwargs) -> Union[bool, None]:
def get(self, url, show_errmsg=False, retry=None, interval=None, **kwargs):
"""跳转到一个url \n
:param url: 目标url
:param show_errmsg: 是否显示和抛出异常
@ -129,9 +105,7 @@ class MixPage(SessionPage, DriverPage, BasePage):
elif self._mode == 's':
return super().get(url, show_errmsg, retry, interval, **kwargs)
def ele(self,
loc_or_ele: Union[Tuple[str, str], str, DriverElement, SessionElement, WebElement],
timeout: float = None) -> Union[DriverElement, SessionElement, str, None]:
def ele(self, loc_or_ele, timeout=None):
"""返回第一个符合条件的元素、属性或节点文本 \n
:param loc_or_ele: 元素的定位信息可以是元素对象loc元组或查询字符串
:param timeout: 查找元素超时时间默认与页面等待时间一致
@ -142,9 +116,7 @@ class MixPage(SessionPage, DriverPage, BasePage):
elif self._mode == 'd':
return super(SessionPage, self).ele(loc_or_ele, timeout=timeout)
def eles(self,
loc_or_str: Union[Tuple[str, str], str],
timeout: float = None) -> List[Union[DriverElement, SessionElement, str]]:
def eles(self, loc_or_str, timeout=None):
"""返回页面中所有符合条件的元素、属性或节点文本 \n
:param loc_or_str: 元素的定位信息可以是loc元组或查询字符串
:param timeout: 查找元素超时时间默认与页面等待时间一致
@ -155,8 +127,7 @@ class MixPage(SessionPage, DriverPage, BasePage):
elif self._mode == 'd':
return super(SessionPage, self).eles(loc_or_str, timeout=timeout)
def s_ele(self, loc_or_ele: Union[Tuple[str, str], str, DriverElement, SessionElement] = None) \
-> Union[SessionElement, str, None]:
def s_ele(self, loc_or_ele=None):
"""查找第一个符合条件的元素以SessionElement形式返回d模式处理复杂页面时效率很高 \n
:param loc_or_ele: 元素的定位信息可以是loc元组或查询字符串
:return: SessionElement对象或属性文本
@ -166,7 +137,7 @@ class MixPage(SessionPage, DriverPage, BasePage):
elif self._mode == 'd':
return super(SessionPage, self).s_ele(loc_or_ele)
def s_eles(self, loc_or_str: Union[Tuple[str, str], str] = None) -> List[Union[SessionElement, str]]:
def s_eles(self, loc_or_str=None):
"""查找所有符合条件的元素以SessionElement形式返回d模式处理复杂页面时效率很高 \n
:param loc_or_str: 元素的定位信息可以是loc元组或查询字符串
:return: SessionElement对象或属性文本组成的列表
@ -176,11 +147,7 @@ class MixPage(SessionPage, DriverPage, BasePage):
elif self._mode == 'd':
return super(SessionPage, self).s_eles(loc_or_str)
def _ele(self,
loc_or_ele: Union[Tuple[str, str], str, DriverElement, SessionElement, WebElement],
timeout: float = None, single: bool = True) \
-> Union[DriverElement, SessionElement, str, None, List[Union[SessionElement, str]], List[
Union[DriverElement, str]]]:
def _ele(self, loc_or_ele, timeout=None, single=True):
"""返回页面中符合条件的元素、属性或节点文本,默认返回第一个 \n
:param loc_or_ele: 元素的定位信息可以是元素对象loc元组或查询字符串
:param timeout: 查找元素超时时间d模式专用
@ -192,7 +159,7 @@ class MixPage(SessionPage, DriverPage, BasePage):
elif self._mode == 'd':
return super(SessionPage, self)._ele(loc_or_ele, timeout=timeout, single=single)
def get_cookies(self, as_dict: bool = False, all_domains: bool = False) -> Union[dict, list]:
def get_cookies(self, as_dict=False, all_domains=False):
"""返回cookies \n
:param as_dict: 是否以字典方式返回
:param all_domains: 是否返回所有域的cookies
@ -205,12 +172,12 @@ class MixPage(SessionPage, DriverPage, BasePage):
# ----------------MixPage独有属性和方法-----------------------
@property
def drission(self) -> Drission:
def drission(self):
"""返回当前使用的 Dirssion 对象"""
return self._drission
@property
def driver(self) -> WebDriver:
def driver(self):
"""返回 driver 对象,如没有则创建 \n
每次访问时切换到 d 模式用于独有函数及外部调用
:return: WebDriver对象
@ -219,27 +186,27 @@ class MixPage(SessionPage, DriverPage, BasePage):
return self._drission.driver
@property
def session(self) -> Session:
def session(self):
"""返回 Session 对象,如没有则创建"""
return self._drission.session
@property
def response(self) -> Response:
def response(self):
"""返回 s 模式获取到的 Response 对象,切换到 s 模式"""
self.change_mode('s')
return self._response
@property
def mode(self) -> str:
def mode(self):
"""返回当前模式,'s''d' """
return self._mode
@property
def _session_url(self) -> str:
def _session_url(self):
"""返回 session 保存的url"""
return self._response.url if self._response else None
def change_mode(self, mode: str = None, go: bool = True, copy_cookies: bool = True) -> None:
def change_mode(self, mode=None, go=True, copy_cookies=True):
"""切换模式,接收's''d',除此以外的字符串会切换为 d 模式 \n
切换时会把当前模式的cookies复制到目标模式 \n
切换后如果go是True调用相应的get函数使访问的页面同步 \n
@ -277,7 +244,7 @@ class MixPage(SessionPage, DriverPage, BasePage):
if go and self._drission.driver.current_url.startswith('http'):
self.get(self._drission.driver.current_url)
def set_cookies(self, cookies: Union[RequestsCookieJar, list, tuple, str, dict], refresh: bool = True) -> None:
def set_cookies(self, cookies, refresh=True):
"""设置cookies \n
:param cookies: cookies信息可为CookieJar, list, tuple, str, dict
:param refresh: 设置cookies后是否刷新页面
@ -290,13 +257,13 @@ class MixPage(SessionPage, DriverPage, BasePage):
if refresh:
self.refresh()
def cookies_to_session(self, copy_user_agent: bool = False) -> None:
def cookies_to_session(self, copy_user_agent=False):
"""从driver复制cookies到session \n
:param copy_user_agent : 是否复制user agent信息
"""
self._drission.cookies_to_session(copy_user_agent)
def cookies_to_driver(self, url: str = None) -> None:
def cookies_to_driver(self, url=None):
"""从session复制cookies到driver \n
chrome需要指定域才能接收cookies \n
:param url: 目标域
@ -305,7 +272,7 @@ class MixPage(SessionPage, DriverPage, BasePage):
url = url or self._session_url
self._drission.cookies_to_driver(url)
def check_page(self, by_requests: bool = False) -> Union[bool, None]:
def check_page(self, by_requests=False):
"""d模式时检查网页是否符合预期 \n
默认由response状态检查可重载实现针对性检查 \n
:param by_requests: 是否用内置response检查
@ -320,25 +287,19 @@ class MixPage(SessionPage, DriverPage, BasePage):
r = self._make_response(self.url, retry=0)[0]
return r.ok if r else False
def close_driver(self) -> None:
def close_driver(self):
"""关闭driver及浏览器"""
self._driver = None
self.drission.close_driver(True)
def close_session(self) -> None:
def close_session(self):
"""关闭session"""
self._session = None
self._response = None
self.drission.close_session()
# ----------------重写SessionPage的函数-----------------------
def post(self,
url: str,
data: Union[dict, str] = None,
show_errmsg: bool = False,
retry: int = None,
interval: float = None,
**kwargs) -> bool:
def post(self, url, data=None, show_errmsg=False, retry=None, interval=None, **kwargs):
"""用post方式跳转到url会切换到s模式 \n
:param url: 目标url
:param data: post方式时提交的数据
@ -352,13 +313,13 @@ class MixPage(SessionPage, DriverPage, BasePage):
return super().post(url, data, show_errmsg, retry, interval, **kwargs)
@property
def download(self) -> DownloadKit:
def download(self):
"""返回下载器对象"""
if self.mode == 'd':
self.cookies_to_session()
return super().download
def chrome_downloading(self, path: str = None) -> list:
def chrome_downloading(self, path=None):
"""返回浏览器下载中的文件列表 \n
:param path: 下载文件夹路径默认读取配置信息
:return: 正在下载的文件列表
@ -373,10 +334,10 @@ class MixPage(SessionPage, DriverPage, BasePage):
return super().chrome_downloading(path)
# ----------------MixPage独有函数-----------------------
def hide_browser(self) -> None:
def hide_browser(self):
"""隐藏浏览器窗口"""
self.drission.hide_browser()
def show_browser(self) -> None:
def show_browser(self):
"""显示浏览器窗口"""
self.drission.show_browser()

View File

@ -1,5 +1,5 @@
# -*- coding:utf-8 -*-
from typing import Union, List, Tuple
from typing import Union, List, Tuple, Any
from DownloadKit import DownloadKit
from requests import Response, Session
@ -52,11 +52,24 @@ class MixPage(SessionPage, DriverPage, BasePage):
def json(self) -> dict: ...
def get(self,
url: str,
show_errmsg: bool = ...,
retry: int = ...,
interval: float = ...,
**kwargs) -> Union[bool, None]: ...
url: str,
show_errmsg: bool | None = ...,
retry: int | None = ...,
interval: float | None = ...,
timeout: float | None = ...,
params: dict | None = ...,
data: Union[dict, str, None] = ...,
json: Union[dict, str, None] = ...,
headers: dict | None = ...,
cookies: Any | None = ...,
files: Any | None = ...,
auth: Any | None = ...,
allow_redirects: bool = ...,
proxies: dict | None = ...,
hooks: Any | None = ...,
stream: Any | None = ...,
verify: Any | None = ...,
cert: Any | None = ...) -> Union[bool, None]: ...
def ele(self,
loc_or_ele: Union[Tuple[str, str], str, DriverElement, SessionElement, WebElement],
@ -115,11 +128,23 @@ class MixPage(SessionPage, DriverPage, BasePage):
# ----------------重写SessionPage的函数-----------------------
def post(self,
url: str,
data: Union[dict, str] = ...,
show_errmsg: bool = ...,
retry: int = ...,
interval: float = ...,
**kwargs) -> bool: ...
show_errmsg: bool | None = ...,
retry: int | None = ...,
interval: float | None = ...,
timeout: float | None = ...,
params: dict | None = ...,
data: Union[dict, str, None] = ...,
json: Union[dict, str, None] = ...,
headers: dict | None = ...,
cookies: Any | None = ...,
files: Any | None = ...,
auth: Any | None = ...,
allow_redirects: bool = ...,
proxies: dict | None = ...,
hooks: Any | None = ...,
stream: Any | None = ...,
verify: Any | None = ...,
cert: Any | None = ...) -> bool: ...
@property
def download(self) -> DownloadKit: ...

View File

@ -5,11 +5,9 @@
@File : session_element.py
"""
from re import match, DOTALL
from typing import Union, List, Tuple
from lxml.etree import tostring
from lxml.html import HtmlElement, fromstring
# from lxml.etree import Element as HtmlElement, fromstring
from .base import DrissionElement, BasePage, BaseElement
from .common import get_ele_txt, get_loc, make_absolute_link
@ -18,7 +16,7 @@ from .common import get_ele_txt, get_loc, make_absolute_link
class SessionElement(DrissionElement):
"""session模式的元素对象包装了一个lxml的Element对象并封装了常用功能"""
def __init__(self, ele: HtmlElement, page=None):
def __init__(self, ele, page=None):
"""初始化对象 \n
:param ele: 被包装的HtmlElement元素
:param page: 元素所在页面对象如果是从 html 文本生成的元素则为 None
@ -27,16 +25,14 @@ class SessionElement(DrissionElement):
self._inner_ele = ele
@property
def inner_ele(self) -> HtmlElement:
def inner_ele(self):
return self._inner_ele
def __repr__(self) -> str:
def __repr__(self):
attrs = [f"{attr}='{self.attrs[attr]}'" for attr in self.attrs]
return f'<SessionElement {self.tag} {" ".join(attrs)}>'
def __call__(self,
loc_or_str: Union[Tuple[str, str], str],
timeout=None) -> Union['SessionElement', str, None]:
def __call__(self, loc_or_str, timeout=None):
"""在内部查找元素 \n
ele2 = ele1('@id=ele_id') \n
:param loc_or_str: 元素的定位信息可以是loc元组或查询字符串
@ -46,48 +42,45 @@ class SessionElement(DrissionElement):
return self.ele(loc_or_str)
@property
def tag(self) -> str:
def tag(self):
"""返回元素类型"""
return self._inner_ele.tag
@property
def html(self) -> str:
def html(self):
"""返回outerHTML文本"""
html = tostring(self._inner_ele, method="html").decode()
return html[:html.rfind('>') + 1] # tostring()会把跟紧元素的文本节点也带上,因此要去掉
@property
def inner_html(self) -> str:
def inner_html(self):
"""返回元素innerHTML文本"""
r = match(r'<.*?>(.*)</.*?>', self.html, flags=DOTALL)
return '' if not r else r.group(1)
@property
def attrs(self) -> dict:
def attrs(self):
"""返回元素所有属性及值"""
return {attr: self.attr(attr) for attr, val in self.inner_ele.items()}
@property
def text(self) -> str:
def text(self):
"""返回元素内所有文本"""
return get_ele_txt(self)
@property
def raw_text(self) -> str:
def raw_text(self):
"""返回未格式化处理的元素内文本"""
return str(self._inner_ele.text_content())
def parent(self, level_or_loc: Union[tuple, str, int] = 1) -> Union['SessionElement', None]:
def parent(self, level_or_loc=1):
"""返回上面某一级父元素,可指定层数或用查询语法定位 \n
:param level_or_loc: 第几级父元素或定位符
:return: 上级元素对象
"""
return super().parent(level_or_loc)
def prev(self,
index: int = 1,
filter_loc: Union[tuple, str] = '',
timeout: float = 0) -> Union['SessionElement', str, None]:
def prev(self, index=1, filter_loc='', timeout=0):
"""返回前面的一个兄弟元素,可用查询语法筛选,可指定返回筛选结果的第几个 \n
:param index: 前面第几个查询结果元素
:param filter_loc: 用于筛选元素的查询语法
@ -96,10 +89,7 @@ class SessionElement(DrissionElement):
"""
return super().prev(index, filter_loc, timeout)
def next(self,
index: int = 1,
filter_loc: Union[tuple, str] = '',
timeout: float = 0) -> Union['SessionElement', str, None]:
def next(self, index=1, filter_loc='', timeout=0):
"""返回后面的一个兄弟元素,可用查询语法筛选,可指定返回筛选结果的第几个 \n
:param index: 后面第几个查询结果元素
:param filter_loc: 用于筛选元素的查询语法
@ -108,10 +98,7 @@ class SessionElement(DrissionElement):
"""
return super().next(index, filter_loc, timeout)
def before(self,
index: int = 1,
filter_loc: Union[tuple, str] = '',
timeout: float = None) -> Union['SessionElement', str, None]:
def before(self, index=1, filter_loc='', timeout=None):
"""返回前面的一个兄弟元素,可用查询语法筛选,可指定返回筛选结果的第几个 \n
:param index: 前面第几个查询结果元素
:param filter_loc: 用于筛选元素的查询语法
@ -120,10 +107,7 @@ class SessionElement(DrissionElement):
"""
return super().before(index, filter_loc, timeout)
def after(self,
index: int = 1,
filter_loc: Union[tuple, str] = '',
timeout: float = None) -> Union['SessionElement', str, None]:
def after(self, index=1, filter_loc='', timeout=None):
"""返回后面的一个兄弟元素,可用查询语法筛选,可指定返回筛选结果的第几个 \n
:param index: 后面第几个查询结果元素
:param filter_loc: 用于筛选元素的查询语法
@ -132,9 +116,7 @@ class SessionElement(DrissionElement):
"""
return super().after(index, filter_loc, timeout)
def prevs(self,
filter_loc: Union[tuple, str] = '',
timeout: float = 0) -> List[Union['SessionElement', str]]:
def prevs(self, filter_loc='', timeout=0):
"""返回前面全部兄弟元素或节点组成的列表,可用查询语法筛选 \n
:param filter_loc: 用于筛选元素的查询语法
:param timeout: 查找元素的超时时间
@ -142,9 +124,7 @@ class SessionElement(DrissionElement):
"""
return super().prevs(filter_loc, timeout)
def nexts(self,
filter_loc: Union[tuple, str] = '',
timeout: float = 0) -> List[Union['SessionElement', str]]:
def nexts(self, filter_loc='', timeout=0):
"""返回后面全部兄弟元素或节点组成的列表,可用查询语法筛选 \n
:param filter_loc: 用于筛选元素的查询语法
:param timeout: 查找元素的超时时间
@ -152,9 +132,7 @@ class SessionElement(DrissionElement):
"""
return super().nexts(filter_loc, timeout)
def befores(self,
filter_loc: Union[tuple, str] = '',
timeout: float = None) -> List[Union['SessionElement', str]]:
def befores(self, filter_loc='', timeout=None):
"""返回后面全部兄弟元素或节点组成的列表,可用查询语法筛选 \n
:param filter_loc: 用于筛选元素的查询语法
:param timeout: 查找元素的超时时间
@ -162,9 +140,7 @@ class SessionElement(DrissionElement):
"""
return super().befores(filter_loc, timeout)
def afters(self,
filter_loc: Union[tuple, str] = '',
timeout: float = None) -> List[Union['SessionElement', str]]:
def afters(self, filter_loc='', timeout=None):
"""返回前面全部兄弟元素或节点组成的列表,可用查询语法筛选 \n
:param filter_loc: 用于筛选元素的查询语法
:param timeout: 查找元素的超时时间
@ -172,7 +148,7 @@ class SessionElement(DrissionElement):
"""
return super().afters(filter_loc, timeout)
def attr(self, attr: str) -> Union[str, None]:
def attr(self, attr):
"""返回attribute属性值 \n
:param attr: 属性名
:return: 属性值文本没有该属性返回None
@ -205,9 +181,7 @@ class SessionElement(DrissionElement):
else:
return self.inner_ele.get(attr)
def ele(self,
loc_or_str: Union[Tuple[str, str], str],
timeout=None) -> Union['SessionElement', str, None]:
def ele(self, loc_or_str, timeout=None):
"""返回当前元素下级符合条件的第一个元素、属性或节点文本 \n
:param loc_or_str: 元素的定位信息可以是loc元组或查询字符串
:param timeout: 不起实际作用用于和DriverElement对应便于无差别调用
@ -215,9 +189,7 @@ class SessionElement(DrissionElement):
"""
return self._ele(loc_or_str)
def eles(self,
loc_or_str: Union[Tuple[str, str], str],
timeout=None) -> List[Union['SessionElement', str]]:
def eles(self, loc_or_str, timeout=None):
"""返回当前元素下级所有符合条件的子元素、属性或节点文本 \n
:param loc_or_str: 元素的定位信息可以是loc元组或查询字符串
:param timeout: 不起实际作用用于和DriverElement对应便于无差别调用
@ -225,27 +197,21 @@ class SessionElement(DrissionElement):
"""
return self._ele(loc_or_str, single=False)
def s_ele(self,
loc_or_str: Union[Tuple[str, str], str] = None) -> Union['SessionElement', str, None]:
def s_ele(self, loc_or_str=None):
"""返回当前元素下级符合条件的第一个元素、属性或节点文本 \n
:param loc_or_str: 元素的定位信息可以是loc元组或查询字符串
:return: SessionElement对象或属性文本
"""
return self._ele(loc_or_str)
def s_eles(self,
loc_or_str: Union[Tuple[str, str], str] = None) -> List[Union['SessionElement', str]]:
def s_eles(self, loc_or_str=None):
"""返回当前元素下级所有符合条件的子元素、属性或节点文本 \n
:param loc_or_str: 元素的定位信息可以是loc元组或查询字符串
:return: SessionElement对象或属性文本组成的列表
"""
return self._ele(loc_or_str, single=False)
def _ele(self,
loc_or_str: Union[Tuple[str, str], str],
timeout=None,
single: bool = True,
relative: bool = False) -> Union['SessionElement', str, None, List[Union['SessionElement', str]]]:
def _ele(self, loc_or_str, timeout=None, single=True, relative=False):
"""返回当前元素下级符合条件的子元素、属性或节点文本,默认返回第一个 \n
:param loc_or_str: 元素的定位信息可以是loc元组或查询字符串
:param timeout: 不起实际作用用于和父类对应
@ -255,7 +221,7 @@ class SessionElement(DrissionElement):
"""
return make_session_ele(self, loc_or_str, single)
def _get_ele_path(self, mode) -> str:
def _get_ele_path(self, mode):
"""获取css路径或xpath路径
:param mode: 'css' 'xpath'
:return: css路径或xpath路径
@ -276,9 +242,7 @@ class SessionElement(DrissionElement):
return f':root{path_str[1:]}' if mode == 'css' else path_str
def make_session_ele(html_or_ele: Union[str, BaseElement, BasePage],
loc: Union[str, Tuple[str, str]] = None,
single: bool = True) -> Union[SessionElement, str, None, List[Union[SessionElement, str]]]:
def make_session_ele(html_or_ele, loc=None, single=True):
"""从接收到的对象或html文本中查找元素返回SessionElement对象 \n
如要直接从html生成SessionElement而不在下级查找loc输入None即可 \n
:param html_or_ele: html文本BaseParser对象

View File

@ -10,7 +10,7 @@ from .session_page import SessionPage
class SessionElement(DrissionElement):
"""session模式的元素对象包装了一个lxml的Element对象并封装了常用功能"""
def __init__(self, ele: HtmlElement, page=...):
def __init__(self, ele: HtmlElement, page: Union[SessionPage, None] = ...):
self._inner_ele: HtmlElement = ...
self.page: SessionPage = ...
@ -21,7 +21,7 @@ class SessionElement(DrissionElement):
def __call__(self,
loc_or_str: Union[Tuple[str, str], str],
timeout=...) -> Union['SessionElement', str, None]: ...
timeout: float = ...) -> Union['SessionElement', str, None]: ...
@property
def tag(self) -> str: ...

View File

@ -1,37 +1,35 @@
# -*- coding:utf-8 -*-
from re import search
from time import sleep
from typing import Union, List, Tuple
from urllib.parse import urlparse
from DownloadKit import DownloadKit
from requests import Session, Response
from requests.structures import CaseInsensitiveDict
from tldextract import extract
from DownloadKit import DownloadKit
from .base import BasePage
from .config import _cookie_to_dict, SessionOptions, _cookies_to_tuple
from .config import SessionOptions, cookies_to_tuple, cookie_to_dict
from .session_element import SessionElement, make_session_ele
class SessionPage(BasePage):
"""SessionPage封装了页面操作的常用功能使用requests来获取、解析网页"""
def __init__(self, session_or_options: Union[Session, SessionOptions] = None,
timeout: float = 10):
def __init__(self, session_or_options=None, timeout=10):
"""初始化函数"""
super().__init__(timeout)
self._response = None
self._create_session(session_or_options)
def _create_session(self, Session_or_Options) -> None:
def _create_session(self, Session_or_Options):
if Session_or_Options is None or isinstance(Session_or_Options, SessionOptions):
options = Session_or_Options or SessionOptions()
self._set_session(options.as_dict())
elif isinstance(Session_or_Options, Session):
self._session = Session_or_Options
def _set_session(self, data) -> None:
def _set_session(self, data):
"""根据传入字典对session进行设置 \n
:param data: session配置字典
:return: None
@ -50,7 +48,7 @@ class SessionPage(BasePage):
self._session.__setattr__(i, data[i])
def set_cookies(self, cookies):
cookies = _cookies_to_tuple(cookies)
cookies = cookies_to_tuple(cookies)
for cookie in cookies:
if cookie['value'] is None:
cookie['value'] = ''
@ -64,9 +62,7 @@ class SessionPage(BasePage):
self.session.cookies.set(cookie['name'], cookie['value'], **kwargs)
def __call__(self,
loc_or_str: Union[Tuple[str, str], str, SessionElement],
timeout=None) -> Union[SessionElement, str, None]:
def __call__(self, loc_or_str, timeout=None):
"""在内部查找元素 \n
ele2 = ele1('@id=ele_id') \n
:param loc_or_str: 元素的定位信息可以是loc元组或查询字符串
@ -77,17 +73,17 @@ class SessionPage(BasePage):
# -----------------共有属性和方法-------------------
@property
def url(self) -> str:
def url(self):
"""返回当前访问url"""
return self._url
@property
def html(self) -> str:
def html(self):
"""返回页面的html文本"""
return self.response.text if self.response else ''
@property
def json(self) -> dict:
def json(self):
"""当返回内容是json格式时返回对应的字典"""
return self.response.json()
@ -103,9 +99,7 @@ class SessionPage(BasePage):
"""
return self._s_connect(url, 'get', None, show_errmsg, retry, interval, **kwargs)
def ele(self,
loc_or_ele: Union[Tuple[str, str], str, SessionElement],
timeout: float = None) -> Union[SessionElement, str, None]:
def ele(self, loc_or_ele, timeout=None):
"""返回页面中符合条件的第一个元素、属性或节点文本 \n
:param loc_or_ele: 元素的定位信息可以是元素对象loc元组或查询字符串
:param timeout: 不起实际作用用于和DriverElement对应便于无差别调用
@ -113,9 +107,7 @@ class SessionPage(BasePage):
"""
return self._ele(loc_or_ele)
def eles(self,
loc_or_str: Union[Tuple[str, str], str],
timeout: float = None) -> List[Union[SessionElement, str]]:
def eles(self, loc_or_str, timeout=None):
"""返回页面中所有符合条件的元素、属性或节点文本 \n
:param loc_or_str: 元素的定位信息可以是loc元组或查询字符串
:param timeout: 不起实际作用用于和DriverElement对应便于无差别调用
@ -123,24 +115,21 @@ class SessionPage(BasePage):
"""
return self._ele(loc_or_str, single=False)
def s_ele(self, loc_or_ele: Union[Tuple[str, str], str, SessionElement] = None) -> Union[SessionElement, str, None]:
def s_ele(self, loc_or_ele=None):
"""返回页面中符合条件的第一个元素、属性或节点文本 \n
:param loc_or_ele: 元素的定位信息可以是元素对象loc元组或查询字符串
:return: SessionElement对象或属性文本
"""
return make_session_ele(self.html) if loc_or_ele is None else self._ele(loc_or_ele)
def s_eles(self, loc_or_str: Union[Tuple[str, str], str] = None) -> List[Union[SessionElement, str]]:
def s_eles(self, loc_or_str=None):
"""返回页面中符合条件的所有元素、属性或节点文本 \n
:param loc_or_str: 元素的定位信息可以是元素对象loc元组或查询字符串
:return: SessionElement对象或属性文本
"""
return self._ele(loc_or_str, single=False)
def _ele(self,
loc_or_ele: Union[Tuple[str, str], str, SessionElement],
timeout: float = None,
single: bool = True) -> Union[SessionElement, str, None, List[Union[SessionElement, str]]]:
def _ele(self, loc_or_ele, timeout=None, single=True):
"""返回页面中符合条件的元素、属性或节点文本,默认返回第一个 \n
:param loc_or_ele: 元素的定位信息可以是元素对象loc元组或查询字符串
:param timeout: 不起实际作用用于和父类对应
@ -149,7 +138,7 @@ class SessionPage(BasePage):
"""
return loc_or_ele if isinstance(loc_or_ele, SessionElement) else make_session_ele(self, loc_or_ele, single)
def get_cookies(self, as_dict: bool = False, all_domains: bool = False) -> Union[dict, list]:
def get_cookies(self, as_dict=False, all_domains=False):
"""返回cookies \n
:param as_dict: 是否以字典方式返回
:param all_domains: 是否返回所有域的cookies
@ -168,34 +157,28 @@ class SessionPage(BasePage):
if as_dict:
return {x.name: x.value for x in cookies}
else:
return [_cookie_to_dict(cookie) for cookie in cookies]
return [cookie_to_dict(cookie) for cookie in cookies]
# ----------------session独有属性和方法-----------------------
@property
def session(self) -> Session:
def session(self):
"""返回session对象"""
return self._session
@property
def response(self) -> Response:
def response(self):
"""返回访问url得到的response对象"""
return self._response
@property
def download(self) -> DownloadKit:
def download(self):
"""返回下载器对象"""
if not hasattr(self, '_download_kit'):
self._download_kit = DownloadKit(session=self)
return self._download_kit
def post(self,
url: str,
data: Union[dict, str] = None,
show_errmsg: bool = False,
retry: int = None,
interval: float = None,
**kwargs) -> bool:
def post(self, url, data=None, show_errmsg=False, retry=None, interval=None, **kwargs):
"""用post方式跳转到url \n
:param url: 目标url
:param data: 提交的数据
@ -207,14 +190,7 @@ class SessionPage(BasePage):
"""
return self._s_connect(url, 'post', data, show_errmsg, retry, interval, **kwargs)
def _s_connect(self,
url: str,
mode: str,
data: Union[dict, str] = None,
show_errmsg: bool = False,
retry: int = None,
interval: float = None,
**kwargs) -> bool:
def _s_connect(self, url, mode, data=None, show_errmsg=False, retry=None, interval=None, **kwargs):
"""执行get或post连接 \n
:param url: 目标url
:param mode: 'get' 'post'
@ -242,14 +218,7 @@ class SessionPage(BasePage):
return self._url_available
def _make_response(self,
url: str,
mode: str = 'get',
data: Union[dict, str] = None,
retry: int = None,
interval: float = None,
show_errmsg: bool = False,
**kwargs) -> tuple:
def _make_response(self, url, mode='get', data=None, retry=None, interval=None, show_errmsg=False, **kwargs):
"""生成Response对象 \n
:param url: 目标url
:param mode: 'get' 'post'
@ -268,12 +237,12 @@ class SessionPage(BasePage):
parsed_url = urlparse(url)
hostname = parsed_url.hostname
scheme = parsed_url.scheme
if not _check_headers(kwargs, self.session.headers, 'Referer'):
if not check_headers(kwargs, self.session.headers, 'Referer'):
kwargs['headers']['Referer'] = self.url if self.url else f'{scheme}://{hostname}'
if 'Host' not in kwargs['headers']:
kwargs['headers']['Host'] = hostname
if not _check_headers(kwargs, self.session.headers, 'timeout'):
if not check_headers(kwargs, self.session.headers, 'timeout'):
kwargs['timeout'] = self.timeout
if 'allow_redirects' not in kwargs:
@ -290,7 +259,7 @@ class SessionPage(BasePage):
r = self.session.post(url, data=data, **kwargs)
if r:
return _set_charset(r), 'Success'
return set_charset(r), 'Success'
except Exception as e:
err = e
@ -317,12 +286,12 @@ class SessionPage(BasePage):
return r, f'状态码:{r.status_code}'
def _check_headers(kwargs, headers: Union[dict, CaseInsensitiveDict], arg: str) -> bool:
def check_headers(kwargs, headers, arg) -> bool:
"""检查kwargs或headers中是否有arg所示属性"""
return arg in kwargs['headers'] or arg in headers
def _set_charset(response) -> Response:
def set_charset(response) -> Response:
"""设置Response对象的编码"""
# 在headers中获取编码
content_type = response.headers.get('content-type', '').lower()

View File

@ -3,6 +3,7 @@ from typing import Any, Union, Tuple, List
from DownloadKit import DownloadKit
from requests import Session, Response
from requests.cookies import RequestsCookieJar
from requests.structures import CaseInsensitiveDict
from .base import BasePage
from .session_element import SessionElement
@ -22,8 +23,7 @@ class SessionPage(BasePage):
self.retry_times: int = ...
self.retry_interval: float = ...
def _create_session(self,
Session_or_Options: Union[Session, SessionOptions]) -> None: ...
def _create_session(self, Session_or_Options: Union[Session, SessionOptions]) -> None: ...
def _set_session(self, data: dict) -> None: ...
@ -31,7 +31,7 @@ class SessionPage(BasePage):
def __call__(self,
loc_or_str: Union[Tuple[str, str], str, SessionElement],
timeout=...) -> Union[SessionElement, str, None]: ...
timeout: float = ...) -> Union[SessionElement, str, None]: ...
# -----------------共有属性和方法-------------------
@ -114,7 +114,7 @@ class SessionPage(BasePage):
hooks: Any | None = ...,
stream: Any | None = ...,
verify: Any | None = ...,
cert: Any | None = ..., ) -> bool: ...
cert: Any | None = ...) -> bool: ...
def _s_connect(self,
url: str,
@ -133,3 +133,10 @@ class SessionPage(BasePage):
interval: float = ...,
show_errmsg: bool = ...,
**kwargs) -> tuple: ...
def check_headers(kwargs: Union[dict, CaseInsensitiveDict], headers: Union[dict, CaseInsensitiveDict],
arg: str) -> bool: ...
def set_charset(response: Response) -> Response: ...

View File

@ -5,34 +5,32 @@
@File : shadow_root_element.py
"""
from time import perf_counter
from typing import Union, Any, Tuple, List
from typing import Union
from selenium.webdriver.remote.webelement import WebElement
from .base import BaseElement
from .common import get_loc
from .driver_element import make_driver_ele, DriverElement
from .driver_element import make_driver_ele
from .session_element import make_session_ele, SessionElement
class ShadowRootElement(BaseElement):
"""ShadowRootElement是用于处理ShadowRoot的类使用方法和DriverElement基本一致"""
def __init__(self, inner_ele: WebElement, parent_ele: DriverElement):
def __init__(self, inner_ele, parent_ele):
super().__init__(parent_ele.page)
self.parent_ele = parent_ele
self._inner_ele = inner_ele
@property
def inner_ele(self) -> WebElement:
def inner_ele(self):
return self._inner_ele
def __repr__(self) -> str:
def __repr__(self):
return f'<ShadowRootElement in {self.parent_ele} >'
def __call__(self,
loc_or_str: Union[Tuple[str, str], str],
timeout: float = None) -> Union[DriverElement, str, None]:
def __call__(self, loc_or_str, timeout=None):
"""在内部查找元素 \n
ele2 = ele1('@id=ele_id') \n
:param loc_or_str: 元素的定位信息可以是loc元组或查询字符串
@ -42,21 +40,21 @@ class ShadowRootElement(BaseElement):
return self.ele(loc_or_str, timeout)
@property
def tag(self) -> str:
def tag(self):
"""元素标签名"""
return 'shadow-root'
@property
def html(self) -> str:
def html(self):
return f'<shadow_root>{self.inner_html}</shadow_root>'
@property
def inner_html(self) -> str:
def inner_html(self):
"""返回内部的html文本"""
shadow_root = WebElement(self.page.driver, self.inner_ele._id)
return shadow_root.get_attribute('innerHTML')
def parent(self, level_or_loc: Union[str, int] = 1) -> DriverElement:
def parent(self, level_or_loc=1):
"""返回上面某一级父元素,可指定层数或用查询语法定位 \n
:param level_or_loc: 第几级父元素或定位符
:return: DriverElement对象
@ -77,9 +75,7 @@ class ShadowRootElement(BaseElement):
return self.parent_ele.ele(loc, timeout=0)
def next(self,
index: int = 1,
filter_loc: Union[tuple, str] = '') -> Union[DriverElement, str, None]:
def next(self, index=1, filter_loc=''):
"""返回后面的一个兄弟元素,可用查询语法筛选,可指定返回筛选结果的第几个 \n
:param index: 第几个查询结果元素
:param filter_loc: 用于筛选元素的查询语法
@ -88,9 +84,7 @@ class ShadowRootElement(BaseElement):
nodes = self.nexts(filter_loc=filter_loc)
return nodes[index - 1] if nodes else None
def before(self,
index: int = 1,
filter_loc: Union[tuple, str] = '') -> Union[DriverElement, str, None]:
def before(self, index=1, filter_loc=''):
"""返回前面的一个兄弟元素,可用查询语法筛选,可指定返回筛选结果的第几个 \n
:param index: 前面第几个查询结果元素
:param filter_loc: 用于筛选元素的查询语法
@ -99,8 +93,7 @@ class ShadowRootElement(BaseElement):
nodes = self.befores(filter_loc=filter_loc)
return nodes[index - 1] if nodes else None
def after(self, index: int = 1,
filter_loc: Union[tuple, str] = '') -> Union[DriverElement, str, None]:
def after(self, index=1, filter_loc=''):
"""返回后面的一个兄弟元素,可用查询语法筛选,可指定返回筛选结果的第几个 \n
:param index: 后面第几个查询结果元素
:param filter_loc: 用于筛选元素的查询语法
@ -109,7 +102,7 @@ class ShadowRootElement(BaseElement):
nodes = self.afters(filter_loc=filter_loc)
return nodes[index - 1] if nodes else None
def nexts(self, filter_loc: Union[tuple, str] = '') -> List[Union[DriverElement, str]]:
def nexts(self, filter_loc=''):
"""返回后面所有兄弟元素或节点组成的列表 \n
:param filter_loc: 用于筛选元素的查询语法
:return: DriverElement对象组成的列表
@ -122,7 +115,7 @@ class ShadowRootElement(BaseElement):
xpath = f'xpath:./{loc}'
return self.parent_ele.eles(xpath, timeout=0.1)
def befores(self, filter_loc: Union[tuple, str] = '') -> List[Union[DriverElement, str]]:
def befores(self, filter_loc=''):
"""返回后面全部兄弟元素或节点组成的列表,可用查询语法筛选 \n
:param filter_loc: 用于筛选元素的查询语法
:return: 本元素前面的元素或节点组成的列表
@ -135,7 +128,7 @@ class ShadowRootElement(BaseElement):
xpath = f'xpath:./preceding::{loc}'
return self.parent_ele.eles(xpath, timeout=0.1)
def afters(self, filter_loc: Union[tuple, str] = '') -> List[Union[DriverElement, str]]:
def afters(self, filter_loc=''):
"""返回前面全部兄弟元素或节点组成的列表,可用查询语法筛选 \n
:param filter_loc: 用于筛选元素的查询语法
:return: 本元素后面的元素或节点组成的列表
@ -145,9 +138,7 @@ class ShadowRootElement(BaseElement):
xpath = f'xpath:./following::{loc}'
return eles1 + self.parent_ele.eles(xpath, timeout=0.1)
def ele(self,
loc_or_str: Union[Tuple[str, str], str],
timeout: float = None) -> Union[DriverElement, str, None]:
def ele(self, loc_or_str, timeout=None):
"""返回当前元素下级符合条件的第一个元素,默认返回 \n
:param loc_or_str: 元素的定位信息可以是loc元组或查询字符串
:param timeout: 查找元素超时时间默认与元素所在页面等待时间一致
@ -155,9 +146,7 @@ class ShadowRootElement(BaseElement):
"""
return self._ele(loc_or_str, timeout)
def eles(self,
loc_or_str: Union[Tuple[str, str], str],
timeout: float = None) -> List[Union[DriverElement, str]]:
def eles(self, loc_or_str, timeout=None):
"""返回当前元素下级所有符合条件的子元素 \n
:param loc_or_str: 元素的定位信息可以是loc元组或查询字符串
:param timeout: 查找元素超时时间默认与元素所在页面等待时间一致
@ -165,25 +154,21 @@ class ShadowRootElement(BaseElement):
"""
return self._ele(loc_or_str, timeout=timeout, single=False)
def s_ele(self, loc_or_ele=None) -> Union[SessionElement, str, None]:
def s_ele(self, loc_or_str=None) -> Union[SessionElement, str, None]:
"""查找第一个符合条件的元素以SessionElement形式返回处理复杂页面时效率很高 \n
:param loc_or_ele: 元素的定位信息可以是loc元组或查询字符串
:param loc_or_str: 元素的定位信息可以是loc元组或查询字符串
:return: SessionElement对象或属性文本
"""
return make_session_ele(self, loc_or_ele)
return make_session_ele(self, loc_or_str)
def s_eles(self, loc_or_ele) -> List[Union[SessionElement, str]]:
def s_eles(self, loc_or_str):
"""查找所有符合条件的元素以SessionElement列表形式返回处理复杂页面时效率很高 \n
:param loc_or_ele: 元素的定位信息可以是loc元组或查询字符串
:param loc_or_str: 元素的定位信息可以是loc元组或查询字符串
:return: SessionElement对象或属性文本
"""
return make_session_ele(self, loc_or_ele, single=False)
return make_session_ele(self, loc_or_str, single=False)
def _ele(self,
loc_or_str: Union[Tuple[str, str], str],
timeout: float = None,
single: bool = True,
relative: bool = False) -> Union[DriverElement, str, None, List[Union[DriverElement, str]]]:
def _ele(self, loc_or_str, timeout=None, single=True, relative=False):
"""返回当前元素下级符合条件的子元素,默认返回第一个 \n
:param loc_or_str: 元素的定位信息可以是loc元组或查询字符串
:param timeout: 查找元素超时时间
@ -212,7 +197,7 @@ class ShadowRootElement(BaseElement):
else:
return [make_driver_ele(self, f'css:{css}', True, timeout) for css in css_paths]
def run_script(self, script: str, *args) -> Any:
def run_script(self, script, *args):
"""执行js代码传入自己为第一个参数 \n
:param script: js文本
:param args: 传入的参数
@ -221,11 +206,11 @@ class ShadowRootElement(BaseElement):
shadow_root = WebElement(self.page.driver, self.inner_ele._id)
return shadow_root.parent.execute_script(script, shadow_root, *args)
def is_enabled(self) -> bool:
def is_enabled(self):
"""是否可用"""
return self.inner_ele.is_enabled()
def is_valid(self) -> bool:
def is_valid(self):
"""用于判断元素是否还能用,应对页面跳转元素不能用的情况"""
try:
self.is_enabled()

View File

@ -63,9 +63,9 @@ class ShadowRootElement(BaseElement):
loc_or_str: Union[Tuple[str, str], str],
timeout: float = ...) -> List[Union[DriverElement, str]]: ...
def s_ele(self, loc_or_ele=...) -> Union[SessionElement, str, None]: ...
def s_ele(self, loc_or_str: Union[Tuple[str, str], str]=...) -> Union[SessionElement, str, None]: ...
def s_eles(self, loc_or_ele) -> List[Union[SessionElement, str]]: ...
def s_eles(self, loc_or_str: Union[Tuple[str, str], str]) -> List[Union[SessionElement, str]]: ...
def _ele(self,
loc_or_str: Union[Tuple[str, str], str],

View File

@ -1,17 +1,13 @@
# -*- coding:utf-8 -*-
from time import sleep
from typing import Union, Tuple, List
from DownloadKit import DownloadKit
from requests import Session, Response
from requests import Session
from tldextract import extract
from .chromium_base import ChromiumBase, ChromiumFrame
from .base import BasePage
from .chromium_element import ChromiumElement # , ChromiumBase
from .chromium_base import ChromiumBase
from .chromium_page import ChromiumPage
from .config import DriverOptions, SessionOptions, _cookies_to_tuple
from .session_element import SessionElement
from .config import DriverOptions, SessionOptions, cookies_to_tuple
from .session_page import SessionPage
from .tab import Tab
@ -19,12 +15,7 @@ from .tab import Tab
class WebPage(SessionPage, ChromiumPage, BasePage):
"""整合浏览器和request的页面类"""
def __init__(self,
mode: str = 'd',
timeout: float = 10,
tab_id: str = None,
driver_or_options: Union[Tab, DriverOptions, bool] = None,
session_or_options: Union[Session, SessionOptions, bool] = None) -> None:
def __init__(self, mode='d', timeout=10, tab_id=None, driver_or_options=None, session_or_options=None):
"""初始化函数 \n
:param mode: 'd' 's'即driver模式和session模式
:param timeout: 超时时间d模式时为寻找元素时间s模式时为连接时间默认10秒
@ -49,9 +40,7 @@ class WebPage(SessionPage, ChromiumPage, BasePage):
if self._mode == 'd':
self._driver
def __call__(self,
loc_or_str: Union[Tuple[str, str], str, ChromiumElement, SessionElement],
timeout: float = None) -> Union[ChromiumElement, SessionElement, ChromiumFrame, None]:
def __call__(self, loc_or_str, timeout=None):
"""在内部查找元素 \n
ele = page('@id=ele_id') \n
:param loc_or_str: 元素的定位信息可以是loc元组或查询字符串
@ -65,7 +54,7 @@ class WebPage(SessionPage, ChromiumPage, BasePage):
# -----------------共有属性和方法-------------------
@property
def url(self) -> Union[str, None]:
def url(self):
"""返回当前url"""
if self._mode == 'd':
return super(SessionPage, self).url if self._tab_obj else None
@ -73,7 +62,7 @@ class WebPage(SessionPage, ChromiumPage, BasePage):
return self._session_url
@property
def html(self) -> str:
def html(self):
"""返回页面html文本"""
if self._mode == 's':
return super().html
@ -81,7 +70,7 @@ class WebPage(SessionPage, ChromiumPage, BasePage):
return super(SessionPage, self).html if self._has_driver else ''
@property
def json(self) -> dict:
def json(self):
"""当返回内容是json格式时返回对应的字典"""
if self._mode == 's':
return super().json
@ -89,13 +78,13 @@ class WebPage(SessionPage, ChromiumPage, BasePage):
return super(SessionPage, self).json
@property
def response(self) -> Response:
def response(self):
"""返回 s 模式获取到的 Response 对象,切换到 s 模式"""
self.change_mode('s')
return self._response
@property
def mode(self) -> str:
def mode(self):
"""返回当前模式,'s''d' """
return self._mode
@ -107,7 +96,7 @@ class WebPage(SessionPage, ChromiumPage, BasePage):
return super(SessionPage, self).get_cookies()
@property
def session(self) -> Session:
def session(self):
"""返回Session对象如未初始化则按配置信息创建"""
if self._session is None:
self._set_session(self._session_options)
@ -118,12 +107,12 @@ class WebPage(SessionPage, ChromiumPage, BasePage):
return self._session
@property
def driver(self) -> Tab:
def driver(self):
"""返回纯粹的Tab对象"""
return self._tab_obj
@property
def _wait_driver(self) -> Tab:
def _wait_driver(self):
"""返回用于控制浏览器的Tab对象会先等待页面加载完毕"""
while self._is_loading:
sleep(.1)
@ -131,7 +120,7 @@ class WebPage(SessionPage, ChromiumPage, BasePage):
return self._driver
@property
def _driver(self) -> Tab:
def _driver(self):
"""返回纯粹的Tab对象调用时切换到d模式并连接浏览器"""
self.change_mode('d')
if self._tab_obj is None:
@ -143,17 +132,11 @@ class WebPage(SessionPage, ChromiumPage, BasePage):
self._tab_obj = tab
@property
def _session_url(self) -> str:
def _session_url(self):
"""返回 session 保存的url"""
return self._response.url if self._response else None
def get(self,
url: str,
show_errmsg: bool = False,
retry: int = None,
interval: float = None,
timeout: float = None,
**kwargs) -> Union[bool, None]:
def get(self, url, show_errmsg=False, retry=None, interval=None, timeout=None, **kwargs):
"""跳转到一个url \n
:param url: 目标url
:param show_errmsg: 是否显示和抛出异常
@ -168,9 +151,7 @@ class WebPage(SessionPage, ChromiumPage, BasePage):
elif self._mode == 's':
return super().get(url, show_errmsg, retry, interval, timeout, **kwargs)
def ele(self,
loc_or_ele: Union[Tuple[str, str], str, ChromiumElement, SessionElement],
timeout: float = None) -> Union[ChromiumElement, SessionElement, ChromiumFrame, str, None]:
def ele(self, loc_or_ele, timeout=None):
"""返回第一个符合条件的元素、属性或节点文本 \n
:param loc_or_ele: 元素的定位信息可以是元素对象loc元组或查询字符串
:param timeout: 查找元素超时时间默认与页面等待时间一致
@ -181,9 +162,7 @@ class WebPage(SessionPage, ChromiumPage, BasePage):
elif self._mode == 'd':
return super(SessionPage, self).ele(loc_or_ele, timeout=timeout)
def eles(self,
loc_or_str: Union[Tuple[str, str], str],
timeout: float = None) -> List[Union[ChromiumElement, SessionElement, ChromiumFrame, str]]:
def eles(self, loc_or_str, timeout=None):
"""返回页面中所有符合条件的元素、属性或节点文本 \n
:param loc_or_str: 元素的定位信息可以是loc元组或查询字符串
:param timeout: 查找元素超时时间默认与页面等待时间一致
@ -194,8 +173,7 @@ class WebPage(SessionPage, ChromiumPage, BasePage):
elif self._mode == 'd':
return super(SessionPage, self).eles(loc_or_str, timeout=timeout)
def s_ele(self, loc_or_ele: Union[Tuple[str, str], str, ChromiumElement, SessionElement] = None) \
-> Union[SessionElement, str, None]:
def s_ele(self, loc_or_ele=None):
"""查找第一个符合条件的元素以SessionElement形式返回d模式处理复杂页面时效率很高 \n
:param loc_or_ele: 元素的定位信息可以是loc元组或查询字符串
:return: SessionElement对象或属性文本
@ -205,7 +183,7 @@ class WebPage(SessionPage, ChromiumPage, BasePage):
elif self._mode == 'd':
return super(SessionPage, self).s_ele(loc_or_ele)
def s_eles(self, loc_or_str: Union[Tuple[str, str], str] = None) -> List[Union[SessionElement, str]]:
def s_eles(self, loc_or_str=None):
"""查找所有符合条件的元素以SessionElement形式返回d模式处理复杂页面时效率很高 \n
:param loc_or_str: 元素的定位信息可以是loc元组或查询字符串
:return: SessionElement对象或属性文本组成的列表
@ -215,7 +193,7 @@ class WebPage(SessionPage, ChromiumPage, BasePage):
elif self._mode == 'd':
return super(SessionPage, self).s_eles(loc_or_str)
def change_mode(self, mode: str = None, go: bool = True, copy_cookies: bool = True) -> None:
def change_mode(self, mode=None, go=True, copy_cookies=True):
"""切换模式,接收's''d',除此以外的字符串会切换为 d 模式 \n
切换时会把当前模式的cookies复制到目标模式 \n
切换后如果go是True调用相应的get函数使访问的页面同步 \n
@ -258,7 +236,7 @@ class WebPage(SessionPage, ChromiumPage, BasePage):
if url.startswith('http'):
self.get(url)
def cookies_to_session(self, copy_user_agent: bool = True) -> None:
def cookies_to_session(self, copy_user_agent=True):
"""把driver对象的cookies复制到session对象 \n
:param copy_user_agent: 是否复制ua信息
:return: None
@ -269,7 +247,7 @@ class WebPage(SessionPage, ChromiumPage, BasePage):
self.set_cookies(self._get_driver_cookies(as_dict=True), set_session=True)
def cookies_to_driver(self) -> None:
def cookies_to_driver(self):
"""把session对象的cookies复制到driver对象"""
ex_url = extract(self._session_url)
domain = f'{ex_url.domain}.{ex_url.suffix}'
@ -282,7 +260,7 @@ class WebPage(SessionPage, ChromiumPage, BasePage):
cookies.append(cookie)
self.set_cookies(cookies, set_driver=True)
def get_cookies(self, as_dict: bool = False, all_domains: bool = False) -> Union[dict, list]:
def get_cookies(self, as_dict=False, all_domains=False):
"""返回cookies \n
:param as_dict: 是否以字典方式返回
:param all_domains: 是否返回所有域的cookies
@ -293,18 +271,17 @@ class WebPage(SessionPage, ChromiumPage, BasePage):
elif self._mode == 'd':
return self._get_driver_cookies(as_dict)
def _get_driver_cookies(self, as_dict: bool = False):
def _get_driver_cookies(self, as_dict=False):
cookies = self._tab_obj.Network.getCookies()['cookies']
# cookies = super(WebPage, self)._wait_driver.Network.getCookies()['cookies']
if as_dict:
return {cookie['name']: cookie['value'] for cookie in cookies}
else:
return cookies
def set_cookies(self, cookies, set_session: bool = False, set_driver: bool = False):
def set_cookies(self, cookies, set_session=False, set_driver=False):
# 添加cookie到driver
if set_driver:
cookies = _cookies_to_tuple(cookies)
cookies = cookies_to_tuple(cookies)
result_cookies = []
for cookie in cookies:
if not cookie.get('domain', None):
@ -330,7 +307,7 @@ class WebPage(SessionPage, ChromiumPage, BasePage):
# elif self._mode == 'd':
# super(SessionPage, self).set_headers(headers)
def check_page(self, by_requests: bool = False) -> Union[bool, None]:
def check_page(self, by_requests=False):
"""d模式时检查网页是否符合预期 \n
默认由response状态检查可重载实现针对性检查 \n
:param by_requests: 是否用内置response检查
@ -345,7 +322,7 @@ class WebPage(SessionPage, ChromiumPage, BasePage):
r = self._make_response(self.url, retry=0)[0]
return r.ok if r else False
def close_driver(self) -> None:
def close_driver(self):
"""关闭driver及浏览器"""
if self._has_driver:
self.change_mode('s')
@ -355,7 +332,7 @@ class WebPage(SessionPage, ChromiumPage, BasePage):
pass
self._has_driver = None
def close_session(self) -> None:
def close_session(self):
"""关闭session"""
if self._has_session:
self.change_mode('d')
@ -365,13 +342,7 @@ class WebPage(SessionPage, ChromiumPage, BasePage):
self._has_session = None
# ----------------重写SessionPage的函数-----------------------
def post(self,
url: str,
data: Union[dict, str] = None,
show_errmsg: bool = False,
retry: int = None,
interval: float = None,
**kwargs) -> bool:
def post(self, url: str, data=None, show_errmsg=False, retry=None, interval=None, **kwargs):
"""用post方式跳转到url会切换到s模式 \n
:param url: 目标url
:param data: post方式时提交的数据
@ -385,17 +356,13 @@ class WebPage(SessionPage, ChromiumPage, BasePage):
return super().post(url, data, show_errmsg, retry, interval, **kwargs)
@property
def download(self) -> DownloadKit:
def download(self):
"""返回下载器对象"""
if self.mode == 'd':
self.cookies_to_session()
return super().download
def _ele(self,
loc_or_ele: Union[Tuple[str, str], str, ChromiumElement, SessionElement],
timeout: float = None, single: bool = True, relative: bool = False) \
-> Union[ChromiumElement, SessionElement, ChromiumFrame, str, None, List[Union[SessionElement, str]], List[
Union[ChromiumElement, str, ChromiumFrame]]]:
def _ele(self, loc_or_ele, timeout=None, single=True, relative=False):
"""返回页面中符合条件的元素、属性或节点文本,默认返回第一个 \n
:param loc_or_ele: 元素的定位信息可以是元素对象loc元组或查询字符串
:param timeout: 查找元素超时时间d模式专用
@ -446,7 +413,7 @@ class WebPage(SessionPage, ChromiumPage, BasePage):
else:
raise TypeError('session_or_options参数只能接收Session, dict, SessionOptions或False。')
def quit(self) -> None:
def quit(self):
"""关闭浏览器关闭session"""
if self._has_session:
self._session.close()

View File

@ -51,7 +51,7 @@ class WebPage(SessionPage, ChromiumPage, BasePage):
def mode(self) -> str: ...
@property
def cookies(self): ...
def cookies(self)->Union[dict, list]: ...
@property
def session(self) -> Session: ...
@ -65,8 +65,8 @@ class WebPage(SessionPage, ChromiumPage, BasePage):
@property
def _driver(self) -> Tab: ...
# @_driver.setter
# def _driver(self, tab): ...
@_driver.setter
def _driver(self, tab:Tab): ...
@property
def _session_url(self) -> str: ...
@ -112,9 +112,9 @@ class WebPage(SessionPage, ChromiumPage, BasePage):
def get_cookies(self, as_dict: bool = ..., all_domains: bool = ...) -> Union[dict, list]: ...
def _get_driver_cookies(self, as_dict: bool = ...): ...
def _get_driver_cookies(self, as_dict: bool = ...)->dict: ...
def set_cookies(self, cookies, set_session: bool = ..., set_driver: bool = ...): ...
def set_cookies(self, cookies, set_session: bool = ..., set_driver: bool = ...) -> None: ...
def check_page(self, by_requests: bool = ...) -> Union[bool, None]: ...
@ -152,8 +152,8 @@ class WebPage(SessionPage, ChromiumPage, BasePage):
-> Union[ChromiumElement, SessionElement, ChromiumFrame, str, None, List[Union[SessionElement, str]], List[
Union[ChromiumElement, str, ChromiumFrame]]]: ...
def _set_driver_options(self, Tab_or_Options): ...
def _set_driver_options(self, Tab_or_Options:Union[Tab, DriverOptions]) -> None: ...
def _set_session_options(self, Session_or_Options): ...
def _set_session_options(self, Session_or_Options:Union[Session, SessionOptions]) -> None: ...
def quit(self) -> None: ...