mirror of
https://gitee.com/g1879/DrissionPage.git
synced 2024-12-10 04:00:23 +08:00
用存根文件取代类型注解
This commit is contained in:
parent
d210db2844
commit
b0dc817ecd
@ -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;')
|
||||
|
@ -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: ...
|
||||
|
@ -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
|
||||
|
@ -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 = ...): ...
|
||||
|
@ -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: 查找元素的超时时间
|
||||
|
@ -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
@ -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: ...
|
||||
|
||||
|
@ -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: 窗口标题
|
||||
|
@ -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: ...
|
||||
|
@ -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)
|
||||
|
@ -1,5 +1,4 @@
|
||||
# -*- coding:utf-8 -*-
|
||||
|
||||
from .chromium_base import ChromiumBase
|
||||
from .chromium_page import ChromiumPage
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
226
DrissionPage/config.pyi
Normal 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: ...
|
@ -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对象或DriverOptions、Options类,传入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,从端口号获取
|
||||
|
@ -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: ...
|
||||
|
@ -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
|
||||
|
@ -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: ...
|
||||
|
||||
|
@ -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,可传入id、name、序号、元素对象、定位符
|
||||
: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: 指定的标签页,可以是多个
|
||||
|
@ -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: ...
|
||||
|
@ -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()
|
||||
|
@ -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: ...
|
||||
|
@ -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对象
|
||||
|
@ -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: ...
|
||||
|
@ -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()
|
||||
|
@ -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: ...
|
||||
|
@ -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()
|
||||
|
@ -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],
|
||||
|
@ -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()
|
||||
|
@ -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: ...
|
||||
|
Loading…
x
Reference in New Issue
Block a user