mirror of
https://gitee.com/g1879/DrissionPage.git
synced 2024-12-10 04:00:23 +08:00
commit
ff016d6095
@ -14,4 +14,4 @@ from ._configs.chromium_options import ChromiumOptions
|
||||
from ._configs.session_options import SessionOptions
|
||||
|
||||
__all__ = ['ChromiumPage', 'ChromiumOptions', 'SessionOptions', 'SessionPage', 'WebPage', '__version__']
|
||||
__version__ = '4.0.2'
|
||||
__version__ = '4.0.4'
|
||||
|
@ -20,31 +20,30 @@ from ..errors import ElementNotFoundError
|
||||
class BaseParser(object):
|
||||
"""所有页面、元素类的基类"""
|
||||
|
||||
def __call__(self, loc_or_str):
|
||||
return self.ele(loc_or_str)
|
||||
def __call__(self, locator):
|
||||
return self.ele(locator)
|
||||
|
||||
def ele(self, loc_or_ele, index=1, timeout=None):
|
||||
return self._ele(loc_or_ele, timeout, index=index, method='ele()')
|
||||
def ele(self, locator, index=1, timeout=None):
|
||||
return self._ele(locator, timeout, index=index, method='ele()')
|
||||
|
||||
def eles(self, loc_or_str, timeout=None):
|
||||
return self._ele(loc_or_str, timeout, index=None)
|
||||
def eles(self, locator, timeout=None):
|
||||
return self._ele(locator, timeout, index=None)
|
||||
|
||||
# ----------------以下属性或方法待后代实现----------------
|
||||
@property
|
||||
def html(self):
|
||||
return ''
|
||||
|
||||
def s_ele(self, loc_or_ele):
|
||||
def s_ele(self, locator):
|
||||
pass
|
||||
|
||||
def s_eles(self, loc_or_str):
|
||||
def s_eles(self, locator):
|
||||
pass
|
||||
|
||||
def _ele(self, loc_or_ele, timeout=None, index=1, raise_err=None, method=None):
|
||||
def _ele(self, locator, timeout=None, index=1, raise_err=None, method=None):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def _find_elements(self, loc_or_ele, timeout=None, index=1, raise_err=None):
|
||||
def _find_elements(self, locator, timeout=None, index=1, relative=False, raise_err=None):
|
||||
pass
|
||||
|
||||
|
||||
@ -53,6 +52,7 @@ class BaseElement(BaseParser):
|
||||
|
||||
def __init__(self, page=None):
|
||||
self.page = page
|
||||
self._type = 'BaseElement'
|
||||
|
||||
# ----------------以下属性或方法由后代实现----------------
|
||||
@property
|
||||
@ -68,9 +68,9 @@ class BaseElement(BaseParser):
|
||||
def nexts(self):
|
||||
pass
|
||||
|
||||
def _ele(self, loc_or_str, timeout=None, index=1, relative=False, raise_err=None, method=None):
|
||||
def _ele(self, locator, timeout=None, index=1, relative=False, raise_err=None, method=None):
|
||||
"""调用获取元素的方法
|
||||
:param loc_or_str: 定位符
|
||||
:param locator: 定位符
|
||||
:param timeout: 超时时间(秒)
|
||||
:param index: 获取第几个,从1开始,可传入负数获取倒数第几个
|
||||
:param relative: 是否相对定位
|
||||
@ -78,24 +78,19 @@ class BaseElement(BaseParser):
|
||||
:param method: 调用的方法名
|
||||
:return: 元素对象或它们组成的列表
|
||||
"""
|
||||
r = self._find_elements(loc_or_str, timeout=timeout, index=index, relative=relative, raise_err=raise_err)
|
||||
r = self._find_elements(locator, timeout=timeout, index=index, relative=relative, raise_err=raise_err)
|
||||
if r or isinstance(r, list):
|
||||
return r
|
||||
if Settings.raise_when_ele_not_found or raise_err is True:
|
||||
raise ElementNotFoundError(None, method, {'loc_or_str': loc_or_str, 'index': index})
|
||||
raise ElementNotFoundError(None, method, {'locator': locator, 'index': index})
|
||||
|
||||
r.method = method
|
||||
r.args = {'loc_or_str': loc_or_str, 'index': index}
|
||||
r.args = {'locator': locator, 'index': index}
|
||||
return r
|
||||
|
||||
@abstractmethod
|
||||
def _find_elements(self, loc_or_str, timeout=None, index=1, relative=False, raise_err=None):
|
||||
pass
|
||||
|
||||
|
||||
class DrissionElement(BaseElement):
|
||||
"""ChromiumElement 和 SessionElement的基类
|
||||
但不是ShadowRoot的基类"""
|
||||
"""ChromiumElement 和 SessionElement的基类,但不是ShadowRoot的基类"""
|
||||
|
||||
@property
|
||||
def link(self):
|
||||
@ -151,21 +146,21 @@ class DrissionElement(BaseElement):
|
||||
|
||||
return self._ele(loc, timeout=0, relative=True, raise_err=False, method='parent()')
|
||||
|
||||
def child(self, filter_loc='', index=1, timeout=None, ele_only=True):
|
||||
def child(self, locator='', index=1, timeout=None, ele_only=True):
|
||||
"""返回直接子元素元素或节点组成的列表,可用查询语法筛选
|
||||
:param filter_loc: 用于筛选的查询语法
|
||||
:param locator: 用于筛选的查询语法
|
||||
:param index: 第几个查询结果,1开始
|
||||
:param timeout: 查找节点的超时时间(秒)
|
||||
:param ele_only: 是否只获取元素,为False时把文本、注释节点也纳入
|
||||
:return: 直接子元素或节点文本组成的列表
|
||||
"""
|
||||
if isinstance(filter_loc, int):
|
||||
index = filter_loc
|
||||
filter_loc = ''
|
||||
if not filter_loc:
|
||||
if isinstance(locator, int):
|
||||
index = locator
|
||||
locator = ''
|
||||
if not locator:
|
||||
loc = '*' if ele_only else 'node()'
|
||||
else:
|
||||
loc = get_loc(filter_loc, True) # 把定位符转换为xpath
|
||||
loc = get_loc(locator, True) # 把定位符转换为xpath
|
||||
if loc[0] == 'css selector':
|
||||
raise ValueError('此css selector语法不受支持,请换成xpath。')
|
||||
loc = loc[1].lstrip('./')
|
||||
@ -175,62 +170,62 @@ class DrissionElement(BaseElement):
|
||||
return node
|
||||
|
||||
if Settings.raise_when_ele_not_found:
|
||||
raise ElementNotFoundError(None, 'child()', {'filter_loc': filter_loc, 'index': index,
|
||||
raise ElementNotFoundError(None, 'child()', {'locator': locator, 'index': index,
|
||||
'ele_only': ele_only})
|
||||
else:
|
||||
return NoneElement(self.page, 'child()', {'filter_loc': filter_loc, 'index': index, 'ele_only': ele_only})
|
||||
return NoneElement(self.page, 'child()', {'locator': locator, 'index': index, 'ele_only': ele_only})
|
||||
|
||||
def prev(self, filter_loc='', index=1, timeout=None, ele_only=True):
|
||||
def prev(self, locator='', index=1, timeout=None, ele_only=True):
|
||||
"""返回前面的一个兄弟元素,可用查询语法筛选,可指定返回筛选结果的第几个
|
||||
:param filter_loc: 用于筛选的查询语法
|
||||
:param locator: 用于筛选的查询语法
|
||||
:param index: 前面第几个查询结果,1开始
|
||||
:param timeout: 查找节点的超时时间(秒)
|
||||
:param ele_only: 是否只获取元素,为False时把文本、注释节点也纳入
|
||||
:return: 兄弟元素
|
||||
"""
|
||||
return self._get_relative('prev()', 'preceding', True, filter_loc, index, timeout, ele_only)
|
||||
return self._get_relative('prev()', 'preceding', True, locator, index, timeout, ele_only)
|
||||
|
||||
def next(self, filter_loc='', index=1, timeout=None, ele_only=True):
|
||||
def next(self, locator='', index=1, timeout=None, ele_only=True):
|
||||
"""返回后面的一个兄弟元素,可用查询语法筛选,可指定返回筛选结果的第几个
|
||||
:param filter_loc: 用于筛选的查询语法
|
||||
:param locator: 用于筛选的查询语法
|
||||
:param index: 后面第几个查询结果,1开始
|
||||
:param timeout: 查找节点的超时时间(秒)
|
||||
:param ele_only: 是否只获取元素,为False时把文本、注释节点也纳入
|
||||
:return: 兄弟元素
|
||||
"""
|
||||
return self._get_relative('next()', 'following', True, filter_loc, index, timeout, ele_only)
|
||||
return self._get_relative('next()', 'following', True, locator, index, timeout, ele_only)
|
||||
|
||||
def before(self, filter_loc='', index=1, timeout=None, ele_only=True):
|
||||
def before(self, locator='', index=1, timeout=None, ele_only=True):
|
||||
"""返回前面的一个兄弟元素,可用查询语法筛选,可指定返回筛选结果的第几个
|
||||
:param filter_loc: 用于筛选的查询语法
|
||||
:param locator: 用于筛选的查询语法
|
||||
:param index: 前面第几个查询结果,1开始
|
||||
:param timeout: 查找节点的超时时间(秒)
|
||||
:param ele_only: 是否只获取元素,为False时把文本、注释节点也纳入
|
||||
:return: 本元素前面的某个元素或节点
|
||||
"""
|
||||
return self._get_relative('before()', 'preceding', False, filter_loc, index, timeout, ele_only)
|
||||
return self._get_relative('before()', 'preceding', False, locator, index, timeout, ele_only)
|
||||
|
||||
def after(self, filter_loc='', index=1, timeout=None, ele_only=True):
|
||||
def after(self, locator='', index=1, timeout=None, ele_only=True):
|
||||
"""返回后面的一个兄弟元素,可用查询语法筛选,可指定返回筛选结果的第几个
|
||||
:param filter_loc: 用于筛选的查询语法
|
||||
:param locator: 用于筛选的查询语法
|
||||
:param index: 后面第几个查询结果,1开始
|
||||
:param timeout: 查找节点的超时时间(秒)
|
||||
:param ele_only: 是否只获取元素,为False时把文本、注释节点也纳入
|
||||
:return: 本元素后面的某个元素或节点
|
||||
"""
|
||||
return self._get_relative('after()', 'following', False, filter_loc, index, timeout, ele_only)
|
||||
return self._get_relative('after()', 'following', False, locator, index, timeout, ele_only)
|
||||
|
||||
def children(self, filter_loc='', timeout=None, ele_only=True):
|
||||
def children(self, locator='', timeout=None, ele_only=True):
|
||||
"""返回直接子元素元素或节点组成的列表,可用查询语法筛选
|
||||
:param filter_loc: 用于筛选的查询语法
|
||||
:param locator: 用于筛选的查询语法
|
||||
:param timeout: 查找节点的超时时间(秒)
|
||||
:param ele_only: 是否只获取元素,为False时把文本、注释节点也纳入
|
||||
:return: 直接子元素或节点文本组成的列表
|
||||
"""
|
||||
if not filter_loc:
|
||||
if not locator:
|
||||
loc = '*' if ele_only else 'node()'
|
||||
else:
|
||||
loc = get_loc(filter_loc, True) # 把定位符转换为xpath
|
||||
loc = get_loc(locator, True) # 把定位符转换为xpath
|
||||
if loc[0] == 'css selector':
|
||||
raise ValueError('此css selector语法不受支持,请换成xpath。')
|
||||
loc = loc[1].lstrip('./')
|
||||
@ -239,69 +234,69 @@ class DrissionElement(BaseElement):
|
||||
nodes = self._ele(loc, timeout=timeout, index=None, relative=True)
|
||||
return [e for e in nodes if not (isinstance(e, str) and sub('[ \n\t\r]', '', e) == '')]
|
||||
|
||||
def prevs(self, filter_loc='', timeout=None, ele_only=True):
|
||||
def prevs(self, locator='', timeout=None, ele_only=True):
|
||||
"""返回前面全部兄弟元素或节点组成的列表,可用查询语法筛选
|
||||
:param filter_loc: 用于筛选的查询语法
|
||||
:param locator: 用于筛选的查询语法
|
||||
:param timeout: 查找节点的超时时间(秒)
|
||||
:param ele_only: 是否只获取元素,为False时把文本、注释节点也纳入
|
||||
:return: 兄弟元素或节点文本组成的列表
|
||||
"""
|
||||
return self._get_relatives(filter_loc=filter_loc, direction='preceding', timeout=timeout, ele_only=ele_only)
|
||||
return self._get_relatives(locator=locator, direction='preceding', timeout=timeout, ele_only=ele_only)
|
||||
|
||||
def nexts(self, filter_loc='', timeout=None, ele_only=True):
|
||||
def nexts(self, locator='', timeout=None, ele_only=True):
|
||||
"""返回后面全部兄弟元素或节点组成的列表,可用查询语法筛选
|
||||
:param filter_loc: 用于筛选的查询语法
|
||||
:param locator: 用于筛选的查询语法
|
||||
:param timeout: 查找节点的超时时间(秒)
|
||||
:param ele_only: 是否只获取元素,为False时把文本、注释节点也纳入
|
||||
:return: 兄弟元素或节点文本组成的列表
|
||||
"""
|
||||
return self._get_relatives(filter_loc=filter_loc, direction='following', timeout=timeout, ele_only=ele_only)
|
||||
return self._get_relatives(locator=locator, direction='following', timeout=timeout, ele_only=ele_only)
|
||||
|
||||
def befores(self, filter_loc='', timeout=None, ele_only=True):
|
||||
def befores(self, locator='', timeout=None, ele_only=True):
|
||||
"""返回后面全部兄弟元素或节点组成的列表,可用查询语法筛选
|
||||
:param filter_loc: 用于筛选的查询语法
|
||||
:param locator: 用于筛选的查询语法
|
||||
:param timeout: 查找节点的超时时间(秒)
|
||||
:param ele_only: 是否只获取元素,为False时把文本、注释节点也纳入
|
||||
:return: 本元素前面的元素或节点组成的列表
|
||||
"""
|
||||
return self._get_relatives(filter_loc=filter_loc, direction='preceding',
|
||||
return self._get_relatives(locator=locator, direction='preceding',
|
||||
brother=False, timeout=timeout, ele_only=ele_only)
|
||||
|
||||
def afters(self, filter_loc='', timeout=None, ele_only=True):
|
||||
def afters(self, locator='', timeout=None, ele_only=True):
|
||||
"""返回前面全部兄弟元素或节点组成的列表,可用查询语法筛选
|
||||
:param filter_loc: 用于筛选的查询语法
|
||||
:param locator: 用于筛选的查询语法
|
||||
:param timeout: 查找节点的超时时间(秒)
|
||||
:param ele_only: 是否只获取元素,为False时把文本、注释节点也纳入
|
||||
:return: 本元素后面的元素或节点组成的列表
|
||||
"""
|
||||
return self._get_relatives(filter_loc=filter_loc, direction='following',
|
||||
return self._get_relatives(locator=locator, direction='following',
|
||||
brother=False, timeout=timeout, ele_only=ele_only)
|
||||
|
||||
def _get_relative(self, func, direction, brother, filter_loc='', index=1, timeout=None, ele_only=True):
|
||||
def _get_relative(self, func, direction, brother, locator='', index=1, timeout=None, ele_only=True):
|
||||
"""获取一个亲戚元素或节点,可用查询语法筛选,可指定返回筛选结果的第几个
|
||||
:param func: 方法名称
|
||||
:param direction: 方向,'following' 或 'preceding'
|
||||
:param filter_loc: 用于筛选的查询语法
|
||||
:param locator: 用于筛选的查询语法
|
||||
:param index: 前面第几个查询结果,1开始
|
||||
:param timeout: 查找节点的超时时间(秒)
|
||||
:param ele_only: 是否只获取元素,为False时把文本、注释节点也纳入
|
||||
:return: 本元素前面的某个元素或节点
|
||||
"""
|
||||
if isinstance(filter_loc, int):
|
||||
index = filter_loc
|
||||
filter_loc = ''
|
||||
node = self._get_relatives(index, filter_loc, direction, brother, timeout, ele_only)
|
||||
if isinstance(locator, int):
|
||||
index = locator
|
||||
locator = ''
|
||||
node = self._get_relatives(index, locator, direction, brother, timeout, ele_only)
|
||||
if node:
|
||||
return node
|
||||
if Settings.raise_when_ele_not_found:
|
||||
raise ElementNotFoundError(None, func, {'filter_loc': filter_loc, 'index': index, 'ele_only': ele_only})
|
||||
raise ElementNotFoundError(None, func, {'locator': locator, 'index': index, 'ele_only': ele_only})
|
||||
else:
|
||||
return NoneElement(self.page, func, {'filter_loc': filter_loc, 'index': index, 'ele_only': ele_only})
|
||||
return NoneElement(self.page, func, {'locator': locator, 'index': index, 'ele_only': ele_only})
|
||||
|
||||
def _get_relatives(self, index=None, filter_loc='', direction='following', brother=True, timeout=.5, ele_only=True):
|
||||
def _get_relatives(self, index=None, locator='', direction='following', brother=True, timeout=.5, ele_only=True):
|
||||
"""按要求返回兄弟元素或节点组成的列表
|
||||
:param index: 获取第几个,该参数不为None时只获取该编号的元素
|
||||
:param filter_loc: 用于筛选的查询语法
|
||||
:param locator: 用于筛选的查询语法
|
||||
:param direction: 'following' 或 'preceding',查找的方向
|
||||
:param brother: 查找范围,在同级查找还是整个dom前后查找
|
||||
:param timeout: 查找等待时间(秒)
|
||||
@ -309,11 +304,11 @@ class DrissionElement(BaseElement):
|
||||
"""
|
||||
brother = '-sibling' if brother else ''
|
||||
|
||||
if not filter_loc:
|
||||
if not locator:
|
||||
loc = '*' if ele_only else 'node()'
|
||||
|
||||
else:
|
||||
loc = get_loc(filter_loc, True) # 把定位符转换为xpath
|
||||
loc = get_loc(locator, True) # 把定位符转换为xpath
|
||||
if loc[0] == 'css selector':
|
||||
raise ValueError('此css selector语法不受支持,请换成xpath。')
|
||||
loc = loc[1].lstrip('./')
|
||||
@ -341,12 +336,15 @@ class DrissionElement(BaseElement):
|
||||
return
|
||||
|
||||
@abstractmethod
|
||||
def attr(self, attr: str):
|
||||
def attr(self, name: str):
|
||||
return ''
|
||||
|
||||
def _get_ele_path(self, mode):
|
||||
return ''
|
||||
|
||||
def _find_elements(self, locator, timeout=None, index=1, relative=False, raise_err=None):
|
||||
pass
|
||||
|
||||
|
||||
class BasePage(BaseParser):
|
||||
"""页面类的基类"""
|
||||
@ -362,6 +360,7 @@ class BasePage(BaseParser):
|
||||
self._download_path = None
|
||||
self._none_ele_return_value = False
|
||||
self._none_ele_value = None
|
||||
self._type = 'BasePage'
|
||||
|
||||
@property
|
||||
def title(self):
|
||||
@ -379,11 +378,6 @@ class BasePage(BaseParser):
|
||||
"""设置查找元素时等待的秒数"""
|
||||
self._timeout = second
|
||||
|
||||
@property
|
||||
def cookies(self):
|
||||
"""返回cookies"""
|
||||
return self.get_cookies(True)
|
||||
|
||||
@property
|
||||
def url_available(self):
|
||||
"""返回当前访问的url有效性"""
|
||||
@ -415,36 +409,32 @@ class BasePage(BaseParser):
|
||||
return
|
||||
|
||||
@abstractmethod
|
||||
def get_cookies(self, as_dict=False, all_info=False):
|
||||
def cookies(self, as_dict=False, all_info=False):
|
||||
return {}
|
||||
|
||||
@abstractmethod
|
||||
def get(self, url, show_errmsg=False, retry=None, interval=None):
|
||||
pass
|
||||
|
||||
def _ele(self, loc_or_ele, timeout=None, index=1, raise_err=None, method=None):
|
||||
def _ele(self, locator, timeout=None, index=1, raise_err=None, method=None):
|
||||
"""调用获取元素的方法
|
||||
:param loc_or_ele: 定位符
|
||||
:param locator: 定位符
|
||||
:param timeout: 超时时间(秒)
|
||||
:param index: 获取第几个,从1开始,可传入负数获取倒数第几个
|
||||
:param raise_err: 找不到时是否抛出异常
|
||||
:param method: 调用的方法名
|
||||
:return: 元素对象或它们组成的列表
|
||||
"""
|
||||
if not loc_or_ele:
|
||||
raise ElementNotFoundError(None, method, {'loc_or_str': loc_or_ele})
|
||||
if not locator:
|
||||
raise ElementNotFoundError(None, method, {'locator': locator})
|
||||
|
||||
r = self._find_elements(loc_or_ele, timeout=timeout, index=index, raise_err=raise_err)
|
||||
r = self._find_elements(locator, timeout=timeout, index=index, raise_err=raise_err)
|
||||
|
||||
if r or isinstance(r, list):
|
||||
return r
|
||||
if Settings.raise_when_ele_not_found or raise_err is True:
|
||||
raise ElementNotFoundError(None, method, {'loc_or_str': loc_or_ele, 'index': index})
|
||||
raise ElementNotFoundError(None, method, {'locator': locator, 'index': index})
|
||||
|
||||
r.method = method
|
||||
r.args = {'loc_or_str': loc_or_ele, 'index': index}
|
||||
r.args = {'locator': locator, 'index': index}
|
||||
return r
|
||||
|
||||
@abstractmethod
|
||||
def _find_elements(self, loc_or_ele, timeout=None, index=1, raise_err=None):
|
||||
pass
|
||||
|
@ -14,36 +14,37 @@ from .._elements.none_element import NoneElement
|
||||
|
||||
|
||||
class BaseParser(object):
|
||||
_type: str
|
||||
|
||||
def __call__(self, loc_or_str: Union[Tuple[str, str], str], index: int = 1): ...
|
||||
def __call__(self, locator: Union[Tuple[str, str], str], index: int = 1): ...
|
||||
|
||||
def ele(self,
|
||||
loc_or_ele: Union[Tuple[str, str], str, BaseElement],
|
||||
locator: Union[Tuple[str, str], str, BaseElement],
|
||||
index: int = 1,
|
||||
timeout: float = None): ...
|
||||
|
||||
def eles(self, loc_or_str: Union[Tuple[str, str], str], timeout=None): ...
|
||||
def eles(self, locator: Union[Tuple[str, str], str], timeout=None): ...
|
||||
|
||||
# ----------------以下属性或方法待后代实现----------------
|
||||
@property
|
||||
def html(self) -> str: ...
|
||||
|
||||
def s_ele(self, loc_or_ele: Union[Tuple[str, str], str, BaseElement], index: int = 1): ...
|
||||
def s_ele(self, locator: Union[Tuple[str, str], str, BaseElement], index: int = 1): ...
|
||||
|
||||
def s_eles(self, loc_or_str: Union[Tuple[str, str], str]): ...
|
||||
def s_eles(self, locator: Union[Tuple[str, str], str]): ...
|
||||
|
||||
def _ele(self,
|
||||
loc_or_ele,
|
||||
locator: Union[Tuple[str, str], str],
|
||||
timeout: float = None,
|
||||
index: Optional[int] = 1,
|
||||
raise_err: bool = None,
|
||||
method: str = None): ...
|
||||
|
||||
@abstractmethod
|
||||
def _find_elements(self,
|
||||
loc_or_ele,
|
||||
locator: Union[Tuple[str, str], str],
|
||||
timeout: float = None,
|
||||
index: Optional[int] = 1,
|
||||
relative: bool = False,
|
||||
raise_err: bool = None): ...
|
||||
|
||||
|
||||
@ -57,20 +58,13 @@ class BaseElement(BaseParser):
|
||||
def tag(self) -> str: ...
|
||||
|
||||
def _ele(self,
|
||||
loc_or_str: Union[Tuple[str, str], str],
|
||||
locator: Union[Tuple[str, str], str],
|
||||
timeout: float = None,
|
||||
index: Optional[int] = 1,
|
||||
relative: bool = False,
|
||||
raise_err: bool = None,
|
||||
method: str = None): ...
|
||||
|
||||
@abstractmethod
|
||||
def _find_elements(self, loc_or_str,
|
||||
timeout: float = None,
|
||||
index: Optional[int] = 1,
|
||||
relative: bool = False,
|
||||
raise_err: bool = None): ...
|
||||
|
||||
def parent(self, level_or_loc: Union[tuple, str, int] = 1): ...
|
||||
|
||||
def prev(self, index: int = 1) -> None: ...
|
||||
@ -107,57 +101,57 @@ class DrissionElement(BaseElement):
|
||||
index: int = 1) -> Union[DrissionElement, None]: ...
|
||||
|
||||
def child(self,
|
||||
filter_loc: Union[tuple, str, int] = '',
|
||||
locator: Union[Tuple[str, str], str, int] = '',
|
||||
index: int = 1,
|
||||
timeout: float = None,
|
||||
ele_only: bool = True) -> Union[DrissionElement, str, NoneElement]: ...
|
||||
|
||||
def prev(self,
|
||||
filter_loc: Union[tuple, str, int] = '',
|
||||
locator: Union[Tuple[str, str], str, int] = '',
|
||||
index: int = 1,
|
||||
timeout: float = None,
|
||||
ele_only: bool = True) -> Union[DrissionElement, str, NoneElement]: ...
|
||||
|
||||
def next(self,
|
||||
filter_loc: Union[tuple, str, int] = '',
|
||||
locator: Union[Tuple[str, str], str, int] = '',
|
||||
index: int = 1,
|
||||
timeout: float = None,
|
||||
ele_only: bool = True) -> Union[DrissionElement, str, NoneElement]: ...
|
||||
|
||||
def before(self,
|
||||
filter_loc: Union[tuple, str, int] = '',
|
||||
locator: Union[Tuple[str, str], str, int] = '',
|
||||
index: int = 1,
|
||||
timeout: float = None,
|
||||
ele_only: bool = True) -> Union[DrissionElement, str, NoneElement]: ...
|
||||
|
||||
def after(self,
|
||||
filter_loc: Union[tuple, str, int] = '',
|
||||
locator: Union[Tuple[str, str], str, int] = '',
|
||||
index: int = 1,
|
||||
timeout: float = None,
|
||||
ele_only: bool = True) -> Union[DrissionElement, str, NoneElement]: ...
|
||||
|
||||
def children(self,
|
||||
filter_loc: Union[tuple, str] = '',
|
||||
locator: Union[Tuple[str, str], str] = '',
|
||||
timeout: float = None,
|
||||
ele_only: bool = True) -> List[Union[DrissionElement, str]]: ...
|
||||
|
||||
def prevs(self,
|
||||
filter_loc: Union[tuple, str] = '',
|
||||
locator: Union[Tuple[str, str], str] = '',
|
||||
timeout: float = None,
|
||||
ele_only: bool = True) -> List[Union[DrissionElement, str]]: ...
|
||||
|
||||
def nexts(self,
|
||||
filter_loc: Union[tuple, str] = '',
|
||||
locator: Union[Tuple[str, str], str] = '',
|
||||
timeout: float = None,
|
||||
ele_only: bool = True) -> List[Union[DrissionElement, str]]: ...
|
||||
|
||||
def befores(self,
|
||||
filter_loc: Union[tuple, str] = '',
|
||||
locator: Union[Tuple[str, str], str] = '',
|
||||
timeout: float = None,
|
||||
ele_only: bool = True) -> List[Union[DrissionElement, str]]: ...
|
||||
|
||||
def afters(self,
|
||||
filter_loc: Union[tuple, str] = '',
|
||||
locator: Union[Tuple[str, str], str] = '',
|
||||
timeout: float = None,
|
||||
ele_only: bool = True) -> List[Union[DrissionElement, str]]: ...
|
||||
|
||||
@ -165,14 +159,14 @@ class DrissionElement(BaseElement):
|
||||
func: str,
|
||||
direction: str,
|
||||
brother: bool,
|
||||
filter_loc: Union[tuple, str] = '',
|
||||
locator: Union[Tuple[str, str], str] = '',
|
||||
index: int = 1,
|
||||
timeout: float = None,
|
||||
ele_only: bool = True) -> DrissionElement: ...
|
||||
|
||||
def _get_relatives(self,
|
||||
index: int = None,
|
||||
filter_loc: Union[tuple, str] = '',
|
||||
locator: Union[Tuple[str, str], str] = '',
|
||||
direction: str = 'following',
|
||||
brother: bool = True,
|
||||
timeout: float = 0.5,
|
||||
@ -189,7 +183,7 @@ class DrissionElement(BaseElement):
|
||||
def raw_text(self) -> str: ...
|
||||
|
||||
@abstractmethod
|
||||
def attr(self, attr: str) -> str: ...
|
||||
def attr(self, name: str) -> str: ...
|
||||
|
||||
def _get_ele_path(self, mode) -> str: ...
|
||||
|
||||
@ -215,9 +209,6 @@ class BasePage(BaseParser):
|
||||
@timeout.setter
|
||||
def timeout(self, second: float) -> None: ...
|
||||
|
||||
@property
|
||||
def cookies(self) -> dict: ...
|
||||
|
||||
@property
|
||||
def url_available(self) -> bool: ...
|
||||
|
||||
@ -238,21 +229,14 @@ class BasePage(BaseParser):
|
||||
def user_agent(self) -> str: ...
|
||||
|
||||
@abstractmethod
|
||||
def get_cookies(self, as_dict: bool = False, all_info: bool = False) -> Union[list, dict]: ...
|
||||
def cookies(self, as_dict: bool = False, all_info: bool = False) -> Union[list, dict]: ...
|
||||
|
||||
@abstractmethod
|
||||
def get(self, url: str, show_errmsg: bool = False, retry: int = None, interval: float = None): ...
|
||||
|
||||
def _ele(self,
|
||||
loc_or_ele,
|
||||
locator,
|
||||
timeout: float = None,
|
||||
index: Optional[int] = 1,
|
||||
raise_err: bool = None,
|
||||
method: str = None): ...
|
||||
|
||||
@abstractmethod
|
||||
def _find_elements(self,
|
||||
loc_or_ele,
|
||||
timeout: float = None,
|
||||
index: Optional[int] = 1,
|
||||
raise_err: bool = None): ...
|
||||
|
@ -49,35 +49,44 @@ class Browser(object):
|
||||
self.id = browser_id
|
||||
self._frames = {}
|
||||
self._drivers = {}
|
||||
# self._drivers = {t: Driver(t, 'page', address) for t in self.tabs}
|
||||
self._all_drivers = {}
|
||||
self._connected = False
|
||||
|
||||
self._process_id = None
|
||||
r = self.run_cdp('SystemInfo.getProcessInfo')
|
||||
for i in r.get('processInfo', []):
|
||||
if i['type'] == 'browser':
|
||||
self._process_id = i['id']
|
||||
break
|
||||
try:
|
||||
r = self.run_cdp('SystemInfo.getProcessInfo')
|
||||
for i in r.get('processInfo', []):
|
||||
if i['type'] == 'browser':
|
||||
self._process_id = i['id']
|
||||
break
|
||||
except:
|
||||
pass
|
||||
|
||||
self.run_cdp('Target.setDiscoverTargets', discover=True)
|
||||
self._driver.set_callback('Target.targetDestroyed', self._onTargetDestroyed)
|
||||
self._driver.set_callback('Target.targetCreated', self._onTargetCreated)
|
||||
|
||||
def _get_driver(self, tab_id, owner=None):
|
||||
"""获取对应tab id的Driver
|
||||
"""新建并返回指定tab id的Driver
|
||||
:param tab_id: 标签页id
|
||||
:param owner: 使用该驱动的对象
|
||||
:return: Driver对象
|
||||
"""
|
||||
return self._drivers.pop(tab_id, Driver(tab_id, 'page', self.address, owner))
|
||||
d = self._drivers.pop(tab_id, Driver(tab_id, 'page', self.address))
|
||||
d.owner = owner
|
||||
self._all_drivers.setdefault(tab_id, set()).add(d)
|
||||
return d
|
||||
|
||||
def _onTargetCreated(self, **kwargs):
|
||||
"""标签页创建时执行"""
|
||||
if (kwargs['targetInfo']['type'] in ('page', 'webview')
|
||||
and kwargs['targetInfo']['targetId'] not in self._all_drivers
|
||||
and not kwargs['targetInfo']['url'].startswith('devtools://')):
|
||||
try:
|
||||
self._drivers[kwargs['targetInfo']['targetId']] = Driver(kwargs['targetInfo']['targetId'],
|
||||
'page', self.address)
|
||||
tab_id = kwargs['targetInfo']['targetId']
|
||||
d = Driver(tab_id, 'page', self.address)
|
||||
self._drivers[tab_id] = d
|
||||
self._all_drivers.setdefault(tab_id, set()).add(d)
|
||||
except WebSocketBadStatusException:
|
||||
pass
|
||||
|
||||
@ -88,7 +97,10 @@ class Browser(object):
|
||||
self._dl_mgr.clear_tab_info(tab_id)
|
||||
for key in [k for k, i in self._frames.items() if i == tab_id]:
|
||||
self._frames.pop(key, None)
|
||||
for d in self._all_drivers.get(tab_id, tuple()):
|
||||
d.stop()
|
||||
self._drivers.pop(tab_id, None)
|
||||
self._all_drivers.pop(tab_id, None)
|
||||
|
||||
def connect_to_page(self):
|
||||
"""执行与page相关的逻辑"""
|
||||
@ -153,7 +165,16 @@ class Browser(object):
|
||||
:param tab_id: 标签页id
|
||||
:return: None
|
||||
"""
|
||||
self.run_cdp('Target.closeTarget', targetId=tab_id, _ignore=PageDisconnectedError)
|
||||
self._onTargetDestroyed(targetId=tab_id)
|
||||
self.driver.run('Target.closeTarget', targetId=tab_id)
|
||||
|
||||
def stop_driver(self, driver):
|
||||
"""停止一个Driver
|
||||
:param driver: Driver对象
|
||||
:return: None
|
||||
"""
|
||||
driver.stop()
|
||||
self._all_drivers.get(driver.id, set()).discard(driver)
|
||||
|
||||
def activate_tab(self, tab_id):
|
||||
"""使标签页变为活动状态
|
||||
@ -175,10 +196,15 @@ class Browser(object):
|
||||
:param force: 是否立刻强制终止进程
|
||||
:return: None
|
||||
"""
|
||||
for tab in self._all_drivers.values():
|
||||
for driver in tab:
|
||||
driver.stop()
|
||||
try:
|
||||
self.run_cdp('Browser.close')
|
||||
except PageDisconnectedError:
|
||||
self.driver.stop()
|
||||
return
|
||||
self.driver.stop()
|
||||
|
||||
if force:
|
||||
ip, port = self.address.split(':')
|
||||
|
@ -5,7 +5,7 @@
|
||||
@Copyright: (c) 2024 by g1879, Inc. All Rights Reserved.
|
||||
@License : BSD 3-Clause.
|
||||
"""
|
||||
from typing import List, Optional, Union
|
||||
from typing import List, Optional, Union, Set, Dict
|
||||
|
||||
from .driver import BrowserDriver, Driver
|
||||
from .._pages.chromium_page import ChromiumPage
|
||||
@ -19,7 +19,8 @@ class Browser(object):
|
||||
id: str = ...
|
||||
address: str = ...
|
||||
_frames: dict = ...
|
||||
_drivers: dict = ...
|
||||
_drivers: Dict[str, Driver] = ...
|
||||
_all_drivers: Dict[str, Set[Driver]] = ...
|
||||
_process_id: Optional[int] = ...
|
||||
_dl_mgr: DownloadManager = ...
|
||||
_connected: bool = ...
|
||||
@ -49,6 +50,8 @@ class Browser(object):
|
||||
|
||||
def close_tab(self, tab_id: str) -> None: ...
|
||||
|
||||
def stop_driver(self, driver: Driver) -> None: ...
|
||||
|
||||
def activate_tab(self, tab_id: str) -> None: ...
|
||||
|
||||
def get_window_bounds(self, tab_id: str = None) -> dict: ...
|
||||
|
@ -189,8 +189,9 @@ class Driver(object):
|
||||
timeout = kwargs.pop('_timeout', 30)
|
||||
result = self._send({'method': _method, 'params': kwargs}, timeout=timeout)
|
||||
if 'result' not in result and 'error' in result:
|
||||
kwargs['_timeout'] = timeout
|
||||
return {'error': result['error']['message'], 'type': result.get('type', 'call_method_error'),
|
||||
'method': _method, 'args': kwargs, 'timeout': timeout}
|
||||
'method': _method, 'args': kwargs}
|
||||
else:
|
||||
return result['result']
|
||||
|
||||
|
@ -7,12 +7,8 @@
|
||||
"""
|
||||
from pathlib import Path
|
||||
from re import search
|
||||
from shutil import rmtree
|
||||
from tempfile import gettempdir, TemporaryDirectory
|
||||
from threading import Lock
|
||||
|
||||
from .options_manage import OptionsManager
|
||||
from .._functions.tools import port_is_using, clean_folder
|
||||
|
||||
|
||||
class ChromiumOptions(object):
|
||||
@ -30,7 +26,7 @@ class ChromiumOptions(object):
|
||||
if read_file is not False:
|
||||
ini_path = str(ini_path) if ini_path else None
|
||||
om = OptionsManager(ini_path)
|
||||
self.ini_path = om.ini_path
|
||||
self.ini_path = str(Path(om.ini_path).absolute())
|
||||
|
||||
options = om.chromium_options
|
||||
self._download_path = om.paths.get('download_path', None) or None
|
||||
@ -60,14 +56,10 @@ class ChromiumOptions(object):
|
||||
|
||||
timeouts = om.timeouts
|
||||
self._timeouts = {'base': timeouts['base'],
|
||||
'pageLoad': timeouts['page_load'],
|
||||
'page_load': timeouts['page_load'],
|
||||
'script': timeouts['script']}
|
||||
|
||||
self._auto_port = options.get('auto_port', False)
|
||||
if self._auto_port:
|
||||
port, path = PortFinder().get_port()
|
||||
self._address = f'127.0.0.1:{port}'
|
||||
self.set_argument('--user-data-dir', path)
|
||||
|
||||
others = om.others
|
||||
self._retry_times = others.get('retry_times', 3)
|
||||
@ -83,7 +75,7 @@ class ChromiumOptions(object):
|
||||
self._extensions = []
|
||||
self._prefs = {}
|
||||
self._flags = {}
|
||||
self._timeouts = {'base': 10, 'pageLoad': 30, 'script': 30}
|
||||
self._timeouts = {'base': 10, 'page_load': 30, 'script': 30}
|
||||
self._address = '127.0.0.1:9222'
|
||||
self._load_mode = 'normal'
|
||||
self._proxy = None
|
||||
@ -170,7 +162,7 @@ class ChromiumOptions(object):
|
||||
|
||||
@property
|
||||
def is_auto_port(self):
|
||||
"""返回是否使用自动端口和用户文件"""
|
||||
"""返回是否使用自动端口和用户文件,如指定范围则返回范围tuple"""
|
||||
return self._auto_port
|
||||
|
||||
@property
|
||||
@ -286,18 +278,18 @@ class ChromiumOptions(object):
|
||||
self.clear_file_flags = True
|
||||
return self
|
||||
|
||||
def set_timeouts(self, base=None, pageLoad=None, script=None, implicit=None):
|
||||
def set_timeouts(self, base=None, page_load=None, script=None, implicit=None):
|
||||
"""设置超时时间,单位为秒
|
||||
:param base: 默认超时时间
|
||||
:param pageLoad: 页面加载超时时间
|
||||
:param page_load: 页面加载超时时间
|
||||
:param script: 脚本运行超时时间
|
||||
:return: 当前对象
|
||||
"""
|
||||
base = base if base is not None else implicit
|
||||
if base is not None:
|
||||
self._timeouts['base'] = base
|
||||
if pageLoad is not None:
|
||||
self._timeouts['pageLoad'] = pageLoad
|
||||
if page_load is not None:
|
||||
self._timeouts['page_load'] = page_load
|
||||
if script is not None:
|
||||
self._timeouts['script'] = script
|
||||
|
||||
@ -448,7 +440,6 @@ class ChromiumOptions(object):
|
||||
:return: 当前对象
|
||||
"""
|
||||
self._browser_path = str(path)
|
||||
self._auto_port = False
|
||||
return self
|
||||
|
||||
def set_download_path(self, path):
|
||||
@ -494,14 +485,15 @@ class ChromiumOptions(object):
|
||||
self._system_user_path = on_off
|
||||
return self
|
||||
|
||||
def auto_port(self, on_off=True, tmp_path=None):
|
||||
def auto_port(self, on_off=True, tmp_path=None, scope=None):
|
||||
"""自动获取可用端口
|
||||
:param on_off: 是否开启自动获取端口号
|
||||
:param tmp_path: 临时文件保存路径,为None时保存到系统临时文件夹,on_off为False时此参数无效
|
||||
:param scope: 指定端口范围,不含最后的数字,为None则使用[9600-19600)
|
||||
:return: 当前对象
|
||||
"""
|
||||
if on_off:
|
||||
self._auto_port = True
|
||||
self._auto_port = scope if scope else True
|
||||
if tmp_path:
|
||||
self._tmp_path = str(tmp_path)
|
||||
else:
|
||||
@ -553,7 +545,7 @@ class ChromiumOptions(object):
|
||||
om.set_item('paths', 'tmp_path', self._tmp_path or '')
|
||||
# 设置timeout
|
||||
om.set_item('timeouts', 'base', self._timeouts['base'])
|
||||
om.set_item('timeouts', 'page_load', self._timeouts['pageLoad'])
|
||||
om.set_item('timeouts', 'page_load', self._timeouts['page_load'])
|
||||
om.set_item('timeouts', 'script', self._timeouts['script'])
|
||||
# 设置重试
|
||||
om.set_item('others', 'retry_times', self.retry_times)
|
||||
@ -619,41 +611,3 @@ class ChromiumOptions(object):
|
||||
"""
|
||||
on_off = None if on_off else False
|
||||
return self.set_argument('--mute-audio', on_off)
|
||||
|
||||
|
||||
class PortFinder(object):
|
||||
used_port = {}
|
||||
lock = Lock()
|
||||
|
||||
def __init__(self, path=None):
|
||||
"""
|
||||
:param path: 临时文件保存路径,为None时使用系统临时文件夹
|
||||
"""
|
||||
tmp = Path(path) if path else Path(gettempdir()) / 'DrissionPage'
|
||||
self.tmp_dir = tmp / 'UserTempFolder'
|
||||
self.tmp_dir.mkdir(parents=True, exist_ok=True)
|
||||
if not PortFinder.used_port:
|
||||
clean_folder(self.tmp_dir)
|
||||
|
||||
def get_port(self):
|
||||
"""查找一个可用端口
|
||||
:return: 可以使用的端口和用户文件夹路径组成的元组
|
||||
"""
|
||||
with PortFinder.lock:
|
||||
for i in range(9600, 19600):
|
||||
if i in PortFinder.used_port:
|
||||
continue
|
||||
elif port_is_using('127.0.0.1', i):
|
||||
PortFinder.used_port[i] = None
|
||||
continue
|
||||
path = TemporaryDirectory(dir=self.tmp_dir).name
|
||||
PortFinder.used_port[i] = path
|
||||
return i, path
|
||||
|
||||
for i in range(9600, 19600):
|
||||
if port_is_using('127.0.0.1', i):
|
||||
continue
|
||||
rmtree(PortFinder.used_port[i], ignore_errors=True)
|
||||
return i, TemporaryDirectory(dir=self.tmp_dir).name
|
||||
|
||||
raise OSError('未找到可用端口。')
|
||||
|
@ -6,8 +6,7 @@
|
||||
@License : BSD 3-Clause.
|
||||
"""
|
||||
from pathlib import Path
|
||||
from threading import Lock
|
||||
from typing import Union, Tuple, Any, Literal, Optional
|
||||
from typing import Union, Any, Literal, Optional, Tuple
|
||||
|
||||
|
||||
class ChromiumOptions(object):
|
||||
@ -82,7 +81,7 @@ class ChromiumOptions(object):
|
||||
def is_existing_only(self) -> bool: ...
|
||||
|
||||
@property
|
||||
def is_auto_port(self) -> bool: ...
|
||||
def is_auto_port(self) -> Union[bool, Tuple[int, int]]: ...
|
||||
|
||||
@property
|
||||
def retry_times(self) -> int: ...
|
||||
@ -110,7 +109,9 @@ class ChromiumOptions(object):
|
||||
|
||||
def clear_flags_in_file(self) -> ChromiumOptions: ...
|
||||
|
||||
def set_timeouts(self, base: float = None, pageLoad: float = None,
|
||||
def set_timeouts(self,
|
||||
base: float = None,
|
||||
page_load: float = None,
|
||||
script: float = None) -> ChromiumOptions: ...
|
||||
|
||||
def set_user(self, user: str = 'Default') -> ChromiumOptions: ...
|
||||
@ -153,21 +154,13 @@ class ChromiumOptions(object):
|
||||
|
||||
def use_system_user_path(self, on_off: bool = True) -> ChromiumOptions: ...
|
||||
|
||||
def auto_port(self, on_off: bool = True, tmp_path: Union[str, Path] = None) -> ChromiumOptions: ...
|
||||
def auto_port(self,
|
||||
on_off: bool = True,
|
||||
tmp_path: Union[str, Path] = None,
|
||||
scope: Tuple[int, int] = None) -> ChromiumOptions: ...
|
||||
|
||||
def existing_only(self, on_off: bool = True) -> ChromiumOptions: ...
|
||||
|
||||
def save(self, path: Union[str, Path] = None) -> str: ...
|
||||
|
||||
def save_to_default(self) -> str: ...
|
||||
|
||||
|
||||
class PortFinder(object):
|
||||
used_port: dict = ...
|
||||
lock: Lock = ...
|
||||
tmp_dir: Path = ...
|
||||
|
||||
def __init__(self, path: Union[str, Path] = None): ...
|
||||
|
||||
@staticmethod
|
||||
def get_port() -> Tuple[int, str]: ...
|
||||
|
@ -5,7 +5,7 @@ tmp_path =
|
||||
[chromium_options]
|
||||
address = 127.0.0.1:9222
|
||||
browser_path = chrome
|
||||
arguments = ['--no-default-browser-check', '--disable-suggestions-ui', '--no-first-run', '--disable-infobars', '--disable-popup-blocking', '--hide-crash-restore-bubble']
|
||||
arguments = ['--no-default-browser-check', '--disable-suggestions-ui', '--no-first-run', '--disable-infobars', '--disable-popup-blocking', '--hide-crash-restore-bubble', '--disable-features=PrivacySandboxSettings4']
|
||||
extensions = []
|
||||
prefs = {'profile.default_content_settings.popups': 0, 'profile.default_content_setting_values': {'notifications': 2}}
|
||||
flags = {}
|
||||
|
@ -8,6 +8,7 @@
|
||||
from configparser import RawConfigParser, NoSectionError, NoOptionError
|
||||
from pathlib import Path
|
||||
from pprint import pprint
|
||||
from time import sleep
|
||||
|
||||
|
||||
class OptionsManager(object):
|
||||
@ -28,8 +29,9 @@ class OptionsManager(object):
|
||||
self.ini_path = str(path)
|
||||
|
||||
if not Path(self.ini_path).exists():
|
||||
input('\nini文件不存在。\n如果是打包使用,请查看打包注意事项\nhttps://g1879.gitee.io/drission'
|
||||
'pagedocs/advance/packaging/')
|
||||
print('\nini文件不存在。\n如果是打包使用,请查看打包注意事项\n'
|
||||
'https://g1879.gitee.io/drissionpagedocs/advance/packaging/')
|
||||
sleep(10)
|
||||
self._conf = RawConfigParser()
|
||||
self._conf.read(self.ini_path, encoding='utf-8')
|
||||
|
||||
|
@ -12,11 +12,6 @@ from typing import Any
|
||||
class OptionsManager(object):
|
||||
ini_path: str = ...
|
||||
_conf: RawConfigParser = ...
|
||||
paths: dict = ...
|
||||
chrome_options: dict = ...
|
||||
session_options: dict = ...
|
||||
timeouts: dict = ...
|
||||
proxies: dict = ...
|
||||
|
||||
def __init__(self, path: str = None): ...
|
||||
|
||||
|
@ -171,28 +171,27 @@ class SessionOptions(object):
|
||||
self._headers = {key.lower(): headers[key] for key in headers}
|
||||
return self
|
||||
|
||||
def set_a_header(self, attr, value):
|
||||
def set_a_header(self, name, value):
|
||||
"""设置headers中一个项
|
||||
:param attr: 设置名称
|
||||
:param name: 设置名称
|
||||
:param value: 设置值
|
||||
:return: 返回当前对象
|
||||
"""
|
||||
if self._headers is None:
|
||||
self._headers = {}
|
||||
|
||||
self._headers[attr.lower()] = value
|
||||
self._headers[name.lower()] = value
|
||||
return self
|
||||
|
||||
def remove_a_header(self, attr):
|
||||
def remove_a_header(self, name):
|
||||
"""从headers中删除一个设置
|
||||
:param attr: 要删除的设置
|
||||
:param name: 要删除的设置
|
||||
:return: 返回当前对象
|
||||
"""
|
||||
if self._headers is None:
|
||||
return self
|
||||
|
||||
attr = attr.lower()
|
||||
self._headers.pop(attr, None)
|
||||
self._headers.pop(name.lower(), None)
|
||||
|
||||
return self
|
||||
|
||||
|
@ -51,9 +51,9 @@ class SessionOptions(object):
|
||||
|
||||
def set_headers(self, headers: Union[dict, None]) -> SessionOptions: ...
|
||||
|
||||
def set_a_header(self, attr: str, value: str) -> SessionOptions: ...
|
||||
def set_a_header(self, name: str, value: str) -> SessionOptions: ...
|
||||
|
||||
def remove_a_header(self, attr: str) -> SessionOptions: ...
|
||||
def remove_a_header(self, name: str) -> SessionOptions: ...
|
||||
|
||||
@property
|
||||
def cookies(self) -> list: ...
|
||||
|
@ -19,7 +19,7 @@ from .._base.base import DrissionElement, BaseElement
|
||||
from .._functions.keys import input_text_or_keys
|
||||
from .._functions.locator import get_loc
|
||||
from .._functions.settings import Settings
|
||||
from .._functions.web import make_absolute_link, get_ele_txt, format_html, is_js_func, offset_scroll
|
||||
from .._functions.web import make_absolute_link, get_ele_txt, format_html, is_js_func, offset_scroll, get_blob
|
||||
from .._units.clicker import Clicker
|
||||
from .._units.rect import ElementRect
|
||||
from .._units.scroller import ElementScroller
|
||||
@ -53,6 +53,7 @@ class ChromiumElement(DrissionElement):
|
||||
self._clicker = None
|
||||
self._tag = None
|
||||
self._wait = None
|
||||
self._type = 'ChromiumElement'
|
||||
|
||||
if node_id and obj_id and backend_id:
|
||||
self._node_id = node_id
|
||||
@ -77,17 +78,16 @@ class ChromiumElement(DrissionElement):
|
||||
self._doc_id = doc['objectId'] if doc else None
|
||||
|
||||
def __repr__(self):
|
||||
attrs = self.attrs
|
||||
attrs = [f"{attr}='{attrs[attr]}'" for attr in attrs]
|
||||
attrs = [f"{k}='{v}'" for k, v in self.attrs.items()]
|
||||
return f'<ChromiumElement {self.tag} {" ".join(attrs)}>'
|
||||
|
||||
def __call__(self, loc_or_str, index=1, timeout=None):
|
||||
def __call__(self, locator, index=1, timeout=None):
|
||||
"""在内部查找元素
|
||||
:param loc_or_str: 元素的定位信息,可以是loc元组,或查询字符串
|
||||
:param locator: 元素的定位信息,可以是loc元组,或查询字符串
|
||||
:param timeout: 超时时间(秒)
|
||||
:return: ChromiumElement对象或属性、文本
|
||||
"""
|
||||
return self.ele(loc_or_str, index=index, timeout=timeout)
|
||||
return self.ele(locator, index=index, timeout=timeout)
|
||||
|
||||
def __eq__(self, other):
|
||||
return self._backend_id == getattr(other, '_backend_id', None)
|
||||
@ -127,10 +127,9 @@ class ChromiumElement(DrissionElement):
|
||||
@property
|
||||
def raw_text(self):
|
||||
"""返回未格式化处理的元素内文本"""
|
||||
return self.prop('innerText')
|
||||
return self.property('innerText')
|
||||
|
||||
# -----------------d模式独有属性-------------------
|
||||
|
||||
@property
|
||||
def set(self):
|
||||
"""返回用于设置元素属性的对象"""
|
||||
@ -205,6 +204,29 @@ class ChromiumElement(DrissionElement):
|
||||
|
||||
return self._select
|
||||
|
||||
@property
|
||||
def value(self):
|
||||
return self.property('value')
|
||||
|
||||
# -----即将废弃开始--------
|
||||
@property
|
||||
def location(self):
|
||||
"""返回元素左上角的绝对坐标"""
|
||||
return self.rect.location
|
||||
|
||||
@property
|
||||
def size(self):
|
||||
"""返回元素宽和高组成的元组"""
|
||||
return self.rect.size
|
||||
|
||||
def prop(self, prop):
|
||||
return self.property(prop)
|
||||
|
||||
def get_src(self, timeout=None, base64_to_bytes=True):
|
||||
return self.src(timeout=timeout, base64_to_bytes=base64_to_bytes)
|
||||
|
||||
# -----即将废弃结束--------
|
||||
|
||||
def check(self, uncheck=False, by_js=False):
|
||||
"""选中或取消选中当前元素
|
||||
:param uncheck: 是否取消选中
|
||||
@ -234,104 +256,104 @@ class ChromiumElement(DrissionElement):
|
||||
"""
|
||||
return super().parent(level_or_loc, index)
|
||||
|
||||
def child(self, filter_loc='', index=1, timeout=None, ele_only=True):
|
||||
def child(self, locator='', index=1, timeout=None, ele_only=True):
|
||||
"""返回当前元素的一个符合条件的直接子元素,可用查询语法筛选,可指定返回筛选结果的第几个
|
||||
:param filter_loc: 用于筛选的查询语法
|
||||
:param locator: 用于筛选的查询语法
|
||||
:param index: 第几个查询结果,1开始
|
||||
:param timeout: 查找节点的超时时间(秒)
|
||||
:param ele_only: 是否只获取元素,为False时把文本、注释节点也纳入
|
||||
:return: 直接子元素或节点文本
|
||||
"""
|
||||
return super().child(filter_loc, index, timeout, ele_only=ele_only)
|
||||
return super().child(locator, index, timeout, ele_only=ele_only)
|
||||
|
||||
def prev(self, filter_loc='', index=1, timeout=None, ele_only=True):
|
||||
def prev(self, locator='', index=1, timeout=None, ele_only=True):
|
||||
"""返回当前元素前面一个符合条件的同级元素,可用查询语法筛选,可指定返回筛选结果的第几个
|
||||
:param filter_loc: 用于筛选的查询语法
|
||||
:param locator: 用于筛选的查询语法
|
||||
:param index: 前面第几个查询结果,1开始
|
||||
:param timeout: 查找节点的超时时间(秒)
|
||||
:param ele_only: 是否只获取元素,为False时把文本、注释节点也纳入
|
||||
:return: 兄弟元素或节点文本
|
||||
"""
|
||||
return super().prev(filter_loc, index, timeout, ele_only=ele_only)
|
||||
return super().prev(locator, index, timeout, ele_only=ele_only)
|
||||
|
||||
def next(self, filter_loc='', index=1, timeout=None, ele_only=True):
|
||||
def next(self, locator='', index=1, timeout=None, ele_only=True):
|
||||
"""返回当前元素后面一个符合条件的同级元素,可用查询语法筛选,可指定返回筛选结果的第几个
|
||||
:param filter_loc: 用于筛选的查询语法
|
||||
:param locator: 用于筛选的查询语法
|
||||
:param index: 第几个查询结果,1开始
|
||||
:param timeout: 查找节点的超时时间(秒)
|
||||
:param ele_only: 是否只获取元素,为False时把文本、注释节点也纳入
|
||||
:return: 兄弟元素或节点文本
|
||||
"""
|
||||
return super().next(filter_loc, index, timeout, ele_only=ele_only)
|
||||
return super().next(locator, index, timeout, ele_only=ele_only)
|
||||
|
||||
def before(self, filter_loc='', index=1, timeout=None, ele_only=True):
|
||||
def before(self, locator='', index=1, timeout=None, ele_only=True):
|
||||
"""返回文档中当前元素前面符合条件的一个元素,可用查询语法筛选,可指定返回筛选结果的第几个
|
||||
查找范围不限同级元素,而是整个DOM文档
|
||||
:param filter_loc: 用于筛选的查询语法
|
||||
:param locator: 用于筛选的查询语法
|
||||
:param index: 前面第几个查询结果,1开始
|
||||
:param timeout: 查找节点的超时时间(秒)
|
||||
:param ele_only: 是否只获取元素,为False时把文本、注释节点也纳入
|
||||
:return: 本元素前面的某个元素或节点
|
||||
"""
|
||||
return super().before(filter_loc, index, timeout, ele_only=ele_only)
|
||||
return super().before(locator, index, timeout, ele_only=ele_only)
|
||||
|
||||
def after(self, filter_loc='', index=1, timeout=None, ele_only=True):
|
||||
def after(self, locator='', index=1, timeout=None, ele_only=True):
|
||||
"""返回文档中此当前元素后面符合条件的一个元素,可用查询语法筛选,可指定返回筛选结果的第几个
|
||||
查找范围不限同级元素,而是整个DOM文档
|
||||
:param filter_loc: 用于筛选的查询语法
|
||||
:param locator: 用于筛选的查询语法
|
||||
:param index: 第几个查询结果,1开始
|
||||
:param timeout: 查找节点的超时时间(秒)
|
||||
:param ele_only: 是否只获取元素,为False时把文本、注释节点也纳入
|
||||
:return: 本元素后面的某个元素或节点
|
||||
"""
|
||||
return super().after(filter_loc, index, timeout, ele_only=ele_only)
|
||||
return super().after(locator, index, timeout, ele_only=ele_only)
|
||||
|
||||
def children(self, filter_loc='', timeout=None, ele_only=True):
|
||||
def children(self, locator='', timeout=None, ele_only=True):
|
||||
"""返回当前元素符合条件的直接子元素或节点组成的列表,可用查询语法筛选
|
||||
:param filter_loc: 用于筛选的查询语法
|
||||
:param locator: 用于筛选的查询语法
|
||||
:param timeout: 查找节点的超时时间(秒)
|
||||
:param ele_only: 是否只获取元素,为False时把文本、注释节点也纳入
|
||||
:return: 直接子元素或节点文本组成的列表
|
||||
"""
|
||||
return super().children(filter_loc, timeout, ele_only=ele_only)
|
||||
return super().children(locator, timeout, ele_only=ele_only)
|
||||
|
||||
def prevs(self, filter_loc='', timeout=None, ele_only=True):
|
||||
def prevs(self, locator='', timeout=None, ele_only=True):
|
||||
"""返回当前元素前面符合条件的同级元素或节点组成的列表,可用查询语法筛选
|
||||
:param filter_loc: 用于筛选的查询语法
|
||||
:param locator: 用于筛选的查询语法
|
||||
:param timeout: 查找节点的超时时间(秒)
|
||||
:param ele_only: 是否只获取元素,为False时把文本、注释节点也纳入
|
||||
:return: 兄弟元素或节点文本组成的列表
|
||||
"""
|
||||
return super().prevs(filter_loc, timeout, ele_only=ele_only)
|
||||
return super().prevs(locator, timeout, ele_only=ele_only)
|
||||
|
||||
def nexts(self, filter_loc='', timeout=None, ele_only=True):
|
||||
def nexts(self, locator='', timeout=None, ele_only=True):
|
||||
"""返回当前元素后面符合条件的同级元素或节点组成的列表,可用查询语法筛选
|
||||
:param filter_loc: 用于筛选的查询语法
|
||||
:param locator: 用于筛选的查询语法
|
||||
:param timeout: 查找节点的超时时间(秒)
|
||||
:param ele_only: 是否只获取元素,为False时把文本、注释节点也纳入
|
||||
:return: 兄弟元素或节点文本组成的列表
|
||||
"""
|
||||
return super().nexts(filter_loc, timeout, ele_only=ele_only)
|
||||
return super().nexts(locator, timeout, ele_only=ele_only)
|
||||
|
||||
def befores(self, filter_loc='', timeout=None, ele_only=True):
|
||||
def befores(self, locator='', timeout=None, ele_only=True):
|
||||
"""返回文档中当前元素前面符合条件的元素或节点组成的列表,可用查询语法筛选
|
||||
查找范围不限同级元素,而是整个DOM文档
|
||||
:param filter_loc: 用于筛选的查询语法
|
||||
:param locator: 用于筛选的查询语法
|
||||
:param timeout: 查找节点的超时时间(秒)
|
||||
:param ele_only: 是否只获取元素,为False时把文本、注释节点也纳入
|
||||
:return: 本元素前面的元素或节点组成的列表
|
||||
"""
|
||||
return super().befores(filter_loc, timeout, ele_only=ele_only)
|
||||
return super().befores(locator, timeout, ele_only=ele_only)
|
||||
|
||||
def afters(self, filter_loc='', timeout=None, ele_only=True):
|
||||
def afters(self, locator='', timeout=None, ele_only=True):
|
||||
"""返回文档中当前元素后面符合条件的元素或节点组成的列表,可用查询语法筛选
|
||||
查找范围不限同级元素,而是整个DOM文档
|
||||
:param filter_loc: 用于筛选的查询语法
|
||||
:param locator: 用于筛选的查询语法
|
||||
:param timeout: 查找节点的超时时间(秒)
|
||||
:param ele_only: 是否只获取元素,为False时把文本、注释节点也纳入
|
||||
:return: 本元素后面的元素或节点组成的列表
|
||||
"""
|
||||
return super().afters(filter_loc, timeout, ele_only=ele_only)
|
||||
return super().afters(locator, timeout, ele_only=ele_only)
|
||||
|
||||
def attr(self, attr):
|
||||
"""返回一个attribute属性值
|
||||
@ -344,10 +366,10 @@ class ChromiumElement(DrissionElement):
|
||||
if not link or link.lower().startswith(('javascript:', 'mailto:')):
|
||||
return link
|
||||
else:
|
||||
return make_absolute_link(link, self.prop('baseURI'))
|
||||
return make_absolute_link(link, self.property('baseURI'))
|
||||
|
||||
elif attr == 'src':
|
||||
return make_absolute_link(attrs.get('src', None), self.prop('baseURI'))
|
||||
return make_absolute_link(attrs.get('src', None), self.property('baseURI'))
|
||||
|
||||
elif attr == 'text':
|
||||
return self.text
|
||||
@ -364,20 +386,20 @@ class ChromiumElement(DrissionElement):
|
||||
else:
|
||||
return attrs.get(attr, None)
|
||||
|
||||
def remove_attr(self, attr):
|
||||
def remove_attr(self, name):
|
||||
"""删除元素一个attribute属性
|
||||
:param attr: 属性名
|
||||
:param name: 属性名
|
||||
:return: None
|
||||
"""
|
||||
self.run_js(f'this.removeAttribute("{attr}");')
|
||||
self.run_js(f'this.removeAttribute("{name}");')
|
||||
|
||||
def prop(self, prop):
|
||||
def property(self, name):
|
||||
"""获取一个property属性值
|
||||
:param prop: 属性名
|
||||
:param name: 属性名
|
||||
:return: 属性值文本
|
||||
"""
|
||||
try:
|
||||
value = self.run_js(f'return this.{prop};')
|
||||
value = self.run_js(f'return this.{name};')
|
||||
return format_html(value) if isinstance(value, str) else value
|
||||
except:
|
||||
return None
|
||||
@ -401,60 +423,60 @@ class ChromiumElement(DrissionElement):
|
||||
"""
|
||||
run_js(self, script, as_expr, 0, args)
|
||||
|
||||
def ele(self, loc_or_str, index=1, timeout=None):
|
||||
def ele(self, locator, index=1, timeout=None):
|
||||
"""返回当前元素下级符合条件的一个元素、属性或节点文本
|
||||
:param loc_or_str: 元素的定位信息,可以是loc元组,或查询字符串
|
||||
:param locator: 元素的定位信息,可以是loc元组,或查询字符串
|
||||
:param index: 获取第几个元素,从1开始,可传入负数获取倒数第几个
|
||||
:param timeout: 查找元素超时时间(秒),默认与元素所在页面等待时间一致
|
||||
:return: ChromiumElement对象或属性、文本
|
||||
"""
|
||||
return self._ele(loc_or_str, timeout, index=index, method='ele()')
|
||||
return self._ele(locator, timeout, index=index, method='ele()')
|
||||
|
||||
def eles(self, loc_or_str, timeout=None):
|
||||
def eles(self, locator, timeout=None):
|
||||
"""返回当前元素下级所有符合条件的子元素、属性或节点文本
|
||||
:param loc_or_str: 元素的定位信息,可以是loc元组,或查询字符串
|
||||
:param locator: 元素的定位信息,可以是loc元组,或查询字符串
|
||||
:param timeout: 查找元素超时时间(秒),默认与元素所在页面等待时间一致
|
||||
:return: ChromiumElement对象或属性、文本组成的列表
|
||||
"""
|
||||
return self._ele(loc_or_str, timeout=timeout, index=None)
|
||||
return self._ele(locator, timeout=timeout, index=None)
|
||||
|
||||
def s_ele(self, loc_or_str=None, index=1):
|
||||
def s_ele(self, locator=None, index=1):
|
||||
"""查找一个符合条件的元素,以SessionElement形式返回
|
||||
:param loc_or_str: 元素的定位信息,可以是loc元组,或查询字符串
|
||||
:param locator: 元素的定位信息,可以是loc元组,或查询字符串
|
||||
:param index: 获取第几个,从1开始,可传入负数获取倒数第几个
|
||||
:return: SessionElement对象或属性、文本
|
||||
"""
|
||||
if self.tag in __FRAME_ELEMENT__:
|
||||
r = make_session_ele(self.inner_html, loc_or_str, index=index)
|
||||
r = make_session_ele(self.inner_html, locator, index=index)
|
||||
else:
|
||||
r = make_session_ele(self, loc_or_str, index=index)
|
||||
r = make_session_ele(self, locator, index=index)
|
||||
if isinstance(r, NoneElement):
|
||||
if Settings.raise_when_ele_not_found:
|
||||
raise ElementNotFoundError(None, 's_ele()', {'loc_or_str': loc_or_str})
|
||||
raise ElementNotFoundError(None, 's_ele()', {'locator': locator})
|
||||
else:
|
||||
r.method = 's_ele()'
|
||||
r.args = {'loc_or_str': loc_or_str}
|
||||
r.args = {'locator': locator}
|
||||
return r
|
||||
|
||||
def s_eles(self, loc_or_str=None):
|
||||
def s_eles(self, locator=None):
|
||||
"""查找所有符合条件的元素,以SessionElement列表形式返回
|
||||
:param loc_or_str: 定位符
|
||||
:param locator: 定位符
|
||||
:return: SessionElement或属性、文本组成的列表
|
||||
"""
|
||||
if self.tag in __FRAME_ELEMENT__:
|
||||
return make_session_ele(self.inner_html, loc_or_str, index=None)
|
||||
return make_session_ele(self, loc_or_str, index=None)
|
||||
return make_session_ele(self.inner_html, locator, index=None)
|
||||
return make_session_ele(self, locator, index=None)
|
||||
|
||||
def _find_elements(self, loc_or_str, timeout=None, index=1, relative=False, raise_err=None):
|
||||
def _find_elements(self, locator, timeout=None, index=1, relative=False, raise_err=None):
|
||||
"""返回当前元素下级符合条件的子元素、属性或节点文本,默认返回第一个
|
||||
:param loc_or_str: 元素的定位信息,可以是loc元组,或查询字符串
|
||||
:param locator: 元素的定位信息,可以是loc元组,或查询字符串
|
||||
:param timeout: 查找元素超时时间(秒)
|
||||
:param index: 第几个结果,从1开始,可传入负数获取倒数第几个,为None返回所有
|
||||
:param relative: WebPage用的表示是否相对定位的参数
|
||||
:param raise_err: 找不到元素是是否抛出异常,为None时根据全局设置
|
||||
:return: ChromiumElement对象或文本、属性或其组成的列表
|
||||
"""
|
||||
return find_in_chromium_ele(self, loc_or_str, index, timeout, relative=relative)
|
||||
return find_in_chromium_ele(self, locator, index, timeout, relative=relative)
|
||||
|
||||
def style(self, style, pseudo_ele=''):
|
||||
"""返回元素样式属性值,可获取伪元素属性值
|
||||
@ -466,7 +488,7 @@ class ChromiumElement(DrissionElement):
|
||||
pseudo_ele = f', "{pseudo_ele}"' if pseudo_ele.startswith(':') else f', "::{pseudo_ele}"'
|
||||
return self.run_js(f'return window.getComputedStyle(this{pseudo_ele}).getPropertyValue("{style}");')
|
||||
|
||||
def get_src(self, timeout=None, base64_to_bytes=True):
|
||||
def src(self, timeout=None, base64_to_bytes=True):
|
||||
"""返回元素src资源,base64的可转为bytes返回,其它返回str
|
||||
:param timeout: 等待资源加载的超时时间(秒)
|
||||
:param base64_to_bytes: 为True时,如果是base64数据,转换为bytes格式
|
||||
@ -495,29 +517,12 @@ class ChromiumElement(DrissionElement):
|
||||
end_time = perf_counter() + timeout
|
||||
while perf_counter() < end_time:
|
||||
if is_blob:
|
||||
js = """
|
||||
function fetchData(url) {
|
||||
return new Promise((resolve, reject) => {
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.responseType = 'blob';
|
||||
xhr.onload = function() {
|
||||
var reader = new FileReader();
|
||||
reader.onloadend = function() {resolve(reader.result);}
|
||||
reader.readAsDataURL(xhr.response);
|
||||
};
|
||||
xhr.open('GET', url, true);
|
||||
xhr.send();
|
||||
});
|
||||
}
|
||||
"""
|
||||
try:
|
||||
result = self.page.run_js(js, src)
|
||||
result = get_blob(self.page, src, base64_to_bytes)
|
||||
if result:
|
||||
break
|
||||
except:
|
||||
continue
|
||||
|
||||
else:
|
||||
src = self.prop('currentSrc')
|
||||
src = self.property('currentSrc')
|
||||
if not src:
|
||||
continue
|
||||
|
||||
@ -533,19 +538,14 @@ class ChromiumElement(DrissionElement):
|
||||
if not result:
|
||||
return None
|
||||
|
||||
if is_blob:
|
||||
if base64_to_bytes:
|
||||
from base64 import b64decode
|
||||
return b64decode(result.split(',', 1)[-1])
|
||||
else:
|
||||
return result
|
||||
elif is_blob:
|
||||
return result
|
||||
|
||||
elif result['base64Encoded'] and base64_to_bytes:
|
||||
from base64 import b64decode
|
||||
return b64decode(result['content'])
|
||||
else:
|
||||
if result['base64Encoded'] and base64_to_bytes:
|
||||
from base64 import b64decode
|
||||
return b64decode(result['content'])
|
||||
else:
|
||||
return result['content']
|
||||
return result['content']
|
||||
|
||||
def save(self, path=None, name=None, timeout=None):
|
||||
"""保存图片或其它有src属性的元素的资源
|
||||
@ -554,7 +554,7 @@ class ChromiumElement(DrissionElement):
|
||||
:param timeout: 等待资源加载的超时时间(秒)
|
||||
:return: 返回保存路径
|
||||
"""
|
||||
data = self.get_src(timeout=timeout)
|
||||
data = self.src(timeout=timeout)
|
||||
if not data:
|
||||
raise NoResourceError
|
||||
|
||||
@ -564,7 +564,7 @@ class ChromiumElement(DrissionElement):
|
||||
if src.lower().startswith('data:image'):
|
||||
r = search(r'data:image/(.*?);base64,', src)
|
||||
name = f'img.{r.group(1)}' if r else None
|
||||
name = name or basename(self.prop('currentSrc'))
|
||||
name = name or basename(self.property('currentSrc'))
|
||||
path = get_usable_path(f'{path}{sep}{name}').absolute()
|
||||
write_type = 'wb' if isinstance(data, bytes) else 'w'
|
||||
|
||||
@ -616,7 +616,7 @@ class ChromiumElement(DrissionElement):
|
||||
self.clear(True)
|
||||
if isinstance(vals, (list, tuple)):
|
||||
vals = ''.join([str(i) for i in vals])
|
||||
self.set.prop('value', str(vals))
|
||||
self.set.property('value', str(vals))
|
||||
self.run_js('this.dispatchEvent(new Event("change", {bubbles: true}));')
|
||||
return
|
||||
|
||||
@ -772,18 +772,6 @@ class ChromiumElement(DrissionElement):
|
||||
files = [str(Path(i).absolute()) for i in files]
|
||||
self.page.run_cdp('DOM.setFileInputFiles', files=files, backendNodeId=self._backend_id)
|
||||
|
||||
# -------------即将废弃-------------
|
||||
|
||||
@property
|
||||
def location(self):
|
||||
"""返回元素左上角的绝对坐标"""
|
||||
return self.rect.location
|
||||
|
||||
@property
|
||||
def size(self):
|
||||
"""返回元素宽和高组成的元组"""
|
||||
return self.rect.size
|
||||
|
||||
|
||||
class ShadowRoot(BaseElement):
|
||||
"""ShadowRoot是用于处理ShadowRoot的类,使用方法和ChromiumElement基本一致"""
|
||||
@ -805,19 +793,20 @@ class ShadowRoot(BaseElement):
|
||||
self._node_id = self._get_node_id(obj_id)
|
||||
self._backend_id = self._get_backend_id(self._node_id)
|
||||
self._states = None
|
||||
self._type = 'ShadowRoot'
|
||||
|
||||
def __repr__(self):
|
||||
return f'<ShadowRoot in {self.parent_ele}>'
|
||||
|
||||
def __call__(self, loc_or_str, index=1, timeout=None):
|
||||
def __call__(self, locator, index=1, timeout=None):
|
||||
"""在内部查找元素
|
||||
例:ele2 = ele1('@id=ele_id')
|
||||
:param loc_or_str: 元素的定位信息,可以是loc元组,或查询字符串
|
||||
:param locator: 元素的定位信息,可以是loc元组,或查询字符串
|
||||
:param index: 获取第几个,从1开始,可传入负数获取倒数第几个
|
||||
:param timeout: 超时时间(秒)
|
||||
:return: 元素对象或属性、文本
|
||||
"""
|
||||
return self.ele(loc_or_str, index=index, timeout=timeout)
|
||||
return self.ele(locator, index=index, timeout=timeout)
|
||||
|
||||
def __eq__(self, other):
|
||||
return self._backend_id == getattr(other, '_backend_id', None)
|
||||
@ -888,16 +877,16 @@ class ShadowRoot(BaseElement):
|
||||
|
||||
return self.parent_ele._ele(loc, timeout=0, relative=True, raise_err=False, method='parent()')
|
||||
|
||||
def child(self, filter_loc='', index=1):
|
||||
def child(self, locator='', index=1):
|
||||
"""返回直接子元素元素或节点组成的列表,可用查询语法筛选
|
||||
:param filter_loc: 用于筛选的查询语法
|
||||
:param locator: 用于筛选的查询语法
|
||||
:param index: 第几个查询结果,1开始
|
||||
:return: 直接子元素或节点文本组成的列表
|
||||
"""
|
||||
if not filter_loc:
|
||||
if not locator:
|
||||
loc = '*'
|
||||
else:
|
||||
loc = get_loc(filter_loc, True) # 把定位符转换为xpath
|
||||
loc = get_loc(locator, True) # 把定位符转换为xpath
|
||||
if loc[0] == 'css selector':
|
||||
raise ValueError('此css selector语法不受支持,请换成xpath。')
|
||||
loc = loc[1].lstrip('./')
|
||||
@ -908,17 +897,17 @@ class ShadowRoot(BaseElement):
|
||||
return ele
|
||||
|
||||
if Settings.raise_when_ele_not_found:
|
||||
raise ElementNotFoundError(None, 'child()', {'filter_loc': filter_loc, 'index': index})
|
||||
raise ElementNotFoundError(None, 'child()', {'locator': locator, 'index': index})
|
||||
else:
|
||||
return NoneElement(self.page, 'child()', {'filter_loc': filter_loc, 'index': index})
|
||||
return NoneElement(self.page, 'child()', {'locator': locator, 'index': index})
|
||||
|
||||
def next(self, filter_loc='', index=1):
|
||||
def next(self, locator='', index=1):
|
||||
"""返回当前元素后面一个符合条件的同级元素,可用查询语法筛选,可指定返回筛选结果的第几个
|
||||
:param filter_loc: 用于筛选的查询语法
|
||||
:param locator: 用于筛选的查询语法
|
||||
:param index: 第几个查询结果,1开始
|
||||
:return: ChromiumElement对象
|
||||
"""
|
||||
loc = get_loc(filter_loc, True)
|
||||
loc = get_loc(locator, True)
|
||||
if loc[0] == 'css selector':
|
||||
raise ValueError('此css selector语法不受支持,请换成xpath。')
|
||||
|
||||
@ -929,18 +918,18 @@ class ShadowRoot(BaseElement):
|
||||
return ele
|
||||
|
||||
if Settings.raise_when_ele_not_found:
|
||||
raise ElementNotFoundError(None, 'next()', {'filter_loc': filter_loc, 'index': index})
|
||||
raise ElementNotFoundError(None, 'next()', {'locator': locator, 'index': index})
|
||||
else:
|
||||
return NoneElement(self.page, 'next()', {'filter_loc': filter_loc, 'index': index})
|
||||
return NoneElement(self.page, 'next()', {'locator': locator, 'index': index})
|
||||
|
||||
def before(self, filter_loc='', index=1):
|
||||
def before(self, locator='', index=1):
|
||||
"""返回文档中当前元素前面符合条件的一个元素,可用查询语法筛选,可指定返回筛选结果的第几个
|
||||
查找范围不限同级元素,而是整个DOM文档
|
||||
:param filter_loc: 用于筛选的查询语法
|
||||
:param locator: 用于筛选的查询语法
|
||||
:param index: 前面第几个查询结果,1开始
|
||||
:return: 本元素前面的某个元素或节点
|
||||
"""
|
||||
loc = get_loc(filter_loc, True)
|
||||
loc = get_loc(locator, True)
|
||||
if loc[0] == 'css selector':
|
||||
raise ValueError('此css selector语法不受支持,请换成xpath。')
|
||||
|
||||
@ -951,34 +940,34 @@ class ShadowRoot(BaseElement):
|
||||
return ele
|
||||
|
||||
if Settings.raise_when_ele_not_found:
|
||||
raise ElementNotFoundError(None, 'before()', {'filter_loc': filter_loc, 'index': index})
|
||||
raise ElementNotFoundError(None, 'before()', {'locator': locator, 'index': index})
|
||||
else:
|
||||
return NoneElement(self.page, 'before()', {'filter_loc': filter_loc, 'index': index})
|
||||
return NoneElement(self.page, 'before()', {'locator': locator, 'index': index})
|
||||
|
||||
def after(self, filter_loc='', index=1):
|
||||
def after(self, locator='', index=1):
|
||||
"""返回文档中此当前元素后面符合条件的一个元素,可用查询语法筛选,可指定返回筛选结果的第几个
|
||||
查找范围不限同级元素,而是整个DOM文档
|
||||
:param filter_loc: 用于筛选的查询语法
|
||||
:param locator: 用于筛选的查询语法
|
||||
:param index: 后面第几个查询结果,1开始
|
||||
:return: 本元素后面的某个元素或节点
|
||||
"""
|
||||
nodes = self.afters(filter_loc=filter_loc)
|
||||
nodes = self.afters(locator=locator)
|
||||
if nodes:
|
||||
return nodes[index - 1]
|
||||
if Settings.raise_when_ele_not_found:
|
||||
raise ElementNotFoundError(None, 'after()', {'filter_loc': filter_loc, 'index': index})
|
||||
raise ElementNotFoundError(None, 'after()', {'locator': locator, 'index': index})
|
||||
else:
|
||||
return NoneElement(self.page, 'after()', {'filter_loc': filter_loc, 'index': index})
|
||||
return NoneElement(self.page, 'after()', {'locator': locator, 'index': index})
|
||||
|
||||
def children(self, filter_loc=''):
|
||||
def children(self, locator=''):
|
||||
"""返回当前元素符合条件的直接子元素或节点组成的列表,可用查询语法筛选
|
||||
:param filter_loc: 用于筛选的查询语法
|
||||
:param locator: 用于筛选的查询语法
|
||||
:return: 直接子元素或节点文本组成的列表
|
||||
"""
|
||||
if not filter_loc:
|
||||
if not locator:
|
||||
loc = '*'
|
||||
else:
|
||||
loc = get_loc(filter_loc, True) # 把定位符转换为xpath
|
||||
loc = get_loc(locator, True) # 把定位符转换为xpath
|
||||
if loc[0] == 'css selector':
|
||||
raise ValueError('此css selector语法不受支持,请换成xpath。')
|
||||
loc = loc[1].lstrip('./')
|
||||
@ -986,12 +975,12 @@ class ShadowRoot(BaseElement):
|
||||
loc = f'xpath:./{loc}'
|
||||
return self._ele(loc, index=None, relative=True)
|
||||
|
||||
def nexts(self, filter_loc=''):
|
||||
def nexts(self, locator=''):
|
||||
"""返回当前元素后面符合条件的同级元素或节点组成的列表,可用查询语法筛选
|
||||
:param filter_loc: 用于筛选的查询语法
|
||||
:param locator: 用于筛选的查询语法
|
||||
:return: ChromiumElement对象组成的列表
|
||||
"""
|
||||
loc = get_loc(filter_loc, True)
|
||||
loc = get_loc(locator, True)
|
||||
if loc[0] == 'css selector':
|
||||
raise ValueError('此css selector语法不受支持,请换成xpath。')
|
||||
|
||||
@ -999,13 +988,13 @@ class ShadowRoot(BaseElement):
|
||||
xpath = f'xpath:./{loc}'
|
||||
return self.parent_ele._ele(xpath, index=None, relative=True)
|
||||
|
||||
def befores(self, filter_loc=''):
|
||||
def befores(self, locator=''):
|
||||
"""返回文档中当前元素前面符合条件的元素或节点组成的列表,可用查询语法筛选
|
||||
查找范围不限同级元素,而是整个DOM文档
|
||||
:param filter_loc: 用于筛选的查询语法
|
||||
:param locator: 用于筛选的查询语法
|
||||
:return: 本元素前面的元素或节点组成的列表
|
||||
"""
|
||||
loc = get_loc(filter_loc, True)
|
||||
loc = get_loc(locator, True)
|
||||
if loc[0] == 'css selector':
|
||||
raise ValueError('此css selector语法不受支持,请换成xpath。')
|
||||
|
||||
@ -1013,63 +1002,63 @@ class ShadowRoot(BaseElement):
|
||||
xpath = f'xpath:./preceding::{loc}'
|
||||
return self.parent_ele._ele(xpath, index=None, relative=True)
|
||||
|
||||
def afters(self, filter_loc=''):
|
||||
def afters(self, locator=''):
|
||||
"""返回文档中当前元素后面符合条件的元素或节点组成的列表,可用查询语法筛选
|
||||
查找范围不限同级元素,而是整个DOM文档
|
||||
:param filter_loc: 用于筛选的查询语法
|
||||
:param locator: 用于筛选的查询语法
|
||||
:return: 本元素后面的元素或节点组成的列表
|
||||
"""
|
||||
eles1 = self.nexts(filter_loc)
|
||||
loc = get_loc(filter_loc, True)[1].lstrip('./')
|
||||
eles1 = self.nexts(locator)
|
||||
loc = get_loc(locator, True)[1].lstrip('./')
|
||||
xpath = f'xpath:./following::{loc}'
|
||||
return eles1 + self.parent_ele._ele(xpath, index=None, relative=True)
|
||||
|
||||
def ele(self, loc_or_str, index=1, timeout=None):
|
||||
def ele(self, locator, index=1, timeout=None):
|
||||
"""返回当前元素下级符合条件的一个元素
|
||||
:param loc_or_str: 元素的定位信息,可以是loc元组,或查询字符串
|
||||
:param locator: 元素的定位信息,可以是loc元组,或查询字符串
|
||||
:param index: 获取第几个元素,从1开始,可传入负数获取倒数第几个
|
||||
:param timeout: 查找元素超时时间(秒),默认与元素所在页面等待时间一致
|
||||
:return: ChromiumElement对象
|
||||
"""
|
||||
return self._ele(loc_or_str, timeout, index=index, method='ele()')
|
||||
return self._ele(locator, timeout, index=index, method='ele()')
|
||||
|
||||
def eles(self, loc_or_str, timeout=None):
|
||||
def eles(self, locator, timeout=None):
|
||||
"""返回当前元素下级所有符合条件的子元素
|
||||
:param loc_or_str: 元素的定位信息,可以是loc元组,或查询字符串
|
||||
:param locator: 元素的定位信息,可以是loc元组,或查询字符串
|
||||
:param timeout: 查找元素超时时间(秒),默认与元素所在页面等待时间一致
|
||||
:return: ChromiumElement对象组成的列表
|
||||
"""
|
||||
return self._ele(loc_or_str, timeout=timeout, index=None)
|
||||
return self._ele(locator, timeout=timeout, index=None)
|
||||
|
||||
def s_ele(self, loc_or_str=None, index=1):
|
||||
def s_ele(self, locator=None, index=1):
|
||||
"""查找一个符合条件的元素以SessionElement形式返回,处理复杂页面时效率很高
|
||||
:param loc_or_str: 元素的定位信息,可以是loc元组,或查询字符串
|
||||
:param locator: 元素的定位信息,可以是loc元组,或查询字符串
|
||||
:param index: 获取第几个,从1开始,可传入负数获取倒数第几个
|
||||
:return: SessionElement对象或属性、文本
|
||||
"""
|
||||
r = make_session_ele(self, loc_or_str, index=index)
|
||||
r = make_session_ele(self, locator, index=index)
|
||||
if isinstance(r, NoneElement):
|
||||
r.method = 's_ele()'
|
||||
r.args = {'loc_or_str': loc_or_str}
|
||||
r.args = {'locator': locator}
|
||||
return r
|
||||
|
||||
def s_eles(self, loc_or_str):
|
||||
def s_eles(self, locator):
|
||||
"""查找所有符合条件的元素以SessionElement列表形式返回,处理复杂页面时效率很高
|
||||
:param loc_or_str: 元素的定位信息,可以是loc元组,或查询字符串
|
||||
:param locator: 元素的定位信息,可以是loc元组,或查询字符串
|
||||
:return: SessionElement对象
|
||||
"""
|
||||
return make_session_ele(self, loc_or_str, index=None)
|
||||
return make_session_ele(self, locator, index=None)
|
||||
|
||||
def _find_elements(self, loc_or_str, timeout=None, index=1, relative=False, raise_err=None):
|
||||
def _find_elements(self, locator, timeout=None, index=1, relative=False, raise_err=None):
|
||||
"""返回当前元素下级符合条件的子元素、属性或节点文本,默认返回第一个
|
||||
:param loc_or_str: 元素的定位信息,可以是loc元组,或查询字符串
|
||||
:param locator: 元素的定位信息,可以是loc元组,或查询字符串
|
||||
:param timeout: 查找元素超时时间(秒)
|
||||
:param index: 第几个结果,从1开始,可传入负数获取倒数第几个,为None返回所有
|
||||
:param relative: WebPage用的表示是否相对定位的参数
|
||||
:param raise_err: 找不到元素是是否抛出异常,为None时根据全局设置
|
||||
:return: ChromiumElement对象或其组成的列表
|
||||
"""
|
||||
loc = get_loc(loc_or_str, css_mode=False)
|
||||
loc = get_loc(locator, css_mode=False)
|
||||
if loc[0] == 'css selector' and str(loc[1]).startswith(':root'):
|
||||
loc = loc[0], loc[1][5:]
|
||||
|
||||
@ -1134,20 +1123,20 @@ class ShadowRoot(BaseElement):
|
||||
return r['backendNodeId']
|
||||
|
||||
|
||||
def find_in_chromium_ele(ele, loc, index=1, timeout=None, relative=True):
|
||||
def find_in_chromium_ele(ele, locator, index=1, timeout=None, relative=True):
|
||||
"""在chromium元素中查找
|
||||
:param ele: ChromiumElement对象
|
||||
:param loc: 元素定位元组
|
||||
:param locator: 元素定位元组
|
||||
:param index: 第几个结果,从1开始,可传入负数获取倒数第几个,为None返回所有
|
||||
:param timeout: 查找元素超时时间(秒)
|
||||
:param relative: WebPage用于标记是否相对定位使用
|
||||
:return: 返回ChromiumElement元素或它们组成的列表
|
||||
"""
|
||||
# ---------------处理定位符---------------
|
||||
if isinstance(loc, (str, tuple)):
|
||||
loc = get_loc(loc)
|
||||
if isinstance(locator, (str, tuple)):
|
||||
loc = get_loc(locator)
|
||||
else:
|
||||
raise ValueError(f"定位符必须为str或长度为2的tuple对象。现在是:{loc}")
|
||||
raise ValueError(f"定位符必须为str或长度为2的tuple对象。现在是:{locator}")
|
||||
|
||||
loc_str = loc[1]
|
||||
if loc[0] == 'xpath' and loc[1].lstrip().startswith('/'):
|
||||
@ -1441,7 +1430,7 @@ def run_js(page_or_ele, script, as_expr, timeout, args=None):
|
||||
else:
|
||||
raise ElementLostError('原来获取到的元素对象已不在页面内。')
|
||||
|
||||
if res is None and page.states.has_alert: # 存在alert的情况
|
||||
if res is None and page.states.has_alert:
|
||||
return None
|
||||
|
||||
exceptionDetails = res.get('exceptionDetails')
|
||||
|
@ -8,7 +8,6 @@
|
||||
from pathlib import Path
|
||||
from typing import Union, Tuple, List, Any, Literal, Optional
|
||||
|
||||
from .none_element import NoneElement
|
||||
from .._base.base import DrissionElement, BaseElement
|
||||
from .._elements.session_element import SessionElement
|
||||
from .._pages.chromium_base import ChromiumBase
|
||||
@ -48,9 +47,9 @@ class ChromiumElement(DrissionElement):
|
||||
def __repr__(self) -> str: ...
|
||||
|
||||
def __call__(self,
|
||||
loc_or_str: Union[Tuple[str, str], str],
|
||||
locator: Union[Tuple[str, str], str],
|
||||
index: int = 1,
|
||||
timeout: float = None) -> Union[ChromiumElement, NoneElement]: ...
|
||||
timeout: float = None) -> ChromiumElement: ...
|
||||
|
||||
def __eq__(self, other: ChromiumElement) -> bool: ...
|
||||
|
||||
@ -73,7 +72,6 @@ class ChromiumElement(DrissionElement):
|
||||
def raw_text(self) -> str: ...
|
||||
|
||||
# -----------------d模式独有属性-------------------
|
||||
|
||||
@property
|
||||
def set(self) -> ChromiumElementSetter: ...
|
||||
|
||||
@ -100,60 +98,60 @@ class ChromiumElement(DrissionElement):
|
||||
|
||||
def parent(self,
|
||||
level_or_loc: Union[tuple, str, int] = 1,
|
||||
index: int = 1) -> Union[ChromiumElement, NoneElement]: ...
|
||||
index: int = 1) -> ChromiumElement: ...
|
||||
|
||||
def child(self,
|
||||
filter_loc: Union[tuple, str, int] = '',
|
||||
locator: Union[Tuple[str, str], str, int] = '',
|
||||
index: int = 1,
|
||||
timeout: float = None,
|
||||
ele_only: bool = True) -> Union[ChromiumElement, str, NoneElement]: ...
|
||||
ele_only: bool = True) -> Union[ChromiumElement, str]: ...
|
||||
|
||||
def prev(self,
|
||||
filter_loc: Union[tuple, str, int] = '',
|
||||
locator: Union[Tuple[str, str], str, int] = '',
|
||||
index: int = 1,
|
||||
timeout: float = None,
|
||||
ele_only: bool = True) -> Union[ChromiumElement, str, NoneElement]: ...
|
||||
ele_only: bool = True) -> Union[ChromiumElement, str]: ...
|
||||
|
||||
def next(self,
|
||||
filter_loc: Union[tuple, str, int] = '',
|
||||
locator: Union[Tuple[str, str], str, int] = '',
|
||||
index: int = 1,
|
||||
timeout: float = None,
|
||||
ele_only: bool = True) -> Union[ChromiumElement, str, NoneElement]: ...
|
||||
ele_only: bool = True) -> Union[ChromiumElement, str]: ...
|
||||
|
||||
def before(self,
|
||||
filter_loc: Union[tuple, str, int] = '',
|
||||
locator: Union[Tuple[str, str], str, int] = '',
|
||||
index: int = 1,
|
||||
timeout: float = None,
|
||||
ele_only: bool = True) -> Union[ChromiumElement, str, NoneElement]: ...
|
||||
ele_only: bool = True) -> Union[ChromiumElement, str]: ...
|
||||
|
||||
def after(self,
|
||||
filter_loc: Union[tuple, str, int] = '',
|
||||
locator: Union[Tuple[str, str], str, int] = '',
|
||||
index: int = 1,
|
||||
timeout: float = None,
|
||||
ele_only: bool = True) -> Union[ChromiumElement, str, NoneElement]: ...
|
||||
ele_only: bool = True) -> Union[ChromiumElement, str]: ...
|
||||
|
||||
def children(self,
|
||||
filter_loc: Union[tuple, str] = '',
|
||||
locator: Union[Tuple[str, str], str] = '',
|
||||
timeout: float = None,
|
||||
ele_only: bool = True) -> List[Union[ChromiumElement, str]]: ...
|
||||
|
||||
def prevs(self,
|
||||
filter_loc: Union[tuple, str] = '',
|
||||
locator: Union[Tuple[str, str], str] = '',
|
||||
timeout: float = None,
|
||||
ele_only: bool = True) -> List[Union[ChromiumElement, str]]: ...
|
||||
|
||||
def nexts(self,
|
||||
filter_loc: Union[tuple, str] = '',
|
||||
locator: Union[Tuple[str, str], str] = '',
|
||||
timeout: float = None,
|
||||
ele_only: bool = True) -> List[Union[ChromiumElement, str]]: ...
|
||||
|
||||
def befores(self,
|
||||
filter_loc: Union[tuple, str] = '',
|
||||
locator: Union[Tuple[str, str], str] = '',
|
||||
timeout: float = None,
|
||||
ele_only: bool = True) -> List[Union[ChromiumElement, str]]: ...
|
||||
|
||||
def afters(self,
|
||||
filter_loc: Union[tuple, str] = '',
|
||||
locator: Union[Tuple[str, str], str] = '',
|
||||
timeout: float = None,
|
||||
ele_only: bool = True) -> List[Union[ChromiumElement, str]]: ...
|
||||
|
||||
@ -163,44 +161,47 @@ class ChromiumElement(DrissionElement):
|
||||
@property
|
||||
def select(self) -> SelectElement: ...
|
||||
|
||||
@property
|
||||
def value(self) -> None: ...
|
||||
|
||||
def check(self, uncheck: bool = False, by_js: bool = False) -> None: ...
|
||||
|
||||
def attr(self, attr: str) -> Union[str, None]: ...
|
||||
def attr(self, name: str) -> Union[str, None]: ...
|
||||
|
||||
def remove_attr(self, attr: str) -> None: ...
|
||||
def remove_attr(self, name: str) -> None: ...
|
||||
|
||||
def prop(self, prop: str) -> Union[str, int, None]: ...
|
||||
def property(self, name: str) -> Union[str, int, None]: ...
|
||||
|
||||
def run_js(self, script: str, *args, as_expr: bool = False, timeout: float = None) -> Any: ...
|
||||
|
||||
def run_async_js(self, script: str, *args, as_expr: bool = False) -> None: ...
|
||||
|
||||
def ele(self,
|
||||
loc_or_str: Union[Tuple[str, str], str],
|
||||
locator: Union[Tuple[str, str], str],
|
||||
index: int = 1,
|
||||
timeout: float = None) -> Union[ChromiumElement, NoneElement]: ...
|
||||
timeout: float = None) -> ChromiumElement: ...
|
||||
|
||||
def eles(self,
|
||||
loc_or_str: Union[Tuple[str, str], str],
|
||||
locator: Union[Tuple[str, str], str],
|
||||
timeout: float = None) -> List[ChromiumElement]: ...
|
||||
|
||||
def s_ele(self,
|
||||
loc_or_str: Union[Tuple[str, str], str] = None,
|
||||
index: int = 1) -> Union[SessionElement, NoneElement]: ...
|
||||
locator: Union[Tuple[str, str], str] = None,
|
||||
index: int = 1) -> SessionElement: ...
|
||||
|
||||
def s_eles(self, loc_or_str: Union[Tuple[str, str], str] = None) -> List[SessionElement]: ...
|
||||
def s_eles(self, locator: Union[Tuple[str, str], str] = None) -> List[SessionElement]: ...
|
||||
|
||||
def _find_elements(self,
|
||||
loc_or_str: Union[Tuple[str, str], str],
|
||||
locator: Union[Tuple[str, str], str],
|
||||
timeout: float = None,
|
||||
index: Optional[int] = 1,
|
||||
relative: bool = False,
|
||||
raise_err: bool = False) -> Union[ChromiumElement, ChromiumFrame, NoneElement,
|
||||
raise_err: bool = False) -> Union[ChromiumElement, ChromiumFrame,
|
||||
List[Union[ChromiumElement, ChromiumFrame]]]: ...
|
||||
|
||||
def style(self, style: str, pseudo_ele: str = '') -> str: ...
|
||||
|
||||
def get_src(self, timeout: float = None, base64_to_bytes: bool = True) -> Union[bytes, str, None]: ...
|
||||
def src(self, timeout: float = None, base64_to_bytes: bool = True) -> Union[bytes, str, None]: ...
|
||||
|
||||
def save(self, path: [str, bool] = None, name: str = None, timeout: float = None) -> str: ...
|
||||
|
||||
@ -248,7 +249,8 @@ class ShadowRoot(BaseElement):
|
||||
|
||||
def __repr__(self) -> str: ...
|
||||
|
||||
def __call__(self, loc_or_str: Union[Tuple[str, str], str],
|
||||
def __call__(self,
|
||||
locator: Union[Tuple[str, str], str],
|
||||
timeout: float = None) -> ChromiumElement: ...
|
||||
|
||||
def __eq__(self, other: ShadowRoot) -> bool: ...
|
||||
@ -271,47 +273,51 @@ class ShadowRoot(BaseElement):
|
||||
|
||||
def parent(self, level_or_loc: Union[str, int] = 1, index: int = 1) -> ChromiumElement: ...
|
||||
|
||||
def child(self, filter_loc: Union[tuple, str] = '',
|
||||
index: int = 1) -> Union[ChromiumElement, NoneElement]: ...
|
||||
def child(self,
|
||||
locator: Union[Tuple[str, str], str] = '',
|
||||
index: int = 1) -> ChromiumElement: ...
|
||||
|
||||
def next(self, filter_loc: Union[tuple, str] = '',
|
||||
index: int = 1) -> Union[ChromiumElement, NoneElement]: ...
|
||||
def next(self,
|
||||
locator: Union[Tuple[str, str], str] = '',
|
||||
index: int = 1) -> ChromiumElement: ...
|
||||
|
||||
def before(self, filter_loc: Union[tuple, str] = '',
|
||||
index: int = 1) -> Union[ChromiumElement, NoneElement]: ...
|
||||
def before(self,
|
||||
locator: Union[Tuple[str, str], str] = '',
|
||||
index: int = 1) -> ChromiumElement: ...
|
||||
|
||||
def after(self, filter_loc: Union[tuple, str] = '',
|
||||
index: int = 1) -> Union[ChromiumElement, NoneElement]: ...
|
||||
def after(self,
|
||||
locator: Union[Tuple[str, str], str] = '',
|
||||
index: int = 1) -> ChromiumElement: ...
|
||||
|
||||
def children(self, filter_loc: Union[tuple, str] = '') -> List[ChromiumElement]: ...
|
||||
def children(self, locator: Union[Tuple[str, str], str] = '') -> List[ChromiumElement]: ...
|
||||
|
||||
def nexts(self, filter_loc: Union[tuple, str] = '') -> List[ChromiumElement]: ...
|
||||
def nexts(self, locator: Union[Tuple[str, str], str] = '') -> List[ChromiumElement]: ...
|
||||
|
||||
def befores(self, filter_loc: Union[tuple, str] = '') -> List[ChromiumElement]: ...
|
||||
def befores(self, locator: Union[Tuple[str, str], str] = '') -> List[ChromiumElement]: ...
|
||||
|
||||
def afters(self, filter_loc: Union[tuple, str] = '') -> List[ChromiumElement]: ...
|
||||
def afters(self, locator: Union[Tuple[str, str], str] = '') -> List[ChromiumElement]: ...
|
||||
|
||||
def ele(self,
|
||||
loc_or_str: Union[Tuple[str, str], str],
|
||||
locator: Union[Tuple[str, str], str],
|
||||
index: int = 1,
|
||||
timeout: float = None) -> Union[ChromiumElement, NoneElement]: ...
|
||||
timeout: float = None) -> ChromiumElement: ...
|
||||
|
||||
def eles(self,
|
||||
loc_or_str: Union[Tuple[str, str], str],
|
||||
locator: Union[Tuple[str, str], str],
|
||||
timeout: float = None) -> List[ChromiumElement]: ...
|
||||
|
||||
def s_ele(self,
|
||||
loc_or_str: Union[Tuple[str, str], str] = None,
|
||||
index: int = 1) -> Union[SessionElement, NoneElement]: ...
|
||||
locator: Union[Tuple[str, str], str] = None,
|
||||
index: int = 1) -> SessionElement: ...
|
||||
|
||||
def s_eles(self, loc_or_str: Union[Tuple[str, str], str]) -> List[SessionElement]: ...
|
||||
def s_eles(self, locator: Union[Tuple[str, str], str]) -> List[SessionElement]: ...
|
||||
|
||||
def _find_elements(self,
|
||||
loc_or_str: Union[Tuple[str, str], str],
|
||||
locator: Union[Tuple[str, str], str],
|
||||
timeout: float = None,
|
||||
index: Optional[int] = 1,
|
||||
relative: bool = False,
|
||||
raise_err: bool = None) -> Union[ChromiumElement, ChromiumFrame, NoneElement, str,
|
||||
raise_err: bool = None) -> Union[ChromiumElement, ChromiumFrame, str,
|
||||
List[Union[ChromiumElement, ChromiumFrame, str]]]: ...
|
||||
|
||||
def _get_node_id(self, obj_id: str) -> int: ...
|
||||
@ -325,28 +331,27 @@ def find_in_chromium_ele(ele: ChromiumElement,
|
||||
loc: Union[str, Tuple[str, str]],
|
||||
index: Optional[int] = 1,
|
||||
timeout: float = None,
|
||||
relative: bool = True) -> Union[ChromiumElement, NoneElement, List[ChromiumElement]]: ...
|
||||
relative: bool = True) -> Union[ChromiumElement, List[ChromiumElement]]: ...
|
||||
|
||||
|
||||
def find_by_xpath(ele: ChromiumElement,
|
||||
xpath: str,
|
||||
index: Optional[int],
|
||||
timeout: float,
|
||||
relative: bool = True) -> Union[ChromiumElement, List[ChromiumElement], NoneElement]: ...
|
||||
relative: bool = True) -> Union[ChromiumElement, List[ChromiumElement]]: ...
|
||||
|
||||
|
||||
def find_by_css(ele: ChromiumElement,
|
||||
selector: str,
|
||||
index: Optional[int],
|
||||
timeout: float) -> Union[ChromiumElement, List[ChromiumElement], NoneElement]: ...
|
||||
timeout: float) -> Union[ChromiumElement, List[ChromiumElement],]: ...
|
||||
|
||||
|
||||
def make_chromium_eles(page: Union[ChromiumBase, ChromiumPage, WebPage, ChromiumTab, ChromiumFrame],
|
||||
_ids: Union[tuple, list, str, int],
|
||||
index: Optional[int] = 1,
|
||||
is_obj_id: bool = True
|
||||
) -> Union[ChromiumElement, ChromiumFrame, NoneElement,
|
||||
List[Union[ChromiumElement, ChromiumFrame]]]: ...
|
||||
) -> Union[ChromiumElement, ChromiumFrame, List[Union[ChromiumElement, ChromiumFrame]]]: ...
|
||||
|
||||
|
||||
def make_js_for_find_ele_by_xpath(xpath: str, type_txt: str, node_txt: str) -> str: ...
|
||||
|
@ -18,6 +18,7 @@ class NoneElement(object):
|
||||
self._none_ele_return_value = False
|
||||
self.method = method
|
||||
self.args = args
|
||||
self._get = None
|
||||
|
||||
def __call__(self, *args, **kwargs):
|
||||
if not self._none_ele_return_value:
|
||||
@ -33,7 +34,7 @@ class NoneElement(object):
|
||||
return self
|
||||
else:
|
||||
if item in ('size', 'link', 'css_path', 'xpath', 'comments', 'texts', 'tag', 'html', 'inner_html',
|
||||
'attrs', 'text', 'raw_text'):
|
||||
'attrs', 'text', 'raw_text', 'value', 'attr', 'style', 'src', 'property'):
|
||||
return self._none_ele_value
|
||||
else:
|
||||
raise ElementNotFoundError(None, self.method, self.args)
|
||||
|
@ -27,23 +27,24 @@ class SessionElement(DrissionElement):
|
||||
"""
|
||||
super().__init__(page)
|
||||
self._inner_ele = ele
|
||||
self._type = 'SessionElement'
|
||||
|
||||
@property
|
||||
def inner_ele(self):
|
||||
return self._inner_ele
|
||||
|
||||
def __repr__(self):
|
||||
attrs = [f"{attr}='{self.attrs[attr]}'" for attr in self.attrs]
|
||||
attrs = [f"{k}='{v}'" for k, v in self.attrs.items()]
|
||||
return f'<SessionElement {self.tag} {" ".join(attrs)}>'
|
||||
|
||||
def __call__(self, loc_or_str, timeout=None):
|
||||
def __call__(self, locator, timeout=None):
|
||||
"""在内部查找元素
|
||||
例:ele2 = ele1('@id=ele_id')
|
||||
:param loc_or_str: 元素的定位信息,可以是loc元组,或查询字符串
|
||||
:param timeout: 不起实际作用,用于和DriverElement对应,便于无差别调用
|
||||
:param locator: 元素的定位信息,可以是loc元组,或查询字符串
|
||||
:param timeout: 不起实际作用
|
||||
:return: SessionElement对象或属性、文本
|
||||
"""
|
||||
return self.ele(loc_or_str)
|
||||
return self.ele(locator)
|
||||
|
||||
def __eq__(self, other):
|
||||
return self.xpath == getattr(other, 'xpath', None)
|
||||
@ -80,119 +81,120 @@ class SessionElement(DrissionElement):
|
||||
"""返回未格式化处理的元素内文本"""
|
||||
return str(self._inner_ele.text_content())
|
||||
|
||||
def parent(self, level_or_loc=1):
|
||||
def parent(self, level_or_loc=1, index=1):
|
||||
"""返回上面某一级父元素,可指定层数或用查询语法定位
|
||||
:param level_or_loc: 第几级父元素,或定位符
|
||||
:param index: 当level_or_loc传入定位符,使用此参数选择第几个结果
|
||||
:return: 上级元素对象
|
||||
"""
|
||||
return super().parent(level_or_loc)
|
||||
return super().parent(level_or_loc, index)
|
||||
|
||||
def child(self, filter_loc='', index=1, timeout=None, ele_only=True):
|
||||
def child(self, locator='', index=1, timeout=None, ele_only=True):
|
||||
"""返回当前元素的一个符合条件的直接子元素,可用查询语法筛选,可指定返回筛选结果的第几个
|
||||
:param filter_loc: 用于筛选的查询语法
|
||||
:param locator: 用于筛选的查询语法
|
||||
:param index: 第几个查询结果,1开始
|
||||
:param timeout: 此参数不起实际作用
|
||||
:param ele_only: 是否只获取元素,为False时把文本、注释节点也纳入
|
||||
:return: 直接子元素或节点文本
|
||||
"""
|
||||
return super().child(index, filter_loc, timeout, ele_only=ele_only)
|
||||
return super().child(locator, index, timeout, ele_only=ele_only)
|
||||
|
||||
def prev(self, filter_loc='', index=1, timeout=None, ele_only=True):
|
||||
def prev(self, locator='', index=1, timeout=None, ele_only=True):
|
||||
"""返回当前元素前面一个符合条件的同级元素,可用查询语法筛选,可指定返回筛选结果的第几个
|
||||
:param filter_loc: 用于筛选的查询语法
|
||||
:param locator: 用于筛选的查询语法
|
||||
:param index: 前面第几个查询结果,1开始
|
||||
:param timeout: 此参数不起实际作用
|
||||
:param ele_only: 是否只获取元素,为False时把文本、注释节点也纳入
|
||||
:return: 同级元素
|
||||
"""
|
||||
return super().prev(index, filter_loc, timeout, ele_only=ele_only)
|
||||
return super().prev(locator, index, timeout, ele_only=ele_only)
|
||||
|
||||
def next(self, filter_loc='', index=1, timeout=None, ele_only=True):
|
||||
def next(self, locator='', index=1, timeout=None, ele_only=True):
|
||||
"""返回当前元素后面一个符合条件的同级元素,可用查询语法筛选,可指定返回筛选结果的第几个
|
||||
:param filter_loc: 用于筛选的查询语法
|
||||
:param locator: 用于筛选的查询语法
|
||||
:param index: 第几个查询结果,1开始
|
||||
:param timeout: 此参数不起实际作用
|
||||
:param ele_only: 是否只获取元素,为False时把文本、注释节点也纳入
|
||||
:return: 同级元素
|
||||
"""
|
||||
return super().next(index, filter_loc, timeout, ele_only=ele_only)
|
||||
return super().next(locator, index, timeout, ele_only=ele_only)
|
||||
|
||||
def before(self, filter_loc='', index=1, timeout=None, ele_only=True):
|
||||
def before(self, locator='', index=1, timeout=None, ele_only=True):
|
||||
"""返回文档中当前元素前面符合条件的一个元素,可用查询语法筛选,可指定返回筛选结果的第几个
|
||||
查找范围不限同级元素,而是整个DOM文档
|
||||
:param filter_loc: 用于筛选的查询语法
|
||||
:param locator: 用于筛选的查询语法
|
||||
:param index: 前面第几个查询结果,1开始
|
||||
:param timeout: 此参数不起实际作用
|
||||
:param ele_only: 是否只获取元素,为False时把文本、注释节点也纳入
|
||||
:return: 本元素前面的某个元素或节点
|
||||
"""
|
||||
return super().before(index, filter_loc, timeout, ele_only=ele_only)
|
||||
return super().before(locator, index, timeout, ele_only=ele_only)
|
||||
|
||||
def after(self, filter_loc='', index=1, timeout=None, ele_only=True):
|
||||
def after(self, locator='', index=1, timeout=None, ele_only=True):
|
||||
"""返回文档中此当前元素后面符合条件的一个元素,可用查询语法筛选,可指定返回筛选结果的第几个
|
||||
查找范围不限同级元素,而是整个DOM文档
|
||||
:param filter_loc: 用于筛选的查询语法
|
||||
:param locator: 用于筛选的查询语法
|
||||
:param index: 第几个查询结果,1开始
|
||||
:param timeout: 此参数不起实际作用
|
||||
:param ele_only: 是否只获取元素,为False时把文本、注释节点也纳入
|
||||
:return: 本元素后面的某个元素或节点
|
||||
"""
|
||||
return super().after(index, filter_loc, timeout, ele_only=ele_only)
|
||||
return super().after(locator, index, timeout, ele_only=ele_only)
|
||||
|
||||
def children(self, filter_loc='', timeout=0, ele_only=True):
|
||||
def children(self, locator='', timeout=0, ele_only=True):
|
||||
"""返回当前元素符合条件的直接子元素或节点组成的列表,可用查询语法筛选
|
||||
:param filter_loc: 用于筛选的查询语法
|
||||
:param locator: 用于筛选的查询语法
|
||||
:param timeout: 此参数不起实际作用
|
||||
:param ele_only: 是否只获取元素,为False时把文本、注释节点也纳入
|
||||
:return: 直接子元素或节点文本组成的列表
|
||||
"""
|
||||
return super().children(filter_loc, timeout, ele_only=ele_only)
|
||||
return super().children(locator, timeout, ele_only=ele_only)
|
||||
|
||||
def prevs(self, filter_loc='', timeout=None, ele_only=True):
|
||||
def prevs(self, locator='', timeout=None, ele_only=True):
|
||||
"""返回当前元素前面符合条件的同级元素或节点组成的列表,可用查询语法筛选
|
||||
:param filter_loc: 用于筛选的查询语法
|
||||
:param locator: 用于筛选的查询语法
|
||||
:param timeout: 此参数不起实际作用
|
||||
:param ele_only: 是否只获取元素,为False时把文本、注释节点也纳入
|
||||
:return: 同级元素或节点文本组成的列表
|
||||
"""
|
||||
return super().prevs(filter_loc, timeout, ele_only=ele_only)
|
||||
return super().prevs(locator, timeout, ele_only=ele_only)
|
||||
|
||||
def nexts(self, filter_loc='', timeout=None, ele_only=True):
|
||||
def nexts(self, locator='', timeout=None, ele_only=True):
|
||||
"""返回当前元素后面符合条件的同级元素或节点组成的列表,可用查询语法筛选
|
||||
:param filter_loc: 用于筛选的查询语法
|
||||
:param locator: 用于筛选的查询语法
|
||||
:param timeout: 此参数不起实际作用
|
||||
:param ele_only: 是否只获取元素,为False时把文本、注释节点也纳入
|
||||
:return: 同级元素或节点文本组成的列表
|
||||
"""
|
||||
return super().nexts(filter_loc, timeout, ele_only=ele_only)
|
||||
return super().nexts(locator, timeout, ele_only=ele_only)
|
||||
|
||||
def befores(self, filter_loc='', timeout=None, ele_only=True):
|
||||
def befores(self, locator='', timeout=None, ele_only=True):
|
||||
"""返回文档中当前元素前面符合条件的元素或节点组成的列表,可用查询语法筛选
|
||||
查找范围不限同级元素,而是整个DOM文档
|
||||
:param filter_loc: 用于筛选的查询语法
|
||||
:param locator: 用于筛选的查询语法
|
||||
:param timeout: 此参数不起实际作用
|
||||
:param ele_only: 是否只获取元素,为False时把文本、注释节点也纳入
|
||||
:return: 本元素前面的元素或节点组成的列表
|
||||
"""
|
||||
return super().befores(filter_loc, timeout, ele_only=ele_only)
|
||||
return super().befores(locator, timeout, ele_only=ele_only)
|
||||
|
||||
def afters(self, filter_loc='', timeout=None, ele_only=True):
|
||||
def afters(self, locator='', timeout=None, ele_only=True):
|
||||
"""返回文档中当前元素后面符合条件的元素或节点组成的列表,可用查询语法筛选
|
||||
查找范围不限同级元素,而是整个DOM文档
|
||||
:param filter_loc: 用于筛选的查询语法
|
||||
:param locator: 用于筛选的查询语法
|
||||
:param timeout: 此参数不起实际作用
|
||||
:param ele_only: 是否只获取元素,为False时把文本、注释节点也纳入
|
||||
:return: 本元素后面的元素或节点组成的列表
|
||||
"""
|
||||
return super().afters(filter_loc, timeout, ele_only=ele_only)
|
||||
return super().afters(locator, timeout, ele_only=ele_only)
|
||||
|
||||
def attr(self, attr):
|
||||
def attr(self, name):
|
||||
"""返回attribute属性值
|
||||
:param attr: 属性名
|
||||
:param name: 属性名
|
||||
:return: 属性值文本,没有该属性返回None
|
||||
"""
|
||||
# 获取href属性时返回绝对url
|
||||
if attr == 'href':
|
||||
if name == 'href':
|
||||
link = self.inner_ele.get('href')
|
||||
# 若为链接为None、js或邮件,直接返回
|
||||
if not link or link.lower().startswith(('javascript:', 'mailto:')):
|
||||
@ -201,66 +203,66 @@ class SessionElement(DrissionElement):
|
||||
else: # 其它情况直接返回绝对url
|
||||
return make_absolute_link(link, self.page.url)
|
||||
|
||||
elif attr == 'src':
|
||||
elif name == 'src':
|
||||
return make_absolute_link(self.inner_ele.get('src'), self.page.url)
|
||||
|
||||
elif attr == 'text':
|
||||
elif name == 'text':
|
||||
return self.text
|
||||
|
||||
elif attr == 'innerText':
|
||||
elif name == 'innerText':
|
||||
return self.raw_text
|
||||
|
||||
elif attr in ('html', 'outerHTML'):
|
||||
elif name in ('html', 'outerHTML'):
|
||||
return self.html
|
||||
|
||||
elif attr == 'innerHTML':
|
||||
elif name == 'innerHTML':
|
||||
return self.inner_html
|
||||
|
||||
else:
|
||||
return self.inner_ele.get(attr)
|
||||
return self.inner_ele.get(name)
|
||||
|
||||
def ele(self, loc_or_str, index=1, timeout=None):
|
||||
def ele(self, locator, index=1, timeout=None):
|
||||
"""返回当前元素下级符合条件的一个元素、属性或节点文本
|
||||
:param loc_or_str: 元素的定位信息,可以是loc元组,或查询字符串
|
||||
:param locator: 元素的定位信息,可以是loc元组,或查询字符串
|
||||
:param index: 第几个元素,从1开始,可传入负数获取倒数第几个
|
||||
:param timeout: 不起实际作用
|
||||
:return: SessionElement对象或属性、文本
|
||||
"""
|
||||
return self._ele(loc_or_str, index=index, method='ele()')
|
||||
return self._ele(locator, index=index, method='ele()')
|
||||
|
||||
def eles(self, loc_or_str, timeout=None):
|
||||
def eles(self, locator, timeout=None):
|
||||
"""返回当前元素下级所有符合条件的子元素、属性或节点文本
|
||||
:param loc_or_str: 元素的定位信息,可以是loc元组,或查询字符串
|
||||
:param timeout: 不起实际作用,用于和DriverElement对应,便于无差别调用
|
||||
:param locator: 元素的定位信息,可以是loc元组,或查询字符串
|
||||
:param timeout: 不起实际作用
|
||||
:return: SessionElement对象或属性、文本组成的列表
|
||||
"""
|
||||
return self._ele(loc_or_str, index=None)
|
||||
return self._ele(locator, index=None)
|
||||
|
||||
def s_ele(self, loc_or_str=None, index=1):
|
||||
def s_ele(self, locator=None, index=1):
|
||||
"""返回当前元素下级符合条件的一个元素、属性或节点文本
|
||||
:param loc_or_str: 元素的定位信息,可以是loc元组,或查询字符串
|
||||
:param locator: 元素的定位信息,可以是loc元组,或查询字符串
|
||||
:param index: 获取第几个,从1开始,可传入负数获取倒数第几个
|
||||
:return: SessionElement对象或属性、文本
|
||||
"""
|
||||
return self._ele(loc_or_str, index=index, method='s_ele()')
|
||||
return self._ele(locator, index=index, method='s_ele()')
|
||||
|
||||
def s_eles(self, loc_or_str):
|
||||
def s_eles(self, locator):
|
||||
"""返回当前元素下级所有符合条件的子元素、属性或节点文本
|
||||
:param loc_or_str: 元素的定位信息,可以是loc元组,或查询字符串
|
||||
:param locator: 元素的定位信息,可以是loc元组,或查询字符串
|
||||
:return: SessionElement对象或属性、文本组成的列表
|
||||
"""
|
||||
return self._ele(loc_or_str, index=None)
|
||||
return self._ele(locator, index=None)
|
||||
|
||||
def _find_elements(self, loc_or_str, timeout=None, index=1, relative=False, raise_err=None):
|
||||
def _find_elements(self, locator, timeout=None, index=1, relative=False, raise_err=None):
|
||||
"""返回当前元素下级符合条件的子元素、属性或节点文本
|
||||
:param loc_or_str: 元素的定位信息,可以是loc元组,或查询字符串
|
||||
:param locator: 元素的定位信息,可以是loc元组,或查询字符串
|
||||
:param timeout: 不起实际作用,用于和父类对应
|
||||
:param index: 第几个结果,从1开始,可传入负数获取倒数第几个,为None返回所有
|
||||
:param relative: WebPage用的表示是否相对定位的参数
|
||||
:param raise_err: 找不到元素是是否抛出异常,为None时根据全局设置
|
||||
:return: SessionElement对象
|
||||
"""
|
||||
return make_session_ele(self, loc_or_str, index=index)
|
||||
return make_session_ele(self, locator, index=index)
|
||||
|
||||
def _get_ele_path(self, mode):
|
||||
"""获取css路径或xpath路径
|
||||
@ -304,9 +306,13 @@ def make_session_ele(html_or_ele, loc=None, index=1):
|
||||
raise ValueError("定位符必须为str或长度为2的tuple。")
|
||||
|
||||
# ---------------根据传入对象类型获取页面对象和lxml元素对象---------------
|
||||
the_type = str(type(html_or_ele))
|
||||
# 直接传入html文本
|
||||
if isinstance(html_or_ele, str):
|
||||
page = None
|
||||
html_or_ele = fromstring(html_or_ele)
|
||||
|
||||
# SessionElement
|
||||
if the_type.endswith(".SessionElement'>"):
|
||||
elif html_or_ele._type == 'SessionElement':
|
||||
page = html_or_ele.page
|
||||
|
||||
loc_str = loc[1]
|
||||
@ -327,8 +333,7 @@ def make_session_ele(html_or_ele, loc=None, index=1):
|
||||
|
||||
loc = loc[0], loc_str
|
||||
|
||||
# ChromiumElement, DriverElement
|
||||
elif the_type.endswith((".ChromiumElement'>", ".DriverElement'>")):
|
||||
elif html_or_ele._type == 'ChromiumElement':
|
||||
loc_str = loc[1]
|
||||
if loc[0] == 'xpath' and loc[1].lstrip().startswith('/'):
|
||||
loc_str = f'.{loc[1]}'
|
||||
@ -353,11 +358,6 @@ def make_session_ele(html_or_ele, loc=None, index=1):
|
||||
html = sub(r'^<\?xml.*?>', '', html)
|
||||
html_or_ele = fromstring(html)
|
||||
|
||||
# 直接传入html文本
|
||||
elif isinstance(html_or_ele, str):
|
||||
page = None
|
||||
html_or_ele = fromstring(html_or_ele)
|
||||
|
||||
# ShadowRoot
|
||||
elif isinstance(html_or_ele, BaseElement):
|
||||
page = html_or_ele.page
|
||||
|
@ -9,7 +9,6 @@ from typing import Union, List, Tuple, Optional
|
||||
|
||||
from lxml.html import HtmlElement
|
||||
|
||||
from .none_element import NoneElement
|
||||
from .._base.base import DrissionElement, BaseElement
|
||||
from .._elements.chromium_element import ChromiumElement
|
||||
from .._pages.chromium_base import ChromiumBase
|
||||
@ -29,9 +28,9 @@ class SessionElement(DrissionElement):
|
||||
def __repr__(self) -> str: ...
|
||||
|
||||
def __call__(self,
|
||||
loc_or_str: Union[Tuple[str, str], str],
|
||||
locator: Union[Tuple[str, str], str],
|
||||
index: int = 1,
|
||||
timeout: float = None) -> Union[SessionElement, NoneElement]: ...
|
||||
timeout: float = None) -> SessionElement: ...
|
||||
|
||||
def __eq__(self, other: SessionElement) -> bool: ...
|
||||
|
||||
@ -55,86 +54,86 @@ class SessionElement(DrissionElement):
|
||||
|
||||
def parent(self,
|
||||
level_or_loc: Union[tuple, str, int] = 1,
|
||||
index: int = 1) -> Union[SessionElement, NoneElement]: ...
|
||||
index: int = 1) -> SessionElement: ...
|
||||
|
||||
def child(self,
|
||||
filter_loc: Union[tuple, str, int] = '',
|
||||
locator: Union[Tuple[str, str], str, int] = '',
|
||||
index: int = 1,
|
||||
timeout: float = None,
|
||||
ele_only: bool = True) -> Union[SessionElement, str, NoneElement]: ...
|
||||
ele_only: bool = True) -> Union[SessionElement, str]: ...
|
||||
|
||||
def prev(self,
|
||||
filter_loc: Union[tuple, str, int] = '',
|
||||
locator: Union[Tuple[str, str], str, int] = '',
|
||||
index: int = 1,
|
||||
timeout: float = None,
|
||||
ele_only: bool = True) -> Union[SessionElement, str, NoneElement]: ...
|
||||
ele_only: bool = True) -> Union[SessionElement, str]: ...
|
||||
|
||||
def next(self,
|
||||
filter_loc: Union[tuple, str, int] = '',
|
||||
locator: Union[Tuple[str, str], str, int] = '',
|
||||
index: int = 1,
|
||||
timeout: float = None,
|
||||
ele_only: bool = True) -> Union[SessionElement, str, NoneElement]: ...
|
||||
ele_only: bool = True) -> Union[SessionElement, str]: ...
|
||||
|
||||
def before(self,
|
||||
filter_loc: Union[tuple, str, int] = '',
|
||||
locator: Union[Tuple[str, str], str, int] = '',
|
||||
index: int = 1,
|
||||
timeout: float = None,
|
||||
ele_only: bool = True) -> Union[SessionElement, str, NoneElement]: ...
|
||||
ele_only: bool = True) -> Union[SessionElement, str]: ...
|
||||
|
||||
def after(self,
|
||||
filter_loc: Union[tuple, str, int] = '',
|
||||
locator: Union[Tuple[str, str], str, int] = '',
|
||||
index: int = 1,
|
||||
timeout: float = None,
|
||||
ele_only: bool = True) -> Union[SessionElement, str, NoneElement]: ...
|
||||
ele_only: bool = True) -> Union[SessionElement, str]: ...
|
||||
|
||||
def children(self,
|
||||
filter_loc: Union[tuple, str] = '',
|
||||
locator: Union[Tuple[str, str], str] = '',
|
||||
timeout: float = None,
|
||||
ele_only: bool = True) -> List[Union[SessionElement, str]]: ...
|
||||
|
||||
def prevs(self,
|
||||
filter_loc: Union[tuple, str] = '',
|
||||
locator: Union[Tuple[str, str], str] = '',
|
||||
timeout: float = None,
|
||||
ele_only: bool = True) -> List[Union[SessionElement, str]]: ...
|
||||
|
||||
def nexts(self,
|
||||
filter_loc: Union[tuple, str] = '',
|
||||
locator: Union[Tuple[str, str], str] = '',
|
||||
timeout: float = None,
|
||||
ele_only: bool = True) -> List[Union[SessionElement, str]]: ...
|
||||
|
||||
def befores(self,
|
||||
filter_loc: Union[tuple, str] = '',
|
||||
locator: Union[Tuple[str, str], str] = '',
|
||||
timeout: float = None,
|
||||
ele_only: bool = True) -> List[Union[SessionElement, str]]: ...
|
||||
|
||||
def afters(self,
|
||||
filter_loc: Union[tuple, str] = '',
|
||||
locator: Union[Tuple[str, str], str] = '',
|
||||
timeout: float = None,
|
||||
ele_only: bool = True) -> List[Union[SessionElement, str]]: ...
|
||||
|
||||
def attr(self, attr: str) -> Optional[str]: ...
|
||||
def attr(self, name: str) -> Optional[str]: ...
|
||||
|
||||
def ele(self,
|
||||
loc_or_str: Union[Tuple[str, str], str],
|
||||
locator: Union[Tuple[str, str], str],
|
||||
index: int = 1,
|
||||
timeout: float = None) -> Union[SessionElement, NoneElement]: ...
|
||||
timeout: float = None) -> SessionElement: ...
|
||||
|
||||
def eles(self,
|
||||
loc_or_str: Union[Tuple[str, str], str],
|
||||
locator: Union[Tuple[str, str], str],
|
||||
timeout: float = None) -> List[SessionElement]: ...
|
||||
|
||||
def s_ele(self,
|
||||
loc_or_str: Union[Tuple[str, str], str] = None,
|
||||
index: int = 1) -> Union[SessionElement, NoneElement]: ...
|
||||
locator: Union[Tuple[str, str], str] = None,
|
||||
index: int = 1) -> SessionElement: ...
|
||||
|
||||
def s_eles(self, loc_or_str: Union[Tuple[str, str], str]) -> List[SessionElement]: ...
|
||||
def s_eles(self, locator: Union[Tuple[str, str], str]) -> List[SessionElement]: ...
|
||||
|
||||
def _find_elements(self,
|
||||
loc_or_str: Union[Tuple[str, str], str],
|
||||
locator: Union[Tuple[str, str], str],
|
||||
timeout: float = None,
|
||||
index: Optional[int] = 1,
|
||||
relative: bool = False,
|
||||
raise_err: bool = None) -> Union[SessionElement, NoneElement, List[SessionElement]]: ...
|
||||
raise_err: bool = None) -> Union[SessionElement, List[SessionElement]]: ...
|
||||
|
||||
def _get_ele_path(self, mode: str) -> str: ...
|
||||
|
||||
@ -142,4 +141,4 @@ class SessionElement(DrissionElement):
|
||||
def make_session_ele(html_or_ele: Union[str, SessionElement, SessionPage, ChromiumElement, BaseElement, ChromiumFrame,
|
||||
ChromiumBase],
|
||||
loc: Union[str, Tuple[str, str]] = None,
|
||||
index: Optional[int] = 1) -> Union[SessionElement, NoneElement, List[SessionElement]]: ...
|
||||
index: Optional[int] = 1) -> Union[SessionElement, List[SessionElement]]: ...
|
||||
|
@ -6,10 +6,9 @@
|
||||
@License : BSD 3-Clause.
|
||||
"""
|
||||
from json import load, dump, JSONDecodeError
|
||||
from os import popen
|
||||
from os import environ
|
||||
from pathlib import Path
|
||||
from platform import system
|
||||
from re import search
|
||||
from subprocess import Popen, DEVNULL
|
||||
from tempfile import gettempdir
|
||||
from time import perf_counter, sleep
|
||||
@ -27,7 +26,7 @@ def connect_browser(option):
|
||||
:return: 返回是否接管的浏览器
|
||||
"""
|
||||
address = option.address.replace('localhost', '127.0.0.1').lstrip('http://').lstrip('https://')
|
||||
chrome_path = option.browser_path
|
||||
browser_path = option.browser_path
|
||||
|
||||
ip, port = address.split(':')
|
||||
if ip != '127.0.0.1' or port_is_using(ip, port) or option.is_existing_only:
|
||||
@ -44,16 +43,16 @@ def connect_browser(option):
|
||||
set_prefs(option)
|
||||
set_flags(option)
|
||||
try:
|
||||
_run_browser(port, chrome_path, args)
|
||||
_run_browser(port, browser_path, args)
|
||||
|
||||
# 传入的路径找不到,主动在ini文件、注册表、系统变量中找
|
||||
except FileNotFoundError:
|
||||
chrome_path = get_chrome_path()
|
||||
browser_path = get_chrome_path(option.ini_path)
|
||||
|
||||
if not chrome_path:
|
||||
if not browser_path:
|
||||
raise FileNotFoundError('无法找到浏览器可执行文件路径,请手动配置。')
|
||||
|
||||
_run_browser(port, chrome_path, args)
|
||||
_run_browser(port, browser_path, args)
|
||||
|
||||
test_connect(ip, port)
|
||||
return False
|
||||
@ -220,7 +219,7 @@ def test_connect(ip, port, timeout=30):
|
||||
|
||||
|
||||
def _run_browser(port, path: str, args) -> Popen:
|
||||
"""创建chrome进程
|
||||
"""创建浏览器进程
|
||||
:param port: 端口号
|
||||
:param path: 浏览器路径
|
||||
:param args: 启动参数
|
||||
@ -283,12 +282,13 @@ def _remove_arg_from_dict(target_dict: dict, arg: str) -> None:
|
||||
pass
|
||||
|
||||
|
||||
def get_chrome_path():
|
||||
def get_chrome_path(ini_path):
|
||||
"""从ini文件或系统变量中获取chrome可执行文件的路径"""
|
||||
# -----------从ini文件中获取--------------
|
||||
path = OptionsManager().chromium_options.get('browser_path', None)
|
||||
if path and Path(path).is_file():
|
||||
return str(path)
|
||||
if ini_path:
|
||||
path = OptionsManager(ini_path).chromium_options.get('browser_path', None)
|
||||
if path and Path(path).is_file():
|
||||
return str(path)
|
||||
|
||||
# -----------使用which获取-----------
|
||||
from shutil import which
|
||||
@ -330,23 +330,8 @@ def get_chrome_path():
|
||||
pass
|
||||
|
||||
# -----------从系统变量中获取--------------
|
||||
try:
|
||||
paths = popen('set path').read().lower()
|
||||
except:
|
||||
return None
|
||||
r = search(r'[^;]*chrome[^;]*', paths)
|
||||
|
||||
if r:
|
||||
path = Path(r.group(0)) if 'chrome.exe' in r.group(0) else Path(r.group(0)) / 'chrome.exe'
|
||||
|
||||
if path.exists():
|
||||
return str(path)
|
||||
|
||||
paths = paths.split(';')
|
||||
|
||||
for path in paths:
|
||||
for path in environ.get('PATH', '').split(';'):
|
||||
path = Path(path) / 'chrome.exe'
|
||||
|
||||
try:
|
||||
if path.exists():
|
||||
return str(path)
|
||||
|
@ -25,4 +25,4 @@ def set_flags(opt: ChromiumOptions) -> None: ...
|
||||
def test_connect(ip: str, port: Union[int, str], timeout: float = 30) -> None: ...
|
||||
|
||||
|
||||
def get_chrome_path() -> Union[str, None]: ...
|
||||
def get_chrome_path(ini_path: str) -> Union[str, None]: ...
|
||||
|
@ -8,7 +8,9 @@
|
||||
from pathlib import Path
|
||||
from platform import system
|
||||
from shutil import rmtree
|
||||
from time import perf_counter, sleep
|
||||
from tempfile import gettempdir, TemporaryDirectory
|
||||
from threading import Lock
|
||||
from time import perf_counter
|
||||
|
||||
from psutil import process_iter, AccessDenied, NoSuchProcess, ZombieProcess
|
||||
|
||||
@ -17,6 +19,47 @@ from ..errors import (ContextLostError, ElementLostError, CDPError, PageDisconne
|
||||
AlertExistsError, WrongURLError, StorageError, CookieFormatError, JavaScriptError)
|
||||
|
||||
|
||||
class PortFinder(object):
|
||||
used_port = {}
|
||||
lock = Lock()
|
||||
|
||||
def __init__(self, path=None):
|
||||
"""
|
||||
:param path: 临时文件保存路径,为None时使用系统临时文件夹
|
||||
"""
|
||||
tmp = Path(path) if path else Path(gettempdir()) / 'DrissionPage'
|
||||
self.tmp_dir = tmp / 'UserTempFolder'
|
||||
self.tmp_dir.mkdir(parents=True, exist_ok=True)
|
||||
if not PortFinder.used_port:
|
||||
clean_folder(self.tmp_dir)
|
||||
|
||||
def get_port(self, scope=None):
|
||||
"""查找一个可用端口
|
||||
:param scope: 指定端口范围,不含最后的数字,为None则使用[9600-19600)
|
||||
:return: 可以使用的端口和用户文件夹路径组成的元组
|
||||
"""
|
||||
with PortFinder.lock:
|
||||
if scope in (True, None):
|
||||
scope = (9600, 19600)
|
||||
for i in range(scope[0], scope[1]):
|
||||
if i in PortFinder.used_port:
|
||||
continue
|
||||
elif port_is_using('127.0.0.1', i):
|
||||
PortFinder.used_port[i] = None
|
||||
continue
|
||||
path = TemporaryDirectory(dir=self.tmp_dir).name
|
||||
PortFinder.used_port[i] = path
|
||||
return i, path
|
||||
|
||||
for i in range(scope[0], scope[1]):
|
||||
if port_is_using('127.0.0.1', i):
|
||||
continue
|
||||
rmtree(PortFinder.used_port[i], ignore_errors=True)
|
||||
return i, TemporaryDirectory(dir=self.tmp_dir).name
|
||||
|
||||
raise OSError('未找到可用端口。')
|
||||
|
||||
|
||||
def port_is_using(ip, port):
|
||||
"""检查端口是否被占用
|
||||
:param ip: 浏览器地址
|
||||
@ -69,7 +112,7 @@ def show_or_hide_browser(page, hide=True):
|
||||
pid = page.process_id
|
||||
if not pid:
|
||||
return None
|
||||
hds = get_chrome_hwnds_from_pid(pid, page.title)
|
||||
hds = get_hwnds_from_pid(pid, page.title)
|
||||
sw = SW_HIDE if hide else SW_SHOW
|
||||
for hd in hds:
|
||||
ShowWindow(hd, sw)
|
||||
@ -98,7 +141,7 @@ def get_browser_progress_id(progress, address):
|
||||
return txt.split(' ')[-1]
|
||||
|
||||
|
||||
def get_chrome_hwnds_from_pid(pid, title):
|
||||
def get_hwnds_from_pid(pid, title):
|
||||
"""通过PID查询句柄ID
|
||||
:param pid: 进程id
|
||||
:param title: 窗口标题
|
||||
@ -122,40 +165,21 @@ def get_chrome_hwnds_from_pid(pid, title):
|
||||
return hwnds
|
||||
|
||||
|
||||
def wait_until(page, condition, timeout=10, poll=0.1, raise_err=True):
|
||||
"""等待返回值不为False或空,直到超时
|
||||
:param page: DrissionPage对象
|
||||
:param condition: 等待条件,返回值不为False则停止等待
|
||||
def wait_until(function, kwargs=None, timeout=10):
|
||||
"""等待传入的方法返回值不为假
|
||||
:param function: 要执行的方法
|
||||
:param kwargs: 方法参数
|
||||
:param timeout: 超时时间(秒)
|
||||
:param poll: 轮询间隔
|
||||
:param raise_err: 是否抛出异常
|
||||
:return: DP Element or bool
|
||||
:return: 执行结果,超时抛出TimeoutError
|
||||
"""
|
||||
if kwargs is None:
|
||||
kwargs = {}
|
||||
end_time = perf_counter() + timeout
|
||||
if isinstance(condition, str) or isinstance(condition, tuple):
|
||||
if not callable(getattr(page, 's_ele', None)):
|
||||
raise AttributeError('page对象缺少s_ele方法')
|
||||
condition_method = lambda page: page.s_ele(condition)
|
||||
elif callable(condition):
|
||||
condition_method = condition
|
||||
else:
|
||||
raise ValueError('condition必须是函数或者字符串或者元组')
|
||||
while perf_counter() < end_time:
|
||||
try:
|
||||
value = condition_method(page)
|
||||
if value:
|
||||
return value
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
sleep(poll)
|
||||
if perf_counter() > end_time:
|
||||
break
|
||||
|
||||
if raise_err:
|
||||
raise TimeoutError(f'等待超时(等待{timeout}秒)。')
|
||||
else:
|
||||
return False
|
||||
value = function(**kwargs)
|
||||
if value:
|
||||
return value
|
||||
raise TimeoutError
|
||||
|
||||
|
||||
def stop_process_on_port(port):
|
||||
@ -215,10 +239,12 @@ def raise_error(result, ignore=None):
|
||||
r = CookieFormatError(f'cookie格式不正确:{result["args"]}')
|
||||
elif error == 'Given expression does not evaluate to a function':
|
||||
r = JavaScriptError(f'传入的js无法解析成函数:\n{result["args"]["functionDeclaration"]}')
|
||||
elif error.endswith("' wasn't found"):
|
||||
r = RuntimeError(f'你的浏览器可能太旧。\n方法:{result["method"]}\n参数:{result["args"]}')
|
||||
elif result['type'] in ('call_method_error', 'timeout'):
|
||||
from DrissionPage import __version__
|
||||
from time import process_time
|
||||
txt = f'\n错误:{result["error"]}\nmethod:{result["method"]}\nargs:{result["args"]}\n' \
|
||||
txt = f'\n错误:{result["error"]}\n方法:{result["method"]}\n参数:{result["args"]}\n' \
|
||||
f'版本:{__version__}\n运行时间:{process_time()}\n出现这个错误可能意味着程序有bug,请把错误信息和重现方法' \
|
||||
'告知作者,谢谢。\n报告网站:https://gitee.com/g1879/DrissionPage/issues'
|
||||
r = TimeoutError(txt) if result['type'] == 'timeout' else CDPError(txt)
|
||||
|
@ -7,12 +7,23 @@
|
||||
"""
|
||||
from os import popen
|
||||
from pathlib import Path
|
||||
from typing import Union
|
||||
from types import FunctionType
|
||||
from threading import Lock
|
||||
from typing import Union, Tuple
|
||||
|
||||
from .._pages.chromium_page import ChromiumPage
|
||||
|
||||
|
||||
class PortFinder(object):
|
||||
used_port: dict = ...
|
||||
lock: Lock = ...
|
||||
tmp_dir: Path = ...
|
||||
|
||||
def __init__(self, path: Union[str, Path] = None): ...
|
||||
|
||||
@staticmethod
|
||||
def get_port(scope: Tuple[int, int] = None) -> Tuple[int, str]: ...
|
||||
|
||||
|
||||
def port_is_using(ip: str, port: Union[str, int]) -> bool: ...
|
||||
|
||||
|
||||
@ -25,10 +36,10 @@ def show_or_hide_browser(page: ChromiumPage, hide: bool = True) -> None: ...
|
||||
def get_browser_progress_id(progress: Union[popen, None], address: str) -> Union[str, None]: ...
|
||||
|
||||
|
||||
def get_chrome_hwnds_from_pid(pid: Union[str, int], title: str) -> list: ...
|
||||
def get_hwnds_from_pid(pid: Union[str, int], title: str) -> list: ...
|
||||
|
||||
|
||||
def wait_until(page, condition: Union[FunctionType, str, tuple], timeout: float, poll: float, raise_err: bool): ...
|
||||
def wait_until(function: callable, kwargs: dict = None, timeout: float = 10): ...
|
||||
|
||||
|
||||
def stop_process_on_port(port: Union[int, str]) -> None: ...
|
||||
|
@ -161,8 +161,8 @@ def is_js_func(func):
|
||||
func = func.strip()
|
||||
if (func.startswith('function') or func.startswith('async ')) and func.endswith('}'):
|
||||
return True
|
||||
elif '=>' in func:
|
||||
return True
|
||||
# elif '=>' in func:
|
||||
# return True
|
||||
return False
|
||||
|
||||
|
||||
@ -328,3 +328,38 @@ def is_cookie_in_driver(page, cookie):
|
||||
if cookie['name'] == c['name'] and cookie['value'] == c['value']:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def get_blob(page, url, as_bytes=True):
|
||||
"""获取知道blob资源
|
||||
:param page: 资源所在页面对象
|
||||
:param url: 资源url
|
||||
:param as_bytes: 是否以字节形式返回
|
||||
:return: 资源内容
|
||||
"""
|
||||
if not url.startswith('blob'):
|
||||
raise TypeError('该链接非blob类型。')
|
||||
js = """
|
||||
function fetchData(url) {
|
||||
return new Promise((resolve, reject) => {
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.responseType = 'blob';
|
||||
xhr.onload = function() {
|
||||
var reader = new FileReader();
|
||||
reader.onloadend = function(){resolve(reader.result);}
|
||||
reader.readAsDataURL(xhr.response);
|
||||
};
|
||||
xhr.open('GET', url, true);
|
||||
xhr.send();
|
||||
});
|
||||
}
|
||||
"""
|
||||
try:
|
||||
result = page.run_js(js, url)
|
||||
except:
|
||||
raise RuntimeError('无法获取该资源。')
|
||||
if as_bytes:
|
||||
from base64 import b64decode
|
||||
return b64decode(result.split(',', 1)[-1])
|
||||
else:
|
||||
return result
|
||||
|
@ -47,3 +47,6 @@ def set_browser_cookies(page: ChromiumBase, cookies: Union[RequestsCookieJar, li
|
||||
|
||||
|
||||
def is_cookie_in_driver(page: ChromiumBase, cookie: dict) -> bool: ...
|
||||
|
||||
|
||||
def get_blob(page: ChromiumBase, url: str, as_bytes: bool = True) -> bytes: ...
|
||||
|
@ -16,7 +16,7 @@ from urllib.parse import quote
|
||||
from DataRecorder.tools import make_valid_name
|
||||
|
||||
from .._base.base import BasePage
|
||||
from .._elements.chromium_element import ChromiumElement, run_js, make_chromium_eles
|
||||
from .._elements.chromium_element import run_js, make_chromium_eles
|
||||
from .._elements.none_element import NoneElement
|
||||
from .._elements.session_element import make_session_ele
|
||||
from .._functions.locator import get_loc, is_loc
|
||||
@ -62,6 +62,7 @@ class ChromiumBase(BasePage):
|
||||
self._download_path = None
|
||||
self._load_end_time = 0
|
||||
self._init_jss = []
|
||||
self._type = 'ChromiumBase'
|
||||
if not hasattr(self, '_listener'):
|
||||
self._listener = None
|
||||
|
||||
@ -244,15 +245,15 @@ class ChromiumBase(BasePage):
|
||||
self.run_cdp('Page.setInterceptFileChooserDialog', enabled=False)
|
||||
self._upload_list = None
|
||||
|
||||
def __call__(self, loc_or_str, index=1, timeout=None):
|
||||
def __call__(self, locator, index=1, timeout=None):
|
||||
"""在内部查找元素
|
||||
例:ele = page('@id=ele_id')
|
||||
:param loc_or_str: 元素的定位信息,可以是loc元组,或查询字符串
|
||||
:param locator: 元素的定位信息,可以是loc元组,或查询字符串
|
||||
:param index: 获取第几个元素,从1开始,可传入负数获取倒数第几个
|
||||
:param timeout: 超时时间(秒)
|
||||
:return: ChromiumElement对象
|
||||
"""
|
||||
return self.ele(loc_or_str, index, timeout)
|
||||
return self.ele(locator, index, timeout)
|
||||
|
||||
def _wait_to_stop(self):
|
||||
"""eager策略超时时使页面停止加载"""
|
||||
@ -473,8 +474,8 @@ class ChromiumBase(BasePage):
|
||||
show_errmsg=show_errmsg, timeout=timeout)
|
||||
return self._url_available
|
||||
|
||||
def get_cookies(self, as_dict=False, all_domains=False, all_info=False):
|
||||
"""获取cookies信息
|
||||
def cookies(self, as_dict=False, all_domains=False, all_info=False):
|
||||
"""返回cookies信息
|
||||
:param as_dict: 为True时返回由{name: value}键值对组成的dict,为True时返回list且all_info无效
|
||||
:param all_domains: 是否返回所有域的cookies
|
||||
:param all_info: 是否返回所有信息,为False时只返回name、value、domain
|
||||
@ -491,60 +492,60 @@ class ChromiumBase(BasePage):
|
||||
return [{'name': cookie['name'], 'value': cookie['value'], 'domain': cookie['domain']}
|
||||
for cookie in cookies]
|
||||
|
||||
def ele(self, loc_or_ele, index=1, timeout=None):
|
||||
def ele(self, locator, index=1, timeout=None):
|
||||
"""获取一个符合条件的元素对象
|
||||
:param loc_or_ele: 定位符或元素对象
|
||||
:param locator: 定位符或元素对象
|
||||
:param index: 获取第几个元素,从1开始,可传入负数获取倒数第几个
|
||||
:param timeout: 查找超时时间(秒)
|
||||
:return: ChromiumElement对象
|
||||
"""
|
||||
return self._ele(loc_or_ele, timeout=timeout, index=index, method='ele()')
|
||||
return self._ele(locator, timeout=timeout, index=index, method='ele()')
|
||||
|
||||
def eles(self, loc_or_str, timeout=None):
|
||||
def eles(self, locator, timeout=None):
|
||||
"""获取所有符合条件的元素对象
|
||||
:param loc_or_str: 定位符或元素对象
|
||||
:param locator: 定位符或元素对象
|
||||
:param timeout: 查找超时时间(秒)
|
||||
:return: ChromiumElement对象组成的列表
|
||||
"""
|
||||
return self._ele(loc_or_str, timeout=timeout, index=None)
|
||||
return self._ele(locator, timeout=timeout, index=None)
|
||||
|
||||
def s_ele(self, loc_or_ele=None, index=1):
|
||||
def s_ele(self, locator=None, index=1):
|
||||
"""查找一个符合条件的元素以SessionElement形式返回,处理复杂页面时效率很高
|
||||
:param loc_or_ele: 元素的定位信息,可以是loc元组,或查询字符串
|
||||
:param locator: 元素的定位信息,可以是loc元组,或查询字符串
|
||||
:param index: 获取第几个,从1开始,可传入负数获取倒数第几个
|
||||
:return: SessionElement对象或属性、文本
|
||||
"""
|
||||
r = make_session_ele(self, loc_or_ele, index=index)
|
||||
r = make_session_ele(self, locator, index=index)
|
||||
if isinstance(r, NoneElement):
|
||||
if Settings.raise_when_ele_not_found:
|
||||
raise ElementNotFoundError(None, 's_ele()', {'loc_or_ele': loc_or_ele})
|
||||
raise ElementNotFoundError(None, 's_ele()', {'locator': locator})
|
||||
else:
|
||||
r.method = 's_ele()'
|
||||
r.args = {'loc_or_ele': loc_or_ele}
|
||||
r.args = {'locator': locator}
|
||||
return r
|
||||
|
||||
def s_eles(self, loc_or_str):
|
||||
def s_eles(self, locator):
|
||||
"""查找所有符合条件的元素以SessionElement列表形式返回
|
||||
:param loc_or_str: 元素的定位信息,可以是loc元组,或查询字符串
|
||||
:param locator: 元素的定位信息,可以是loc元组,或查询字符串
|
||||
:return: SessionElement对象组成的列表
|
||||
"""
|
||||
return make_session_ele(self, loc_or_str, index=None)
|
||||
return make_session_ele(self, locator, index=None)
|
||||
|
||||
def _find_elements(self, loc_or_ele, timeout=None, index=1, relative=False, raise_err=None):
|
||||
def _find_elements(self, locator, timeout=None, index=1, relative=False, raise_err=None):
|
||||
"""执行元素查找
|
||||
:param loc_or_ele: 定位符或元素对象
|
||||
:param locator: 定位符或元素对象
|
||||
:param timeout: 查找超时时间(秒)
|
||||
:param index: 第几个结果,从1开始,可传入负数获取倒数第几个,为None返回所有
|
||||
:param relative: WebPage用的表示是否相对定位的参数
|
||||
:param raise_err: 找不到元素是是否抛出异常,为None时根据全局设置
|
||||
:return: ChromiumElement对象或元素对象组成的列表
|
||||
"""
|
||||
if isinstance(loc_or_ele, (str, tuple)):
|
||||
loc = get_loc(loc_or_ele)[1]
|
||||
elif isinstance(loc_or_ele, ChromiumElement) or str(type(loc_or_ele)).endswith(".ChromiumFrame'>"):
|
||||
return loc_or_ele
|
||||
if isinstance(locator, (str, tuple)):
|
||||
loc = get_loc(locator)[1]
|
||||
elif locator._type in ('ChromiumElement', 'ChromiumFrame'):
|
||||
return locator
|
||||
else:
|
||||
raise ValueError('loc_or_str参数只能是tuple、str、ChromiumElement类型。')
|
||||
raise ValueError('locator参数只能是tuple、str、ChromiumElement类型。')
|
||||
|
||||
self.wait.doc_loaded()
|
||||
timeout = timeout if timeout is not None else self.timeout
|
||||
@ -650,11 +651,13 @@ class ChromiumBase(BasePage):
|
||||
"""页面停止加载"""
|
||||
try:
|
||||
self.run_cdp('Page.stopLoading')
|
||||
end_time = perf_counter() + 5
|
||||
while self._ready_state != 'complete' and perf_counter() < end_time:
|
||||
sleep(.1)
|
||||
except (PageDisconnectedError, CDPError):
|
||||
pass
|
||||
end_time = perf_counter() + self.timeouts.page_load
|
||||
while self._ready_state != 'complete' and perf_counter() < end_time:
|
||||
sleep(.1)
|
||||
finally:
|
||||
self._ready_state = 'complete'
|
||||
|
||||
def remove_ele(self, loc_or_ele):
|
||||
"""从页面上删除一个元素
|
||||
@ -680,13 +683,13 @@ class ChromiumBase(BasePage):
|
||||
else:
|
||||
xpath = loc_ind_ele
|
||||
ele = self._ele(xpath, timeout=timeout)
|
||||
if ele and not str(type(ele)).endswith(".ChromiumFrame'>"):
|
||||
if ele and ele._type != 'ChromiumFrame':
|
||||
raise TypeError('该定位符不是指向frame元素。')
|
||||
r = ele
|
||||
|
||||
elif isinstance(loc_ind_ele, tuple):
|
||||
ele = self._ele(loc_ind_ele, timeout=timeout)
|
||||
if ele and not str(type(ele)).endswith(".ChromiumFrame'>"):
|
||||
if ele and ele._type != 'ChromiumFrame':
|
||||
raise TypeError('该定位符不是指向frame元素。')
|
||||
r = ele
|
||||
|
||||
@ -698,7 +701,7 @@ class ChromiumBase(BasePage):
|
||||
xpath = f'xpath:(//*[name()="frame" or name()="iframe"])[{loc_ind_ele}]'
|
||||
r = self._ele(xpath, timeout=timeout)
|
||||
|
||||
elif str(type(loc_ind_ele)).endswith(".ChromiumFrame'>"):
|
||||
elif loc_ind_ele._type == 'ChromiumFrame':
|
||||
r = loc_ind_ele
|
||||
|
||||
else:
|
||||
@ -709,18 +712,18 @@ class ChromiumBase(BasePage):
|
||||
r.args = {'loc_ind_ele': loc_ind_ele}
|
||||
return r
|
||||
|
||||
def get_frames(self, loc=None, timeout=None):
|
||||
def get_frames(self, locator=None, timeout=None):
|
||||
"""获取所有符合条件的frame对象
|
||||
:param loc: 定位符,为None时返回所有
|
||||
:param locator: 定位符,为None时返回所有
|
||||
:param timeout: 查找超时时间(秒)
|
||||
:return: ChromiumFrame对象组成的列表
|
||||
"""
|
||||
loc = loc or 'xpath://*[name()="iframe" or name()="frame"]'
|
||||
frames = self._ele(loc, timeout=timeout, index=None, raise_err=False)
|
||||
return [i for i in frames if str(type(i)).endswith(".ChromiumFrame'>")]
|
||||
locator = locator or 'xpath://*[name()="iframe" or name()="frame"]'
|
||||
frames = self._ele(locator, timeout=timeout, index=None, raise_err=False)
|
||||
return [i for i in frames if i._type == 'ChromiumFrame']
|
||||
|
||||
def get_session_storage(self, item=None):
|
||||
"""获取sessionStorage信息,不设置item则获取全部
|
||||
def session_storage(self, item=None):
|
||||
"""返回sessionStorage信息,不设置item则获取全部
|
||||
:param item: 要获取的项,不设置则返回全部
|
||||
:return: sessionStorage一个或所有项内容
|
||||
"""
|
||||
@ -740,8 +743,8 @@ class ChromiumBase(BasePage):
|
||||
'''
|
||||
return {i['key']: i['val'] for i in self.run_js_loaded(js)}
|
||||
|
||||
def get_local_storage(self, item=None):
|
||||
"""获取localStorage信息,不设置item则获取全部
|
||||
def local_storage(self, item=None):
|
||||
"""返回localStorage信息,不设置item则获取全部
|
||||
:param item: 要获取的项目,不设置则返回全部
|
||||
:return: localStorage一个或所有项内容
|
||||
"""
|
||||
@ -826,7 +829,17 @@ class ChromiumBase(BasePage):
|
||||
def disconnect(self):
|
||||
"""断开与页面的连接,不关闭页面"""
|
||||
if self._driver:
|
||||
self.driver.stop()
|
||||
self.browser.stop_driver(self._driver)
|
||||
|
||||
def reconnect(self, wait=0):
|
||||
"""断开与页面原来的页面,重新建立连接
|
||||
:param wait: 断开后等待若干秒再连接
|
||||
:return: None
|
||||
"""
|
||||
t_id = self._target_id
|
||||
self.disconnect()
|
||||
sleep(wait)
|
||||
self._driver = self.browser._get_driver(t_id, self)
|
||||
|
||||
def handle_alert(self, accept=True, send=None, timeout=None, next_one=False):
|
||||
r = self._handle_alert(accept=accept, send=send, timeout=timeout, next_one=next_one)
|
||||
@ -917,7 +930,11 @@ class ChromiumBase(BasePage):
|
||||
:param interval: 重试间隔
|
||||
:return: 重试次数和间隔组成的tuple
|
||||
"""
|
||||
self._url = quote(url, safe='-_.~!*\'"();:@&=+$,/\\?#[]%') or 'chrome://newtab/'
|
||||
p = Path(url)
|
||||
if p.exists():
|
||||
self._url = str(p.absolute())
|
||||
else:
|
||||
self._url = quote(url, safe='-_.~!*\'"();:@&=+$,/\\?#[]%') or 'chrome://newtab/'
|
||||
retry = retry if retry is not None else self.retry_times
|
||||
interval = interval if interval is not None else self.retry_interval
|
||||
return retry, interval
|
||||
@ -1020,11 +1037,12 @@ class ChromiumBase(BasePage):
|
||||
pic_type = path.suffix.lower()
|
||||
pic_type = 'jpeg' if pic_type == '.jpg' else pic_type[1:]
|
||||
|
||||
width, height = self.rect.size
|
||||
if full_page:
|
||||
width, height = self.rect.size
|
||||
if width == 0 or height == 0:
|
||||
raise RuntimeError('页面大小为0,请尝试等待页面加载完成。')
|
||||
vp = {'x': 0, 'y': 0, 'width': width, 'height': height, 'scale': 1}
|
||||
png = self.run_cdp_loaded('Page.captureScreenshot', format=pic_type,
|
||||
captureBeyondViewport=True, clip=vp)['data']
|
||||
args = {'format': pic_type, 'captureBeyondViewport': True, 'clip': vp}
|
||||
else:
|
||||
if left_top and right_bottom:
|
||||
x, y = left_top
|
||||
@ -1038,11 +1056,14 @@ class ChromiumBase(BasePage):
|
||||
x += 10
|
||||
|
||||
vp = {'x': x, 'y': y, 'width': w, 'height': h, 'scale': 1}
|
||||
png = self.run_cdp_loaded('Page.captureScreenshot', format=pic_type,
|
||||
captureBeyondViewport=v, clip=vp)['data']
|
||||
args = {'format': pic_type, 'captureBeyondViewport': v, 'clip': vp}
|
||||
|
||||
else:
|
||||
png = self.run_cdp_loaded('Page.captureScreenshot', format=pic_type)['data']
|
||||
args = {'format': pic_type}
|
||||
|
||||
if pic_type == 'jpeg':
|
||||
args['quality'] = 100
|
||||
png = self.run_cdp_loaded('Page.captureScreenshot', **args)['data']
|
||||
|
||||
if as_base64:
|
||||
return png
|
||||
@ -1082,6 +1103,15 @@ class ChromiumBase(BasePage):
|
||||
"""返回页面总宽高,格式:(宽, 高)"""
|
||||
return self.rect.size
|
||||
|
||||
def get_session_storage(self, item=None):
|
||||
return self.session_storage(item)
|
||||
|
||||
def get_local_storage(self, item=None):
|
||||
return self.local_storage(item)
|
||||
|
||||
def get_cookies(self, as_dict=False, all_domains=False, all_info=False):
|
||||
return self.cookies(as_dict=as_dict, all_domains=all_domains, all_info=all_info)
|
||||
|
||||
|
||||
class Timeout(object):
|
||||
"""用于保存d模式timeout信息的类"""
|
||||
|
@ -13,7 +13,6 @@ from .._base.base import BasePage
|
||||
from .._base.browser import Browser
|
||||
from .._base.driver import Driver
|
||||
from .._elements.chromium_element import ChromiumElement
|
||||
from .._elements.none_element import NoneElement
|
||||
from .._elements.session_element import SessionElement
|
||||
from .._pages.chromium_frame import ChromiumFrame
|
||||
from .._pages.chromium_page import ChromiumPage
|
||||
@ -62,6 +61,7 @@ class ChromiumBase(BasePage):
|
||||
self._init_jss: list = ...
|
||||
self._ready_state: Optional[str] = ...
|
||||
self._rect: TabRect = ...
|
||||
self._type: str = ...
|
||||
|
||||
def _connect_browser(self, tab_id: str = None) -> None: ...
|
||||
|
||||
@ -94,9 +94,9 @@ class ChromiumBase(BasePage):
|
||||
def _d_set_runtime_settings(self) -> None: ...
|
||||
|
||||
def __call__(self,
|
||||
loc_or_str: Union[Tuple[str, str], str, ChromiumElement],
|
||||
locator: Union[Tuple[str, str], str, ChromiumElement],
|
||||
index: int = 1,
|
||||
timeout: float = None) -> Union[ChromiumElement, NoneElement]: ...
|
||||
timeout: float = None) -> ChromiumElement: ...
|
||||
|
||||
@property
|
||||
def _js_ready_state(self) -> str: ...
|
||||
@ -176,31 +176,30 @@ class ChromiumBase(BasePage):
|
||||
def get(self, url: str, show_errmsg: bool = False, retry: int = None,
|
||||
interval: float = None, timeout: float = None) -> Union[None, bool]: ...
|
||||
|
||||
def get_cookies(self, as_dict: bool = False, all_domains: bool = False,
|
||||
all_info: bool = False) -> Union[list, dict]: ...
|
||||
def cookies(self, as_dict: bool = False, all_domains: bool = False, all_info: bool = False) -> Union[list, dict]: ...
|
||||
|
||||
def ele(self,
|
||||
loc_or_ele: Union[Tuple[str, str], str, ChromiumElement, ChromiumFrame],
|
||||
locator: Union[Tuple[str, str], str, ChromiumElement, ChromiumFrame],
|
||||
index: int = 1,
|
||||
timeout: float = None) -> Union[ChromiumElement, NoneElement]: ...
|
||||
timeout: float = None) -> ChromiumElement: ...
|
||||
|
||||
def eles(self,
|
||||
loc_or_str: Union[Tuple[str, str], str],
|
||||
locator: Union[Tuple[str, str], str],
|
||||
timeout: float = None) -> List[ChromiumElement]: ...
|
||||
|
||||
def s_ele(self,
|
||||
loc_or_ele: Union[Tuple[str, str], str] = None,
|
||||
index:int = 1) -> Union[SessionElement, NoneElement]: ...
|
||||
locator: Union[Tuple[str, str], str] = None,
|
||||
index: int = 1) -> SessionElement: ...
|
||||
|
||||
def s_eles(self, loc_or_str: Union[Tuple[str, str], str]) -> List[SessionElement]: ...
|
||||
def s_eles(self, locator: Union[Tuple[str, str], str]) -> List[SessionElement]: ...
|
||||
|
||||
def _find_elements(self,
|
||||
loc_or_ele: Union[Tuple[str, str], str, ChromiumElement, ChromiumFrame],
|
||||
locator: Union[Tuple[str, str], str, ChromiumElement, ChromiumFrame],
|
||||
timeout: float = None,
|
||||
index: Optional[int] = 1,
|
||||
relative: bool = False,
|
||||
raise_err: bool = None) \
|
||||
-> Union[ChromiumElement, ChromiumFrame, NoneElement, List[Union[ChromiumElement, ChromiumFrame]]]: ...
|
||||
-> Union[ChromiumElement, ChromiumFrame, List[Union[ChromiumElement, ChromiumFrame]]]: ...
|
||||
|
||||
def refresh(self, ignore_cache: bool = False) -> None: ...
|
||||
|
||||
@ -216,15 +215,15 @@ class ChromiumBase(BasePage):
|
||||
|
||||
def get_frame(self, loc_ind_ele: Union[str, int, tuple, ChromiumFrame], timeout: float = None) -> ChromiumFrame: ...
|
||||
|
||||
def get_frames(self, loc: Union[str, tuple] = None, timeout: float = None) -> List[ChromiumFrame]: ...
|
||||
def get_frames(self, locator: Union[str, tuple] = None, timeout: float = None) -> List[ChromiumFrame]: ...
|
||||
|
||||
def run_cdp(self, cmd: str, **cmd_args) -> dict: ...
|
||||
|
||||
def run_cdp_loaded(self, cmd: str, **cmd_args) -> dict: ...
|
||||
|
||||
def get_session_storage(self, item: str = None) -> Union[str, dict, None]: ...
|
||||
def session_storage(self, item: str = None) -> Union[str, dict, None]: ...
|
||||
|
||||
def get_local_storage(self, item: str = None) -> Union[str, dict, None]: ...
|
||||
def local_storage(self, item: str = None) -> Union[str, dict, None]: ...
|
||||
|
||||
def add_init_js(self, script: str) -> str: ...
|
||||
|
||||
@ -243,6 +242,8 @@ class ChromiumBase(BasePage):
|
||||
|
||||
def disconnect(self) -> None: ...
|
||||
|
||||
def reconnect(self, wait: float = 0) -> None: ...
|
||||
|
||||
def handle_alert(self, accept: bool = True, send: str = None, timeout: float = None,
|
||||
next_one: bool = False) -> Union[str, False]: ...
|
||||
|
||||
|
@ -27,15 +27,14 @@ class ChromiumFrame(ChromiumBase):
|
||||
:param ele: frame所在元素
|
||||
:param info: frame所在元素信息
|
||||
"""
|
||||
page_type = str(type(page))
|
||||
if 'ChromiumPage' in page_type or 'WebPage' in page_type:
|
||||
if page._type in ('ChromiumPage', 'WebPage'):
|
||||
self._page = self._target_page = self.tab = page
|
||||
self._browser = page.browser
|
||||
else: # Tab、Frame
|
||||
self._page = page.page
|
||||
self._browser = self._page.browser
|
||||
self._target_page = page
|
||||
self.tab = page.tab if 'ChromiumFrame' in page_type else page
|
||||
self.tab = page.tab if page._type == 'ChromiumFrame' else page
|
||||
|
||||
self.address = page.address
|
||||
self._tab_id = page.tab_id
|
||||
@ -58,28 +57,28 @@ class ChromiumFrame(ChromiumBase):
|
||||
self.doc_ele = ChromiumElement(self, obj_id=obj_id)
|
||||
|
||||
self._rect = None
|
||||
self._type = 'ChromiumFrame'
|
||||
end_time = perf_counter() + 2
|
||||
while perf_counter() < end_time:
|
||||
if self.url not in (None, 'about:blank'):
|
||||
break
|
||||
sleep(.1)
|
||||
|
||||
def __call__(self, loc_or_str, index=1, timeout=None):
|
||||
def __call__(self, locator, index=1, timeout=None):
|
||||
"""在内部查找元素
|
||||
例:ele2 = ele1('@id=ele_id')
|
||||
:param loc_or_str: 元素的定位信息,可以是loc元组,或查询字符串
|
||||
:param locator: 元素的定位信息,可以是loc元组,或查询字符串
|
||||
:param index: 获取第几个,从1开始,可传入负数获取倒数第几个
|
||||
:param timeout: 超时时间(秒)
|
||||
:return: ChromiumElement对象或属性、文本
|
||||
"""
|
||||
return self.ele(loc_or_str, index=index, timeout=timeout)
|
||||
return self.ele(locator, index=index, timeout=timeout)
|
||||
|
||||
def __eq__(self, other):
|
||||
return self._frame_id == getattr(other, '_frame_id', None)
|
||||
|
||||
def __repr__(self):
|
||||
attrs = self._frame_ele.attrs
|
||||
attrs = [f"{attr}='{attrs[attr]}'" for attr in attrs]
|
||||
attrs = [f"{k}='{v}'" for k, v in self._frame_ele.attrs.items()]
|
||||
return f'<ChromiumFrame {self.frame_ele.tag} {" ".join(attrs)}>'
|
||||
|
||||
def _d_set_runtime_settings(self):
|
||||
@ -146,19 +145,6 @@ class ChromiumFrame(ChromiumBase):
|
||||
if timeout <= 0:
|
||||
timeout = .5
|
||||
self._wait_loaded(timeout)
|
||||
# while perf_counter() < end_time:
|
||||
# try:
|
||||
# obj_id = super().run_js('document;', as_expr=True)['objectId']
|
||||
# self.doc_ele = ChromiumElement(self, obj_id=obj_id)
|
||||
# break
|
||||
# except Exception as e:
|
||||
# sleep(.1)
|
||||
# if self._debug:
|
||||
# print(f'获取doc失败,重试 {e}')
|
||||
# else:
|
||||
# raise GetDocumentError
|
||||
|
||||
# self.driver._debug = d_debug
|
||||
|
||||
self._is_loading = False
|
||||
self._reloading = False
|
||||
@ -208,7 +194,6 @@ class ChromiumFrame(ChromiumBase):
|
||||
self._reload()
|
||||
|
||||
# ----------挂件----------
|
||||
|
||||
@property
|
||||
def scroll(self):
|
||||
"""返回用于滚动的对象"""
|
||||
@ -252,7 +237,7 @@ class ChromiumFrame(ChromiumBase):
|
||||
self._listener = FrameListener(self)
|
||||
return self._listener
|
||||
|
||||
# ----------挂件----------
|
||||
# ----------挂件结束----------
|
||||
|
||||
@property
|
||||
def _obj_id(self):
|
||||
@ -305,11 +290,6 @@ class ChromiumFrame(ChromiumBase):
|
||||
r = self._ele('t:title', raise_err=False)
|
||||
return r.text if r else None
|
||||
|
||||
@property
|
||||
def cookies(self):
|
||||
"""以dict格式返回cookies"""
|
||||
return super().cookies if self._is_diff_domain else self.doc_ele.run_js('return this.cookie;')
|
||||
|
||||
@property
|
||||
def attrs(self):
|
||||
"""返回frame元素所有attribute属性"""
|
||||
@ -356,23 +336,57 @@ class ChromiumFrame(ChromiumBase):
|
||||
except:
|
||||
return None
|
||||
|
||||
# ----------------即将废弃-----------------
|
||||
@property
|
||||
def is_alive(self):
|
||||
"""返回是否仍可用"""
|
||||
return self.states.is_alive
|
||||
|
||||
@property
|
||||
def page_size(self):
|
||||
"""返回frame内页面尺寸,格式:(宽,, 高)"""
|
||||
return self.rect.size
|
||||
|
||||
@property
|
||||
def size(self):
|
||||
"""返回frame元素大小"""
|
||||
return self.frame_ele.rect.size
|
||||
|
||||
@property
|
||||
def location(self):
|
||||
"""返回frame元素左上角的绝对坐标"""
|
||||
return self.frame_ele.rect.location
|
||||
|
||||
@property
|
||||
def locations(self):
|
||||
"""返回用于获取元素位置的对象"""
|
||||
return self.frame_ele.rect
|
||||
# ----------------即将废弃结束-----------------
|
||||
|
||||
def refresh(self):
|
||||
"""刷新frame页面"""
|
||||
self.doc_ele.run_js('this.location.reload();')
|
||||
|
||||
def attr(self, attr):
|
||||
"""返回frame元素attribute属性值
|
||||
:param attr: 属性名
|
||||
def property(self, name):
|
||||
"""返回frame元素一个property属性值
|
||||
:param name: 属性名
|
||||
:return: 属性值文本,没有该属性返回None
|
||||
"""
|
||||
return self.frame_ele.attr(attr)
|
||||
return self.frame_ele.property(name)
|
||||
|
||||
def remove_attr(self, attr):
|
||||
def attr(self, name):
|
||||
"""返回frame元素一个attribute属性值
|
||||
:param name: 属性名
|
||||
:return: 属性值文本,没有该属性返回None
|
||||
"""
|
||||
return self.frame_ele.attr(name)
|
||||
|
||||
def remove_attr(self, name):
|
||||
"""删除frame元素attribute属性
|
||||
:param attr: 属性名
|
||||
:param name: 属性名
|
||||
:return: None
|
||||
"""
|
||||
self.frame_ele.remove_attr(attr)
|
||||
self.frame_ele.remove_attr(name)
|
||||
|
||||
def run_js(self, script, *args, as_expr=False, timeout=None):
|
||||
"""运行javascript代码
|
||||
@ -395,85 +409,85 @@ class ChromiumFrame(ChromiumBase):
|
||||
"""
|
||||
return self.frame_ele.parent(level_or_loc, index)
|
||||
|
||||
def prev(self, filter_loc='', index=1, timeout=0, ele_only=True):
|
||||
def prev(self, locator='', index=1, timeout=0, ele_only=True):
|
||||
"""返回当前元素前面一个符合条件的同级元素,可用查询语法筛选,可指定返回筛选结果的第几个
|
||||
:param filter_loc: 用于筛选的查询语法
|
||||
:param locator: 用于筛选的查询语法
|
||||
:param index: 前面第几个查询结果,1开始
|
||||
:param timeout: 查找节点的超时时间(秒)
|
||||
:param ele_only: 是否只获取元素,为False时把文本、注释节点也纳入
|
||||
:return: 同级元素或节点
|
||||
"""
|
||||
return self.frame_ele.prev(filter_loc, index, timeout, ele_only=ele_only)
|
||||
return self.frame_ele.prev(locator, index, timeout, ele_only=ele_only)
|
||||
|
||||
def next(self, filter_loc='', index=1, timeout=0, ele_only=True):
|
||||
def next(self, locator='', index=1, timeout=0, ele_only=True):
|
||||
"""返回当前元素后面一个符合条件的同级元素,可用查询语法筛选,可指定返回筛选结果的第几个
|
||||
:param filter_loc: 用于筛选的查询语法
|
||||
:param locator: 用于筛选的查询语法
|
||||
:param index: 后面第几个查询结果,1开始
|
||||
:param timeout: 查找节点的超时时间(秒)
|
||||
:param ele_only: 是否只获取元素,为False时把文本、注释节点也纳入
|
||||
:return: 同级元素或节点
|
||||
"""
|
||||
return self.frame_ele.next(filter_loc, index, timeout, ele_only=ele_only)
|
||||
return self.frame_ele.next(locator, index, timeout, ele_only=ele_only)
|
||||
|
||||
def before(self, filter_loc='', index=1, timeout=None, ele_only=True):
|
||||
def before(self, locator='', index=1, timeout=None, ele_only=True):
|
||||
"""返回文档中当前元素前面符合条件的一个元素,可用查询语法筛选,可指定返回筛选结果的第几个
|
||||
查找范围不限同级元素,而是整个DOM文档
|
||||
:param filter_loc: 用于筛选的查询语法
|
||||
:param locator: 用于筛选的查询语法
|
||||
:param index: 前面第几个查询结果,1开始
|
||||
:param timeout: 查找节点的超时时间(秒)
|
||||
:param ele_only: 是否只获取元素,为False时把文本、注释节点也纳入
|
||||
:return: 本元素前面的某个元素或节点
|
||||
"""
|
||||
return self.frame_ele.before(filter_loc, index, timeout, ele_only=ele_only)
|
||||
return self.frame_ele.before(locator, index, timeout, ele_only=ele_only)
|
||||
|
||||
def after(self, filter_loc='', index=1, timeout=None, ele_only=True):
|
||||
def after(self, locator='', index=1, timeout=None, ele_only=True):
|
||||
"""返回文档中此当前元素后面符合条件的一个元素,可用查询语法筛选,可指定返回筛选结果的第几个
|
||||
查找范围不限同级元素,而是整个DOM文档
|
||||
:param filter_loc: 用于筛选的查询语法
|
||||
:param locator: 用于筛选的查询语法
|
||||
:param index: 后面第几个查询结果,1开始
|
||||
:param timeout: 查找节点的超时时间(秒)
|
||||
:param ele_only: 是否只获取元素,为False时把文本、注释节点也纳入
|
||||
:return: 本元素后面的某个元素或节点
|
||||
"""
|
||||
return self.frame_ele.after(filter_loc, index, timeout, ele_only=ele_only)
|
||||
return self.frame_ele.after(locator, index, timeout, ele_only=ele_only)
|
||||
|
||||
def prevs(self, filter_loc='', timeout=0, ele_only=True):
|
||||
def prevs(self, locator='', timeout=0, ele_only=True):
|
||||
"""返回当前元素前面符合条件的同级元素或节点组成的列表,可用查询语法筛选
|
||||
:param filter_loc: 用于筛选的查询语法
|
||||
:param locator: 用于筛选的查询语法
|
||||
:param timeout: 查找节点的超时时间(秒)
|
||||
:param ele_only: 是否只获取元素,为False时把文本、注释节点也纳入
|
||||
:return: 同级元素或节点文本组成的列表
|
||||
"""
|
||||
return self.frame_ele.prevs(filter_loc, timeout, ele_only=ele_only)
|
||||
return self.frame_ele.prevs(locator, timeout, ele_only=ele_only)
|
||||
|
||||
def nexts(self, filter_loc='', timeout=0, ele_only=True):
|
||||
def nexts(self, locator='', timeout=0, ele_only=True):
|
||||
"""返回当前元素后面符合条件的同级元素或节点组成的列表,可用查询语法筛选
|
||||
:param filter_loc: 用于筛选的查询语法
|
||||
:param locator: 用于筛选的查询语法
|
||||
:param timeout: 查找节点的超时时间(秒)
|
||||
:param ele_only: 是否只获取元素,为False时把文本、注释节点也纳入
|
||||
:return: 同级元素或节点文本组成的列表
|
||||
"""
|
||||
return self.frame_ele.nexts(filter_loc, timeout, ele_only=ele_only)
|
||||
return self.frame_ele.nexts(locator, timeout, ele_only=ele_only)
|
||||
|
||||
def befores(self, filter_loc='', timeout=None, ele_only=True):
|
||||
def befores(self, locator='', timeout=None, ele_only=True):
|
||||
"""返回文档中当前元素前面符合条件的元素或节点组成的列表,可用查询语法筛选
|
||||
查找范围不限同级元素,而是整个DOM文档
|
||||
:param filter_loc: 用于筛选的查询语法
|
||||
:param locator: 用于筛选的查询语法
|
||||
:param timeout: 查找节点的超时时间
|
||||
:param ele_only: 是否只获取元素,为False时把文本、注释节点也纳入
|
||||
:return: 本元素前面的元素或节点组成的列表
|
||||
"""
|
||||
return self.frame_ele.befores(filter_loc, timeout, ele_only=ele_only)
|
||||
return self.frame_ele.befores(locator, timeout, ele_only=ele_only)
|
||||
|
||||
def afters(self, filter_loc='', timeout=None, ele_only=True):
|
||||
def afters(self, locator='', timeout=None, ele_only=True):
|
||||
"""返回文档中当前元素后面符合条件的元素或节点组成的列表,可用查询语法筛选
|
||||
查找范围不限同级元素,而是整个DOM文档
|
||||
:param filter_loc: 用于筛选的查询语法
|
||||
:param locator: 用于筛选的查询语法
|
||||
:param timeout: 查找节点的超时时间
|
||||
:param ele_only: 是否只获取元素,为False时把文本、注释节点也纳入
|
||||
:return: 本元素前面的元素或节点组成的列表
|
||||
"""
|
||||
return self.frame_ele.afters(filter_loc, timeout, ele_only=ele_only)
|
||||
return self.frame_ele.afters(locator, timeout, ele_only=ele_only)
|
||||
|
||||
def get_screenshot(self, path=None, name=None, as_bytes=None, as_base64=None):
|
||||
"""对页面进行截图,可对整个网页、可见网页、指定范围截图。对可视范围外截图需要90以上版本浏览器支持
|
||||
@ -562,48 +576,21 @@ class ChromiumFrame(ChromiumBase):
|
||||
self.tab.remove_ele(new_ele)
|
||||
return r
|
||||
|
||||
def _find_elements(self, loc_or_ele, timeout=None, index=1, relative=False, raise_err=None):
|
||||
def _find_elements(self, locator, timeout=None, index=1, relative=False, raise_err=None):
|
||||
"""在frame内查找单个元素
|
||||
:param loc_or_ele: 定位符或元素对象
|
||||
:param locator: 定位符或元素对象
|
||||
:param timeout: 查找超时时间
|
||||
:param index: 第几个结果,从1开始,可传入负数获取倒数第几个,为None返回所有
|
||||
:param relative: WebPage用的表示是否相对定位的参数
|
||||
:param raise_err: 找不到元素是是否抛出异常,为None时根据全局设置
|
||||
:return: ChromiumElement对象
|
||||
"""
|
||||
if isinstance(loc_or_ele, ChromiumElement):
|
||||
return loc_or_ele
|
||||
if isinstance(locator, ChromiumElement):
|
||||
return locator
|
||||
self.wait.doc_loaded()
|
||||
return self.doc_ele._ele(loc_or_ele, index=index, timeout=timeout,
|
||||
raise_err=raise_err) if index is not None else self.doc_ele.eles(loc_or_ele, timeout)
|
||||
return self.doc_ele._ele(locator, index=index, timeout=timeout,
|
||||
raise_err=raise_err) if index is not None else self.doc_ele.eles(locator, timeout)
|
||||
|
||||
def _is_inner_frame(self):
|
||||
"""返回当前frame是否同域"""
|
||||
return self._frame_id in str(self._target_page.run_cdp('Page.getFrameTree')['frameTree'])
|
||||
|
||||
# ----------------即将废弃-----------------
|
||||
|
||||
@property
|
||||
def is_alive(self):
|
||||
"""返回是否仍可用"""
|
||||
return self.states.is_alive
|
||||
|
||||
@property
|
||||
def page_size(self):
|
||||
"""返回frame内页面尺寸,格式:(宽,, 高)"""
|
||||
return self.rect.size
|
||||
|
||||
@property
|
||||
def size(self):
|
||||
"""返回frame元素大小"""
|
||||
return self.frame_ele.rect.size
|
||||
|
||||
@property
|
||||
def location(self):
|
||||
"""返回frame元素左上角的绝对坐标"""
|
||||
return self.frame_ele.rect.location
|
||||
|
||||
@property
|
||||
def locations(self):
|
||||
"""返回用于获取元素位置的对象"""
|
||||
return self.frame_ele.rect
|
||||
|
@ -13,7 +13,6 @@ from .chromium_page import ChromiumPage
|
||||
from .chromium_tab import ChromiumTab
|
||||
from .web_page import WebPage
|
||||
from .._elements.chromium_element import ChromiumElement
|
||||
from .._elements.none_element import NoneElement
|
||||
from .._units.listener import FrameListener
|
||||
from .._units.rect import FrameRect
|
||||
from .._units.scroller import FrameScroller
|
||||
@ -32,6 +31,7 @@ class ChromiumFrame(ChromiumBase):
|
||||
self._target_page: ChromiumBase = ...
|
||||
self.tab: ChromiumTab = ...
|
||||
self._tab_id: str = ...
|
||||
self._set: ChromiumFrameSetter = ...
|
||||
self._frame_ele: ChromiumElement = ...
|
||||
self._backend_id: int = ...
|
||||
self._doc_ele: ChromiumElement = ...
|
||||
@ -43,9 +43,9 @@ class ChromiumFrame(ChromiumBase):
|
||||
self._listener: FrameListener = ...
|
||||
|
||||
def __call__(self,
|
||||
loc_or_str: Union[Tuple[str, str], str],
|
||||
locator: Union[Tuple[str, str], str],
|
||||
index: int = 1,
|
||||
timeout: float = None) -> Union[ChromiumElement, NoneElement]: ...
|
||||
timeout: float = None) -> ChromiumElement: ...
|
||||
|
||||
def __eq__(self, other: ChromiumFrame) -> bool: ...
|
||||
|
||||
@ -86,9 +86,6 @@ class ChromiumFrame(ChromiumBase):
|
||||
@property
|
||||
def title(self) -> str: ...
|
||||
|
||||
@property
|
||||
def cookies(self) -> dict: ...
|
||||
|
||||
@property
|
||||
def attrs(self) -> dict: ...
|
||||
|
||||
@ -133,9 +130,11 @@ class ChromiumFrame(ChromiumBase):
|
||||
|
||||
def refresh(self) -> None: ...
|
||||
|
||||
def attr(self, attr: str) -> Union[str, None]: ...
|
||||
def property(self, name: str) -> Union[str, None]: ...
|
||||
|
||||
def remove_attr(self, attr: str) -> None: ...
|
||||
def attr(self, name: str) -> Union[str, None]: ...
|
||||
|
||||
def remove_attr(self, name: str) -> None: ...
|
||||
|
||||
def run_js(self,
|
||||
script: str,
|
||||
@ -144,50 +143,50 @@ class ChromiumFrame(ChromiumBase):
|
||||
timeout: float = None) -> Any: ...
|
||||
|
||||
def parent(self,
|
||||
level_or_loc: Union[tuple, str, int] = 1,
|
||||
index: int = 1) -> Union[ChromiumElement, NoneElement]: ...
|
||||
level_or_loc: Union[Tuple[str, str], str, int] = 1,
|
||||
index: int = 1) -> ChromiumElement: ...
|
||||
|
||||
def prev(self,
|
||||
filter_loc: Union[tuple, str, int] = '',
|
||||
locator: Union[Tuple[str, str], str, int] = '',
|
||||
index: int = 1,
|
||||
timeout: float = 0,
|
||||
ele_only: bool = True) -> Union[ChromiumElement, NoneElement, str]: ...
|
||||
ele_only: bool = True) -> Union[ChromiumElement, str]: ...
|
||||
|
||||
def next(self,
|
||||
filter_loc: Union[tuple, str, int] = '',
|
||||
locator: Union[Tuple[str, str], str, int] = '',
|
||||
index: int = 1,
|
||||
timeout: float = 0,
|
||||
ele_only: bool = True) -> Union[ChromiumElement, NoneElement, str]: ...
|
||||
ele_only: bool = True) -> Union[ChromiumElement, str]: ...
|
||||
|
||||
def before(self,
|
||||
filter_loc: Union[tuple, str, int] = '',
|
||||
locator: Union[Tuple[str, str], str, int] = '',
|
||||
index: int = 1,
|
||||
timeout: float = None,
|
||||
ele_only: bool = True) -> Union[ChromiumElement, NoneElement, str]: ...
|
||||
ele_only: bool = True) -> Union[ChromiumElement, str]: ...
|
||||
|
||||
def after(self,
|
||||
filter_loc: Union[tuple, str, int] = '',
|
||||
locator: Union[Tuple[str, str], str, int] = '',
|
||||
index: int = 1,
|
||||
timeout: float = None,
|
||||
ele_only: bool = True) -> Union[ChromiumElement, NoneElement, str]: ...
|
||||
ele_only: bool = True) -> Union[ChromiumElement, str]: ...
|
||||
|
||||
def prevs(self,
|
||||
filter_loc: Union[tuple, str] = '',
|
||||
locator: Union[Tuple[str, str], str] = '',
|
||||
timeout: float = 0,
|
||||
ele_only: bool = True) -> List[Union[ChromiumElement, str]]: ...
|
||||
|
||||
def nexts(self,
|
||||
filter_loc: Union[tuple, str] = '',
|
||||
locator: Union[Tuple[str, str], str] = '',
|
||||
timeout: float = 0,
|
||||
ele_only: bool = True) -> List[Union[ChromiumElement, str]]: ...
|
||||
|
||||
def befores(self,
|
||||
filter_loc: Union[tuple, str] = '',
|
||||
locator: Union[Tuple[str, str], str] = '',
|
||||
timeout: float = None,
|
||||
ele_only: bool = True) -> List[Union[ChromiumElement, str]]: ...
|
||||
|
||||
def afters(self,
|
||||
filter_loc: Union[tuple, str] = '',
|
||||
locator: Union[Tuple[str, str], str] = '',
|
||||
timeout: float = None,
|
||||
ele_only: bool = True) -> List[Union[ChromiumElement, str]]: ...
|
||||
|
||||
@ -208,7 +207,7 @@ class ChromiumFrame(ChromiumBase):
|
||||
ele: ChromiumElement = None) -> Union[str, bytes]: ...
|
||||
|
||||
def _find_elements(self,
|
||||
loc_or_ele: Union[Tuple[str, str], str, ChromiumElement, ChromiumFrame],
|
||||
locator: Union[Tuple[str, str], str, ChromiumElement, ChromiumFrame],
|
||||
timeout: float = None,
|
||||
index: Optional[int] = 1,
|
||||
relative: bool = False,
|
||||
|
@ -6,13 +6,15 @@
|
||||
@License : BSD 3-Clause.
|
||||
"""
|
||||
from pathlib import Path
|
||||
from threading import Lock
|
||||
from time import sleep, perf_counter
|
||||
|
||||
from requests import get
|
||||
|
||||
from .._base.browser import Browser
|
||||
from .._configs.chromium_options import ChromiumOptions
|
||||
from .._functions.browser import connect_browser
|
||||
from .._configs.chromium_options import ChromiumOptions, PortFinder
|
||||
from .._functions.tools import PortFinder
|
||||
from .._pages.chromium_base import ChromiumBase, get_mhtml, get_pdf, Timeout
|
||||
from .._pages.chromium_tab import ChromiumTab
|
||||
from .._units.setter import ChromiumPageSetter
|
||||
@ -22,7 +24,7 @@ from ..errors import BrowserConnectError
|
||||
|
||||
class ChromiumPage(ChromiumBase):
|
||||
"""用于管理浏览器的类"""
|
||||
PAGES = {}
|
||||
_PAGES = {}
|
||||
|
||||
def __new__(cls, addr_or_opts=None, tab_id=None, timeout=None, addr_driver_opts=None):
|
||||
"""
|
||||
@ -33,14 +35,17 @@ class ChromiumPage(ChromiumBase):
|
||||
addr_or_opts = addr_or_opts or addr_driver_opts
|
||||
opt = handle_options(addr_or_opts)
|
||||
is_exist, browser_id = run_browser(opt)
|
||||
if browser_id in cls.PAGES:
|
||||
return cls.PAGES[browser_id]
|
||||
if browser_id in cls._PAGES:
|
||||
r = cls._PAGES[browser_id]
|
||||
while not hasattr(r, '_frame_id'):
|
||||
sleep(.1)
|
||||
return r
|
||||
r = object.__new__(cls)
|
||||
r._chromium_options = opt
|
||||
r._is_exist = is_exist
|
||||
r._browser_id = browser_id
|
||||
r.address = opt.address
|
||||
cls.PAGES[browser_id] = r
|
||||
cls._PAGES[browser_id] = r
|
||||
return r
|
||||
|
||||
def __init__(self, addr_or_opts=None, tab_id=None, timeout=None, addr_driver_opts=None):
|
||||
@ -56,6 +61,8 @@ class ChromiumPage(ChromiumBase):
|
||||
self._page = self
|
||||
self._run_browser()
|
||||
super().__init__(self.address, tab_id)
|
||||
self._type = 'ChromiumPage'
|
||||
self._lock = Lock()
|
||||
self.set.timeouts(base=timeout)
|
||||
self._page_init()
|
||||
|
||||
@ -72,7 +79,7 @@ class ChromiumPage(ChromiumBase):
|
||||
|
||||
def _d_set_runtime_settings(self):
|
||||
"""设置运行时用到的属性"""
|
||||
self._timeouts = Timeout(self, page_load=self._chromium_options.timeouts['pageLoad'],
|
||||
self._timeouts = Timeout(self, page_load=self._chromium_options.timeouts['page_load'],
|
||||
script=self._chromium_options.timeouts['script'],
|
||||
base=self._chromium_options.timeouts['base'])
|
||||
if self._chromium_options.timeouts['base'] is not None:
|
||||
@ -145,16 +152,17 @@ class ChromiumPage(ChromiumBase):
|
||||
:param id_or_num: 要获取的标签页id或序号,为None时获取当前tab,序号从1开始,可传入负数获取倒数第几个,不是视觉排列顺序,而是激活顺序
|
||||
:return: 标签页对象
|
||||
"""
|
||||
if isinstance(id_or_num, str):
|
||||
return ChromiumTab(self, id_or_num)
|
||||
elif isinstance(id_or_num, int):
|
||||
return ChromiumTab(self, self.tabs[id_or_num - 1 if id_or_num > 0 else id_or_num])
|
||||
elif id_or_num is None:
|
||||
return ChromiumTab(self, self.tab_id)
|
||||
elif isinstance(id_or_num, ChromiumTab):
|
||||
return id_or_num
|
||||
else:
|
||||
raise TypeError(f'id_or_num需传入tab id或序号,非{id_or_num}。')
|
||||
with self._lock:
|
||||
if isinstance(id_or_num, str):
|
||||
return ChromiumTab(self, id_or_num)
|
||||
elif isinstance(id_or_num, int):
|
||||
return ChromiumTab(self, self.tabs[id_or_num - 1 if id_or_num > 0 else id_or_num])
|
||||
elif id_or_num is None:
|
||||
return ChromiumTab(self, self.tab_id)
|
||||
elif isinstance(id_or_num, ChromiumTab):
|
||||
return id_or_num
|
||||
else:
|
||||
raise TypeError(f'id_or_num需传入tab id或序号,非{id_or_num}。')
|
||||
|
||||
def find_tabs(self, title=None, url=None, tab_type=None, single=True):
|
||||
"""查找符合条件的tab,返回它们的id组成的列表
|
||||
@ -202,7 +210,7 @@ class ChromiumPage(ChromiumBase):
|
||||
|
||||
def close(self):
|
||||
"""关闭Page管理的标签页"""
|
||||
self.browser.close_tab(self.tab_id)
|
||||
self.close_tabs(self.tab_id)
|
||||
|
||||
def close_tabs(self, tabs_or_ids=None, others=False):
|
||||
"""关闭传入的标签页,默认关闭当前页。可传入多个
|
||||
@ -247,7 +255,7 @@ class ChromiumPage(ChromiumBase):
|
||||
|
||||
def _on_disconnect(self):
|
||||
"""浏览器退出时执行"""
|
||||
ChromiumPage.PAGES.pop(self._browser_id, None)
|
||||
ChromiumPage._PAGES.pop(self._browser_id, None)
|
||||
|
||||
def __repr__(self):
|
||||
return f'<ChromiumPage browser_id={self.browser.id} tab_id={self.tab_id}>'
|
||||
@ -268,13 +276,18 @@ def handle_options(addr_or_opts):
|
||||
"""
|
||||
if not addr_or_opts:
|
||||
_chromium_options = ChromiumOptions(addr_or_opts)
|
||||
if _chromium_options.is_auto_port:
|
||||
port, path = PortFinder(_chromium_options.tmp_path).get_port(_chromium_options.is_auto_port)
|
||||
_chromium_options.set_address(f'127.0.0.1:{port}')
|
||||
_chromium_options.set_user_data_path(path)
|
||||
_chromium_options.auto_port(scope=_chromium_options.is_auto_port)
|
||||
|
||||
elif isinstance(addr_or_opts, ChromiumOptions):
|
||||
if addr_or_opts.is_auto_port:
|
||||
port, path = PortFinder(addr_or_opts.tmp_path).get_port()
|
||||
port, path = PortFinder(addr_or_opts.tmp_path).get_port(addr_or_opts.is_auto_port)
|
||||
addr_or_opts.set_address(f'127.0.0.1:{port}')
|
||||
addr_or_opts.set_user_data_path(path)
|
||||
addr_or_opts.auto_port()
|
||||
addr_or_opts.auto_port(scope=addr_or_opts.is_auto_port)
|
||||
_chromium_options = addr_or_opts
|
||||
|
||||
elif isinstance(addr_or_opts, str):
|
||||
|
@ -6,6 +6,7 @@
|
||||
@License : BSD 3-Clause.
|
||||
"""
|
||||
from pathlib import Path
|
||||
from threading import Lock
|
||||
from typing import Union, Tuple, List, Optional
|
||||
|
||||
from .._base.browser import Browser
|
||||
@ -18,7 +19,7 @@ from .._units.waiter import PageWaiter
|
||||
|
||||
|
||||
class ChromiumPage(ChromiumBase):
|
||||
PAGES: dict = ...
|
||||
_PAGES: dict = ...
|
||||
|
||||
def __new__(cls,
|
||||
addr_or_opts: Union[str, int, ChromiumOptions] = None,
|
||||
@ -34,6 +35,7 @@ class ChromiumPage(ChromiumBase):
|
||||
self._browser_id: str = ...
|
||||
self._rect: Optional[TabRect] = ...
|
||||
self._is_exist: bool = ...
|
||||
self._lock: Lock = ...
|
||||
|
||||
def _handle_options(self, addr_or_opts: Union[str, ChromiumOptions]) -> str: ...
|
||||
|
||||
@ -53,9 +55,6 @@ class ChromiumPage(ChromiumBase):
|
||||
@property
|
||||
def wait(self) -> PageWaiter: ...
|
||||
|
||||
@property
|
||||
def main_tab(self) -> str: ...
|
||||
|
||||
@property
|
||||
def latest_tab(self) -> str: ...
|
||||
|
||||
|
@ -6,6 +6,7 @@
|
||||
@License : BSD 3-Clause.
|
||||
"""
|
||||
from copy import copy
|
||||
from time import sleep
|
||||
|
||||
from .._base.base import BasePage
|
||||
from .._configs.session_options import SessionOptions
|
||||
@ -19,17 +20,20 @@ from .._units.waiter import TabWaiter
|
||||
|
||||
class ChromiumTab(ChromiumBase):
|
||||
"""实现浏览器标签页的类"""
|
||||
TABS = {}
|
||||
_TABS = {}
|
||||
|
||||
def __new__(cls, page, tab_id):
|
||||
"""
|
||||
:param page: ChromiumPage对象
|
||||
:param tab_id: 要控制的标签页id
|
||||
"""
|
||||
if Settings.singleton_tab_obj and tab_id in cls.TABS:
|
||||
return cls.TABS[tab_id]
|
||||
if Settings.singleton_tab_obj and tab_id in cls._TABS:
|
||||
r = cls._TABS[tab_id]
|
||||
while not hasattr(r, '_frame_id'):
|
||||
sleep(.1)
|
||||
return r
|
||||
r = object.__new__(cls)
|
||||
cls.TABS[tab_id] = r
|
||||
cls._TABS[tab_id] = r
|
||||
return r
|
||||
|
||||
def __init__(self, page, tab_id):
|
||||
@ -45,6 +49,7 @@ class ChromiumTab(ChromiumBase):
|
||||
self._browser = page.browser
|
||||
super().__init__(page.address, tab_id, page.timeout)
|
||||
self._rect = None
|
||||
self._type = 'ChromiumTab'
|
||||
|
||||
def _d_set_runtime_settings(self):
|
||||
"""重写设置浏览器运行参数方法"""
|
||||
@ -91,7 +96,7 @@ class ChromiumTab(ChromiumBase):
|
||||
return f'<ChromiumTab browser_id={self.browser.id} tab_id={self.tab_id}>'
|
||||
|
||||
def _on_disconnect(self):
|
||||
ChromiumTab.TABS.pop(self.tab_id, None)
|
||||
ChromiumTab._TABS.pop(self.tab_id, None)
|
||||
|
||||
|
||||
class WebPageTab(SessionPage, ChromiumTab, BasePage):
|
||||
@ -106,19 +111,20 @@ class WebPageTab(SessionPage, ChromiumTab, BasePage):
|
||||
super().__init__(session_or_options=SessionOptions(read_file=False).from_session(copy(page.session),
|
||||
page._headers))
|
||||
super(SessionPage, self).__init__(page=page, tab_id=tab_id)
|
||||
self._type = 'WebPageTab'
|
||||
|
||||
def __call__(self, loc_or_str, index=1, timeout=None):
|
||||
def __call__(self, locator, index=1, timeout=None):
|
||||
"""在内部查找元素
|
||||
例:ele = page('@id=ele_id')
|
||||
:param loc_or_str: 元素的定位信息,可以是loc元组,或查询字符串
|
||||
:param locator: 元素的定位信息,可以是loc元组,或查询字符串
|
||||
:param index: 获取第几个,从1开始,可传入负数获取倒数第几个
|
||||
:param timeout: 超时时间(秒)
|
||||
:return: 子元素对象
|
||||
"""
|
||||
if self._mode == 'd':
|
||||
return super(SessionPage, self).__call__(loc_or_str, index=index, timeout=timeout)
|
||||
return super(SessionPage, self).__call__(locator, index=index, timeout=timeout)
|
||||
elif self._mode == 's':
|
||||
return super().__call__(loc_or_str, index=index)
|
||||
return super().__call__(locator, index=index)
|
||||
|
||||
@property
|
||||
def set(self):
|
||||
@ -182,11 +188,6 @@ class WebPageTab(SessionPage, ChromiumTab, BasePage):
|
||||
"""返回当前模式,'s'或'd' """
|
||||
return self._mode
|
||||
|
||||
@property
|
||||
def cookies(self):
|
||||
"""以dict方式返回cookies"""
|
||||
return super().cookies
|
||||
|
||||
@property
|
||||
def user_agent(self):
|
||||
"""返回user agent"""
|
||||
@ -252,49 +253,49 @@ class WebPageTab(SessionPage, ChromiumTab, BasePage):
|
||||
return self.response
|
||||
return super().post(url, show_errmsg, retry, interval, **kwargs)
|
||||
|
||||
def ele(self, loc_or_ele, index=1, timeout=None):
|
||||
def ele(self, locator, index=1, timeout=None):
|
||||
"""返回第一个符合条件的元素、属性或节点文本
|
||||
:param loc_or_ele: 元素的定位信息,可以是元素对象,loc元组,或查询字符串
|
||||
:param locator: 元素的定位信息,可以是元素对象,loc元组,或查询字符串
|
||||
:param index: 获取第几个,从1开始,可传入负数获取倒数第几个
|
||||
:param timeout: 查找元素超时时间(秒),默认与页面等待时间一致
|
||||
:return: 元素对象或属性、文本节点文本
|
||||
"""
|
||||
if self._mode == 's':
|
||||
return super().ele(loc_or_ele, index=index)
|
||||
return super().ele(locator, index=index)
|
||||
elif self._mode == 'd':
|
||||
return super(SessionPage, self).ele(loc_or_ele, index=index, timeout=timeout)
|
||||
return super(SessionPage, self).ele(locator, index=index, timeout=timeout)
|
||||
|
||||
def eles(self, loc_or_str, timeout=None):
|
||||
def eles(self, locator, timeout=None):
|
||||
"""返回页面中所有符合条件的元素、属性或节点文本
|
||||
:param loc_or_str: 元素的定位信息,可以是loc元组,或查询字符串
|
||||
:param locator: 元素的定位信息,可以是loc元组,或查询字符串
|
||||
:param timeout: 查找元素超时时间(秒),默认与页面等待时间一致
|
||||
:return: 元素对象或属性、文本组成的列表
|
||||
"""
|
||||
if self._mode == 's':
|
||||
return super().eles(loc_or_str)
|
||||
return super().eles(locator)
|
||||
elif self._mode == 'd':
|
||||
return super(SessionPage, self).eles(loc_or_str, timeout=timeout)
|
||||
return super(SessionPage, self).eles(locator, timeout=timeout)
|
||||
|
||||
def s_ele(self, loc_or_ele=None, index=1):
|
||||
def s_ele(self, locator=None, index=1):
|
||||
"""查找第一个符合条件的元素以SessionElement形式返回,d模式处理复杂页面时效率很高
|
||||
:param loc_or_ele: 元素的定位信息,可以是loc元组,或查询字符串
|
||||
:param locator: 元素的定位信息,可以是loc元组,或查询字符串
|
||||
:param index: 获取第几个,从1开始,可传入负数获取倒数第几个
|
||||
:return: SessionElement对象或属性、文本
|
||||
"""
|
||||
if self._mode == 's':
|
||||
return super().s_ele(loc_or_ele, index=index)
|
||||
return super().s_ele(locator, index=index)
|
||||
elif self._mode == 'd':
|
||||
return super(SessionPage, self).s_ele(loc_or_ele, index=index)
|
||||
return super(SessionPage, self).s_ele(locator, index=index)
|
||||
|
||||
def s_eles(self, loc_or_str):
|
||||
def s_eles(self, locator):
|
||||
"""查找所有符合条件的元素以SessionElement形式返回,d模式处理复杂页面时效率很高
|
||||
:param loc_or_str: 元素的定位信息,可以是loc元组,或查询字符串
|
||||
:param locator: 元素的定位信息,可以是loc元组,或查询字符串
|
||||
:return: SessionElement对象或属性、文本组成的列表
|
||||
"""
|
||||
if self._mode == 's':
|
||||
return super().s_eles(loc_or_str)
|
||||
return super().s_eles(locator)
|
||||
elif self._mode == 'd':
|
||||
return super(SessionPage, self).s_eles(loc_or_str)
|
||||
return super(SessionPage, self).s_eles(locator)
|
||||
|
||||
def change_mode(self, mode=None, go=True, copy_cookies=True):
|
||||
"""切换模式,接收's'或'd',除此以外的字符串会切换为 d 模式
|
||||
@ -351,15 +352,15 @@ class WebPageTab(SessionPage, ChromiumTab, BasePage):
|
||||
user_agent = self.run_cdp('Runtime.evaluate', expression='navigator.userAgent;')['result']['value']
|
||||
self._headers.update({"User-Agent": user_agent})
|
||||
|
||||
set_session_cookies(self.session, super(SessionPage, self).get_cookies())
|
||||
set_session_cookies(self.session, super(SessionPage, self).cookies())
|
||||
|
||||
def cookies_to_browser(self):
|
||||
"""把session对象的cookies复制到浏览器"""
|
||||
if not self._has_driver:
|
||||
return
|
||||
set_browser_cookies(self, super().get_cookies())
|
||||
set_browser_cookies(self, super().cookies())
|
||||
|
||||
def get_cookies(self, as_dict=False, all_domains=False, all_info=False):
|
||||
def cookies(self, as_dict=False, all_domains=False, all_info=False):
|
||||
"""返回cookies
|
||||
:param as_dict: 是否以字典方式返回
|
||||
:param all_domains: 是否返回所有域的cookies
|
||||
@ -367,9 +368,9 @@ class WebPageTab(SessionPage, ChromiumTab, BasePage):
|
||||
:return: cookies信息
|
||||
"""
|
||||
if self._mode == 's':
|
||||
return super().get_cookies(as_dict, all_domains, all_info)
|
||||
return super().cookies(as_dict, all_domains, all_info)
|
||||
elif self._mode == 'd':
|
||||
return super(SessionPage, self).get_cookies(as_dict, all_domains, all_info)
|
||||
return super(SessionPage, self).cookies(as_dict, all_domains, all_info)
|
||||
|
||||
def close(self):
|
||||
"""关闭当前标签页"""
|
||||
@ -378,9 +379,9 @@ class WebPageTab(SessionPage, ChromiumTab, BasePage):
|
||||
if self._response is not None:
|
||||
self._response.close()
|
||||
|
||||
def _find_elements(self, loc_or_ele, timeout=None, index=1, relative=False, raise_err=None):
|
||||
def _find_elements(self, locator, timeout=None, index=1, relative=False, raise_err=None):
|
||||
"""返回页面中符合条件的元素、属性或节点文本,默认返回第一个
|
||||
:param loc_or_ele: 元素的定位信息,可以是元素对象,loc元组,或查询字符串
|
||||
:param locator: 元素的定位信息,可以是元素对象,loc元组,或查询字符串
|
||||
:param timeout: 查找元素超时时间(秒),d模式专用
|
||||
:param index: 第几个结果,从1开始,可传入负数获取倒数第几个,为None返回所有
|
||||
:param relative: WebPage用的表示是否相对定位的参数
|
||||
@ -388,9 +389,13 @@ class WebPageTab(SessionPage, ChromiumTab, BasePage):
|
||||
:return: 元素对象或属性、文本节点文本
|
||||
"""
|
||||
if self._mode == 's':
|
||||
return super()._find_elements(loc_or_ele, index=index)
|
||||
return super()._find_elements(locator, index=index)
|
||||
elif self._mode == 'd':
|
||||
return super(SessionPage, self)._find_elements(loc_or_ele, timeout=timeout, index=index, relative=relative)
|
||||
return super(SessionPage, self)._find_elements(locator, timeout=timeout, index=index, relative=relative)
|
||||
|
||||
def __repr__(self):
|
||||
return f'<WebPageTab browser_id={self.browser.id} tab_id={self.tab_id}>'
|
||||
|
||||
# --------即将废弃-------
|
||||
def get_cookies(self, as_dict=False, all_domains=False, all_info=False):
|
||||
return self.cookies(as_dict=as_dict, all_domains=all_domains, all_info=all_info)
|
@ -17,7 +17,6 @@ from .session_page import SessionPage
|
||||
from .web_page import WebPage
|
||||
from .._base.browser import Browser
|
||||
from .._elements.chromium_element import ChromiumElement
|
||||
from .._elements.none_element import NoneElement
|
||||
from .._elements.session_element import SessionElement
|
||||
from .._units.rect import TabRect
|
||||
from .._units.setter import TabSetter, WebPageTabSetter
|
||||
@ -25,7 +24,7 @@ from .._units.waiter import TabWaiter
|
||||
|
||||
|
||||
class ChromiumTab(ChromiumBase):
|
||||
TABS: dict = ...
|
||||
_TABS: dict = ...
|
||||
|
||||
def __new__(cls, page: ChromiumPage, tab_id: str): ...
|
||||
|
||||
@ -78,9 +77,9 @@ class WebPageTab(SessionPage, ChromiumTab):
|
||||
self._has_session = ...
|
||||
|
||||
def __call__(self,
|
||||
loc_or_str: Union[Tuple[str, str], str, ChromiumElement, SessionElement],
|
||||
locator: Union[Tuple[str, str], str, ChromiumElement, SessionElement],
|
||||
index: int = 1,
|
||||
timeout: float = None) -> Union[ChromiumElement, SessionElement, NoneElement]: ...
|
||||
timeout: float = None) -> Union[ChromiumElement, SessionElement]: ...
|
||||
|
||||
@property
|
||||
def page(self) -> WebPage: ...
|
||||
@ -109,9 +108,6 @@ class WebPageTab(SessionPage, ChromiumTab):
|
||||
@property
|
||||
def mode(self) -> str: ...
|
||||
|
||||
@property
|
||||
def cookies(self) -> dict: ...
|
||||
|
||||
@property
|
||||
def user_agent(self) -> str: ...
|
||||
|
||||
@ -148,19 +144,19 @@ class WebPageTab(SessionPage, ChromiumTab):
|
||||
cert: Any | None = ...) -> Union[bool, None]: ...
|
||||
|
||||
def ele(self,
|
||||
loc_or_ele: Union[Tuple[str, str], str, ChromiumElement, SessionElement],
|
||||
locator: Union[Tuple[str, str], str, ChromiumElement, SessionElement],
|
||||
index: int = 1,
|
||||
timeout: float = None) -> Union[ChromiumElement, SessionElement, NoneElement]: ...
|
||||
timeout: float = None) -> Union[ChromiumElement, SessionElement]: ...
|
||||
|
||||
def eles(self,
|
||||
loc_or_str: Union[Tuple[str, str], str],
|
||||
locator: Union[Tuple[str, str], str],
|
||||
timeout: float = None) -> List[Union[ChromiumElement, SessionElement]]: ...
|
||||
|
||||
def s_ele(self,
|
||||
loc_or_ele: Union[Tuple[str, str], str] = None,
|
||||
index: int = 1) -> Union[SessionElement, NoneElement]: ...
|
||||
locator: Union[Tuple[str, str], str] = None,
|
||||
index: int = 1) -> SessionElement: ...
|
||||
|
||||
def s_eles(self, loc_or_str: Union[Tuple[str, str], str]) -> List[SessionElement]: ...
|
||||
def s_eles(self, locator: Union[Tuple[str, str], str]) -> List[SessionElement]: ...
|
||||
|
||||
def change_mode(self, mode: str = None, go: bool = True, copy_cookies: bool = True) -> None: ...
|
||||
|
||||
@ -168,8 +164,8 @@ class WebPageTab(SessionPage, ChromiumTab):
|
||||
|
||||
def cookies_to_browser(self) -> None: ...
|
||||
|
||||
def get_cookies(self, as_dict: bool = False, all_domains: bool = False,
|
||||
all_info: bool = False) -> Union[dict, list]: ...
|
||||
def cookies(self, as_dict: bool = False, all_domains: bool = False,
|
||||
all_info: bool = False) -> Union[dict, list]: ...
|
||||
|
||||
def close(self) -> None: ...
|
||||
|
||||
@ -198,10 +194,10 @@ class WebPageTab(SessionPage, ChromiumTab):
|
||||
def set(self) -> WebPageTabSetter: ...
|
||||
|
||||
def _find_elements(self,
|
||||
loc_or_ele: Union[Tuple[str, str], str, ChromiumElement, SessionElement, ChromiumFrame],
|
||||
locator: Union[Tuple[str, str], str, ChromiumElement, SessionElement, ChromiumFrame],
|
||||
timeout: float = None,
|
||||
index: Optional[int] = 1,
|
||||
relative: bool = False,
|
||||
raise_err: bool = None) \
|
||||
-> Union[ChromiumElement, SessionElement, ChromiumFrame, NoneElement, List[SessionElement], List[
|
||||
-> Union[ChromiumElement, SessionElement, ChromiumFrame, List[SessionElement], List[
|
||||
Union[ChromiumElement, ChromiumFrame]]]: ...
|
||||
|
@ -35,6 +35,7 @@ class SessionPage(BasePage):
|
||||
self._session = None
|
||||
self._set = None
|
||||
self._encoding = None
|
||||
self._type = 'SessionPage'
|
||||
self._s_set_start_options(session_or_options)
|
||||
self._s_set_runtime_settings()
|
||||
self._create_session()
|
||||
@ -46,8 +47,11 @@ class SessionPage(BasePage):
|
||||
:param session_or_options: Session、SessionOptions对象
|
||||
:return: None
|
||||
"""
|
||||
if not session_or_options or isinstance(session_or_options, SessionOptions):
|
||||
self._session_options = session_or_options or SessionOptions(session_or_options)
|
||||
if not session_or_options:
|
||||
self._session_options = SessionOptions(session_or_options)
|
||||
|
||||
elif isinstance(session_or_options, SessionOptions):
|
||||
self._session_options = session_or_options
|
||||
|
||||
elif isinstance(session_or_options, Session):
|
||||
self._session_options = SessionOptions()
|
||||
@ -68,15 +72,15 @@ class SessionPage(BasePage):
|
||||
if not self._session:
|
||||
self._session, self._headers = self._session_options.make_session()
|
||||
|
||||
def __call__(self, loc_or_str, index=1, timeout=None):
|
||||
def __call__(self, locator, index=1, timeout=None):
|
||||
"""在内部查找元素
|
||||
例:ele2 = ele1('@id=ele_id')
|
||||
:param loc_or_str: 元素的定位信息,可以是loc元组,或查询字符串
|
||||
:param locator: 元素的定位信息,可以是loc元组,或查询字符串
|
||||
:param index: 获取第几个,从1开始,可传入负数获取倒数第几个
|
||||
:param timeout: 不起实际作用,用于和ChromiumElement对应,便于无差别调用
|
||||
:return: SessionElement对象或属性文本
|
||||
"""
|
||||
return self.ele(loc_or_str, index=index)
|
||||
return self.ele(locator, index=index)
|
||||
|
||||
# -----------------共有属性和方法-------------------
|
||||
@property
|
||||
@ -175,50 +179,49 @@ class SessionPage(BasePage):
|
||||
"""
|
||||
return self._s_connect(url, 'post', show_errmsg, retry, interval, **kwargs)
|
||||
|
||||
def ele(self, loc_or_ele, index=1, timeout=None):
|
||||
def ele(self, locator, index=1, timeout=None):
|
||||
"""返回页面中符合条件的一个元素、属性或节点文本
|
||||
:param loc_or_ele: 元素的定位信息,可以是元素对象,loc元组,或查询字符串
|
||||
:param locator: 元素的定位信息,可以是元素对象,loc元组,或查询字符串
|
||||
:param index: 获取第几个,从1开始,可传入负数获取倒数第几个
|
||||
:param timeout: 不起实际作用,用于和ChromiumElement对应,便于无差别调用
|
||||
:return: SessionElement对象或属性、文本
|
||||
"""
|
||||
return self._ele(loc_or_ele, index=index, method='ele()')
|
||||
return self._ele(locator, index=index, method='ele()')
|
||||
|
||||
def eles(self, loc_or_str, timeout=None):
|
||||
def eles(self, locator, timeout=None):
|
||||
"""返回页面中所有符合条件的元素、属性或节点文本
|
||||
:param loc_or_str: 元素的定位信息,可以是loc元组,或查询字符串
|
||||
:param locator: 元素的定位信息,可以是loc元组,或查询字符串
|
||||
:param timeout: 不起实际作用,用于和ChromiumElement对应,便于无差别调用
|
||||
:return: SessionElement对象或属性、文本组成的列表
|
||||
"""
|
||||
return self._ele(loc_or_str, index=None)
|
||||
return self._ele(locator, index=None)
|
||||
|
||||
def s_ele(self, loc_or_ele=None, index=1):
|
||||
def s_ele(self, locator=None, index=1):
|
||||
"""返回页面中符合条件的一个元素、属性或节点文本
|
||||
:param loc_or_ele: 元素的定位信息,可以是元素对象,loc元组,或查询字符串
|
||||
:param locator: 元素的定位信息,可以是元素对象,loc元组,或查询字符串
|
||||
:param index: 获取第几个,从1开始,可传入负数获取倒数第几个
|
||||
:return: SessionElement对象或属性、文本
|
||||
"""
|
||||
return make_session_ele(self.html) if loc_or_ele is None else self._ele(loc_or_ele,
|
||||
index=index, method='s_ele()')
|
||||
return make_session_ele(self.html) if locator is None else self._ele(locator, index=index, method='s_ele()')
|
||||
|
||||
def s_eles(self, loc_or_str):
|
||||
def s_eles(self, locator):
|
||||
"""返回页面中符合条件的所有元素、属性或节点文本
|
||||
:param loc_or_str: 元素的定位信息,可以是元素对象,loc元组,或查询字符串
|
||||
:param locator: 元素的定位信息,可以是元素对象,loc元组,或查询字符串
|
||||
:return: SessionElement对象或属性、文本
|
||||
"""
|
||||
return self._ele(loc_or_str, index=None)
|
||||
return self._ele(locator, index=None)
|
||||
|
||||
def _find_elements(self, loc_or_ele, timeout=None, index=1, raise_err=None):
|
||||
def _find_elements(self, locator, timeout=None, index=1, relative=True, raise_err=None):
|
||||
"""返回页面中符合条件的元素、属性或节点文本,默认返回第一个
|
||||
:param loc_or_ele: 元素的定位信息,可以是元素对象,loc元组,或查询字符串
|
||||
:param locator: 元素的定位信息,可以是元素对象,loc元组,或查询字符串
|
||||
:param timeout: 不起实际作用,用于和父类对应
|
||||
:param index: 第几个结果,从1开始,可传入负数获取倒数第几个,为None返回所有
|
||||
:param raise_err: 找不到元素是是否抛出异常,为None时根据全局设置
|
||||
:return: SessionElement对象
|
||||
"""
|
||||
return loc_or_ele if isinstance(loc_or_ele, SessionElement) else make_session_ele(self, loc_or_ele, index=index)
|
||||
return locator if isinstance(locator, SessionElement) else make_session_ele(self, locator, index=index)
|
||||
|
||||
def get_cookies(self, as_dict=False, all_domains=False, all_info=False):
|
||||
def cookies(self, as_dict=False, all_domains=False, all_info=False):
|
||||
"""返回cookies
|
||||
:param as_dict: 是否以字典方式返回,False则以list返回
|
||||
:param all_domains: 是否返回所有域的cookies
|
||||
@ -310,7 +313,7 @@ class SessionPage(BasePage):
|
||||
parsed_url = urlparse(url)
|
||||
hostname = parsed_url.hostname
|
||||
scheme = parsed_url.scheme
|
||||
if not check_headers(kwargs, self._headers, 'Referer'):
|
||||
if not check_headers(kwargs['headers'], self._headers, 'Referer'):
|
||||
kwargs['headers']['Referer'] = self.url if self.url else f'{scheme}://{hostname}'
|
||||
if 'Host' not in kwargs['headers']:
|
||||
kwargs['headers']['Host'] = hostname
|
||||
@ -364,10 +367,14 @@ class SessionPage(BasePage):
|
||||
def __repr__(self):
|
||||
return f'<SessionPage url={self.url}>'
|
||||
|
||||
# ---------即将废弃---------
|
||||
def get_cookies(self, as_dict=False, all_domains=False, all_info=False):
|
||||
return self.cookies(as_dict=as_dict, all_domains=all_domains, all_info=all_info)
|
||||
|
||||
|
||||
def check_headers(kwargs, headers, arg):
|
||||
"""检查kwargs或headers中是否有arg所示属性"""
|
||||
return arg in kwargs['headers'] or arg in headers
|
||||
return arg in kwargs or arg in headers
|
||||
|
||||
|
||||
def set_charset(response):
|
||||
|
@ -13,7 +13,6 @@ from requests.structures import CaseInsensitiveDict
|
||||
|
||||
from .._base.base import BasePage
|
||||
from .._configs.session_options import SessionOptions
|
||||
from .._elements.none_element import NoneElement
|
||||
from .._elements.session_element import SessionElement
|
||||
from .._units.setter import SessionPageSetter
|
||||
|
||||
@ -41,9 +40,9 @@ class SessionPage(BasePage):
|
||||
def _create_session(self) -> None: ...
|
||||
|
||||
def __call__(self,
|
||||
loc_or_str: Union[Tuple[str, str], str, SessionElement],
|
||||
locator: Union[Tuple[str, str], str, SessionElement],
|
||||
index: int = 1,
|
||||
timeout: float = None) -> Union[SessionElement, NoneElement]: ...
|
||||
timeout: float = None) -> SessionElement: ...
|
||||
|
||||
# -----------------共有属性和方法-------------------
|
||||
@property
|
||||
@ -91,28 +90,29 @@ class SessionPage(BasePage):
|
||||
cert: Any | None = ...) -> bool: ...
|
||||
|
||||
def ele(self,
|
||||
loc_or_ele: Union[Tuple[str, str], str, SessionElement],
|
||||
locator: Union[Tuple[str, str], str, SessionElement],
|
||||
index: int = 1,
|
||||
timeout: float = None) -> Union[SessionElement, NoneElement]: ...
|
||||
timeout: float = None) -> SessionElement: ...
|
||||
|
||||
def eles(self,
|
||||
loc_or_str: Union[Tuple[str, str], str],
|
||||
locator: Union[Tuple[str, str], str],
|
||||
timeout: float = None) -> List[SessionElement]: ...
|
||||
|
||||
def s_ele(self,
|
||||
loc_or_ele: Union[Tuple[str, str], str, SessionElement] = None,
|
||||
index: int = 1) -> Union[SessionElement, NoneElement]: ...
|
||||
locator: Union[Tuple[str, str], str, SessionElement] = None,
|
||||
index: int = 1) -> SessionElement: ...
|
||||
|
||||
def s_eles(self, loc_or_str: Union[Tuple[str, str], str]) -> List[SessionElement]: ...
|
||||
def s_eles(self, loc: Union[Tuple[str, str], str]) -> List[SessionElement]: ...
|
||||
|
||||
def _find_elements(self,
|
||||
loc_or_ele: Union[Tuple[str, str], str, SessionElement],
|
||||
locator: Union[Tuple[str, str], str, SessionElement],
|
||||
timeout: float = None,
|
||||
index: Optional[int] = 1,
|
||||
relative: bool = True,
|
||||
raise_err: bool = None) \
|
||||
-> Union[SessionElement, NoneElement, List[SessionElement]]: ...
|
||||
-> Union[SessionElement, List[SessionElement]]: ...
|
||||
|
||||
def get_cookies(self,
|
||||
def cookies(self,
|
||||
as_dict: bool = False,
|
||||
all_domains: bool = False,
|
||||
all_info: bool = False) -> Union[dict, list]: ...
|
||||
|
@ -48,20 +48,21 @@ class WebPage(SessionPage, ChromiumPage, BasePage):
|
||||
chromium_options = ChromiumOptions(read_file=chromium_options)
|
||||
chromium_options.set_timeouts(base=self._timeout).set_paths(download_path=self.download_path)
|
||||
super(SessionPage, self).__init__(addr_or_opts=chromium_options, timeout=timeout)
|
||||
self._type = 'WebPage'
|
||||
self.change_mode(self._mode, go=False, copy_cookies=False)
|
||||
|
||||
def __call__(self, loc_or_str, index=1, timeout=None):
|
||||
def __call__(self, locator, index=1, timeout=None):
|
||||
"""在内部查找元素
|
||||
例:ele = page('@id=ele_id')
|
||||
:param loc_or_str: 元素的定位信息,可以是loc元组,或查询字符串
|
||||
:param locator: 元素的定位信息,可以是loc元组,或查询字符串
|
||||
:param index: 获取第几个,从1开始,可传入负数获取倒数第几个
|
||||
:param timeout: 超时时间(秒)
|
||||
:return: 子元素对象
|
||||
"""
|
||||
if self._mode == 'd':
|
||||
return super(SessionPage, self).__call__(loc_or_str, index=index, timeout=timeout)
|
||||
return super(SessionPage, self).__call__(locator, index=index, timeout=timeout)
|
||||
elif self._mode == 's':
|
||||
return super().__call__(loc_or_str, index=index)
|
||||
return super().__call__(locator, index=index)
|
||||
|
||||
@property
|
||||
def set(self):
|
||||
@ -125,11 +126,6 @@ class WebPage(SessionPage, ChromiumPage, BasePage):
|
||||
"""返回当前模式,'s'或'd' """
|
||||
return self._mode
|
||||
|
||||
@property
|
||||
def cookies(self):
|
||||
"""以dict方式返回cookies"""
|
||||
return super().cookies
|
||||
|
||||
@property
|
||||
def user_agent(self):
|
||||
"""返回user agent"""
|
||||
@ -195,49 +191,49 @@ class WebPage(SessionPage, ChromiumPage, BasePage):
|
||||
return self.response
|
||||
return super().post(url, show_errmsg, retry, interval, **kwargs)
|
||||
|
||||
def ele(self, loc_or_ele, index=1, timeout=None):
|
||||
def ele(self, locator, index=1, timeout=None):
|
||||
"""返回第一个符合条件的元素、属性或节点文本
|
||||
:param loc_or_ele: 元素的定位信息,可以是元素对象,loc元组,或查询字符串
|
||||
:param locator: 元素的定位信息,可以是元素对象,loc元组,或查询字符串
|
||||
:param index: 获取第几个,从1开始,可传入负数获取倒数第几个
|
||||
:param timeout: 查找元素超时时间(秒),默认与页面等待时间一致
|
||||
:return: 元素对象或属性、文本节点文本
|
||||
"""
|
||||
if self._mode == 's':
|
||||
return super().ele(loc_or_ele, index=index)
|
||||
return super().ele(locator, index=index)
|
||||
elif self._mode == 'd':
|
||||
return super(SessionPage, self).ele(loc_or_ele, index=index, timeout=timeout)
|
||||
return super(SessionPage, self).ele(locator, index=index, timeout=timeout)
|
||||
|
||||
def eles(self, loc_or_str, timeout=None):
|
||||
def eles(self, locator, timeout=None):
|
||||
"""返回页面中所有符合条件的元素、属性或节点文本
|
||||
:param loc_or_str: 元素的定位信息,可以是loc元组,或查询字符串
|
||||
:param locator: 元素的定位信息,可以是loc元组,或查询字符串
|
||||
:param timeout: 查找元素超时时间(秒),默认与页面等待时间一致
|
||||
:return: 元素对象或属性、文本组成的列表
|
||||
"""
|
||||
if self._mode == 's':
|
||||
return super().eles(loc_or_str)
|
||||
return super().eles(locator)
|
||||
elif self._mode == 'd':
|
||||
return super(SessionPage, self).eles(loc_or_str, timeout=timeout)
|
||||
return super(SessionPage, self).eles(locator, timeout=timeout)
|
||||
|
||||
def s_ele(self, loc_or_ele=None, index=1):
|
||||
def s_ele(self, locator=None, index=1):
|
||||
"""查找第一个符合条件的元素以SessionElement形式返回,d模式处理复杂页面时效率很高
|
||||
:param loc_or_ele: 元素的定位信息,可以是loc元组,或查询字符串
|
||||
:param locator: 元素的定位信息,可以是loc元组,或查询字符串
|
||||
:param index: 获取第几个,从1开始,可传入负数获取倒数第几个
|
||||
:return: SessionElement对象或属性、文本
|
||||
"""
|
||||
if self._mode == 's':
|
||||
return super().s_ele(loc_or_ele, index=index)
|
||||
return super().s_ele(locator, index=index)
|
||||
elif self._mode == 'd':
|
||||
return super(SessionPage, self).s_ele(loc_or_ele, index=index)
|
||||
return super(SessionPage, self).s_ele(locator, index=index)
|
||||
|
||||
def s_eles(self, loc_or_str):
|
||||
def s_eles(self, locator):
|
||||
"""查找所有符合条件的元素以SessionElement形式返回,d模式处理复杂页面时效率很高
|
||||
:param loc_or_str: 元素的定位信息,可以是loc元组,或查询字符串
|
||||
:param locator: 元素的定位信息,可以是loc元组,或查询字符串
|
||||
:return: SessionElement对象或属性、文本组成的列表
|
||||
"""
|
||||
if self._mode == 's':
|
||||
return super().s_eles(loc_or_str)
|
||||
return super().s_eles(locator)
|
||||
elif self._mode == 'd':
|
||||
return super(SessionPage, self).s_eles(loc_or_str)
|
||||
return super(SessionPage, self).s_eles(locator)
|
||||
|
||||
def change_mode(self, mode=None, go=True, copy_cookies=True):
|
||||
"""切换模式,接收's'或'd',除此以外的字符串会切换为 d 模式
|
||||
@ -280,7 +276,9 @@ class WebPage(SessionPage, ChromiumPage, BasePage):
|
||||
if go:
|
||||
url = super(SessionPage, self).url
|
||||
if url.startswith('http'):
|
||||
self.get(url)
|
||||
r = self.get(url)
|
||||
if not r:
|
||||
raise ConnectionError('s模式访问失败,请设置go=False,自行构造连接参数进行访问。')
|
||||
|
||||
def cookies_to_session(self, copy_user_agent=True):
|
||||
"""把driver对象的cookies复制到session对象
|
||||
@ -294,15 +292,15 @@ class WebPage(SessionPage, ChromiumPage, BasePage):
|
||||
user_agent = self.run_cdp('Runtime.evaluate', expression='navigator.userAgent;')['result']['value']
|
||||
self._headers.update({"User-Agent": user_agent})
|
||||
|
||||
set_session_cookies(self.session, super(SessionPage, self).get_cookies())
|
||||
set_session_cookies(self.session, super(SessionPage, self).cookies())
|
||||
|
||||
def cookies_to_browser(self):
|
||||
"""把session对象的cookies复制到浏览器"""
|
||||
if not self._has_driver:
|
||||
return
|
||||
set_browser_cookies(self, super().get_cookies())
|
||||
set_browser_cookies(self, super().cookies())
|
||||
|
||||
def get_cookies(self, as_dict=False, all_domains=False, all_info=False):
|
||||
def cookies(self, as_dict=False, all_domains=False, all_info=False):
|
||||
"""返回cookies
|
||||
:param as_dict: 是否以字典方式返回,False以list形式返回
|
||||
:param all_domains: 是否返回所有域的cookies
|
||||
@ -310,9 +308,9 @@ class WebPage(SessionPage, ChromiumPage, BasePage):
|
||||
:return: cookies信息
|
||||
"""
|
||||
if self._mode == 's':
|
||||
return super().get_cookies(as_dict, all_domains, all_info)
|
||||
return super().cookies(as_dict, all_domains, all_info)
|
||||
elif self._mode == 'd':
|
||||
return super(SessionPage, self).get_cookies(as_dict, all_domains, all_info)
|
||||
return super(SessionPage, self).cookies(as_dict, all_domains, all_info)
|
||||
|
||||
def get_tab(self, id_or_num=None):
|
||||
"""获取一个标签页对象
|
||||
@ -375,9 +373,9 @@ class WebPage(SessionPage, ChromiumPage, BasePage):
|
||||
if self._response is not None:
|
||||
self._response.close()
|
||||
|
||||
def _find_elements(self, loc_or_ele, timeout=None, index=1, relative=False, raise_err=None):
|
||||
def _find_elements(self, locator, timeout=None, index=1, relative=False, raise_err=None):
|
||||
"""返回页面中符合条件的元素、属性或节点文本,默认返回第一个
|
||||
:param loc_or_ele: 元素的定位信息,可以是元素对象,loc元组,或查询字符串
|
||||
:param locator: 元素的定位信息,可以是元素对象,loc元组,或查询字符串
|
||||
:param timeout: 查找元素超时时间,d模式专用
|
||||
:param index: 第几个结果,从1开始,可传入负数获取倒数第几个,为None返回所有
|
||||
:param relative: WebPage用的表示是否相对定位的参数
|
||||
@ -385,9 +383,9 @@ class WebPage(SessionPage, ChromiumPage, BasePage):
|
||||
:return: 元素对象或属性、文本节点文本
|
||||
"""
|
||||
if self._mode == 's':
|
||||
return super()._find_elements(loc_or_ele, index=index)
|
||||
return super()._find_elements(locator, index=index)
|
||||
elif self._mode == 'd':
|
||||
return super(SessionPage, self)._find_elements(loc_or_ele, timeout=timeout, index=index, relative=relative)
|
||||
return super(SessionPage, self)._find_elements(locator, timeout=timeout, index=index, relative=relative)
|
||||
|
||||
def quit(self, timeout=5, force=True):
|
||||
"""关闭浏览器和Session
|
||||
@ -407,3 +405,7 @@ class WebPage(SessionPage, ChromiumPage, BasePage):
|
||||
|
||||
def __repr__(self):
|
||||
return f'<WebPage browser_id={self.browser.id} tab_id={self.tab_id}>'
|
||||
|
||||
# -------即将废弃--------
|
||||
def get_cookies(self, as_dict=False, all_domains=False, all_info=False):
|
||||
return self.cookies(as_dict=as_dict, all_domains=all_domains, all_info=all_info)
|
||||
|
@ -18,7 +18,6 @@ from .._base.driver import Driver
|
||||
from .._configs.chromium_options import ChromiumOptions
|
||||
from .._configs.session_options import SessionOptions
|
||||
from .._elements.chromium_element import ChromiumElement
|
||||
from .._elements.none_element import NoneElement
|
||||
from .._elements.session_element import SessionElement
|
||||
from .._units.setter import WebPageSetter
|
||||
|
||||
@ -31,15 +30,16 @@ class WebPage(SessionPage, ChromiumPage, BasePage):
|
||||
chromium_options: Union[ChromiumOptions, bool] = None,
|
||||
session_or_options: Union[Session, SessionOptions, bool] = None) -> None:
|
||||
self._mode: str = ...
|
||||
self._set: WebPageSetter = ...
|
||||
self._has_driver: bool = ...
|
||||
self._has_session: bool = ...
|
||||
self._session_options: Union[SessionOptions, None] = ...
|
||||
self._chromium_options: Union[ChromiumOptions, None] = ...
|
||||
|
||||
def __call__(self,
|
||||
loc_or_str: Union[Tuple[str, str], str, ChromiumElement, SessionElement],
|
||||
locator: Union[Tuple[str, str], str, ChromiumElement, SessionElement],
|
||||
index: int = 1,
|
||||
timeout: float = None) -> Union[ChromiumElement, SessionElement, NoneElement]: ...
|
||||
timeout: float = None) -> Union[ChromiumElement, SessionElement]: ...
|
||||
|
||||
# -----------------共有属性和方法-------------------
|
||||
@property
|
||||
@ -66,9 +66,6 @@ class WebPage(SessionPage, ChromiumPage, BasePage):
|
||||
@property
|
||||
def mode(self) -> str: ...
|
||||
|
||||
@property
|
||||
def cookies(self) -> dict: ...
|
||||
|
||||
@property
|
||||
def user_agent(self) -> str: ...
|
||||
|
||||
@ -105,19 +102,19 @@ class WebPage(SessionPage, ChromiumPage, BasePage):
|
||||
cert: Any | None = ...) -> Union[bool, None]: ...
|
||||
|
||||
def ele(self,
|
||||
loc_or_ele: Union[Tuple[str, str], str, ChromiumElement, SessionElement],
|
||||
locator: Union[Tuple[str, str], str, ChromiumElement, SessionElement],
|
||||
index: int = 1,
|
||||
timeout: float = None) -> Union[ChromiumElement, SessionElement, NoneElement]: ...
|
||||
timeout: float = None) -> Union[ChromiumElement, SessionElement]: ...
|
||||
|
||||
def eles(self,
|
||||
loc_or_str: Union[Tuple[str, str], str],
|
||||
locator: Union[Tuple[str, str], str],
|
||||
timeout: float = None) -> List[Union[ChromiumElement, SessionElement]]: ...
|
||||
|
||||
def s_ele(self,
|
||||
loc_or_ele: Union[Tuple[str, str], str] = None,
|
||||
index: int = 1) -> Union[SessionElement, NoneElement]: ...
|
||||
locator: Union[Tuple[str, str], str] = None,
|
||||
index: int = 1) -> SessionElement: ...
|
||||
|
||||
def s_eles(self, loc_or_str: Union[Tuple[str, str], str]) -> List[SessionElement]: ...
|
||||
def s_eles(self, locator: Union[Tuple[str, str], str]) -> List[SessionElement]: ...
|
||||
|
||||
def change_mode(self, mode: str = None, go: bool = True, copy_cookies: bool = True) -> None: ...
|
||||
|
||||
@ -125,10 +122,10 @@ class WebPage(SessionPage, ChromiumPage, BasePage):
|
||||
|
||||
def cookies_to_browser(self) -> None: ...
|
||||
|
||||
def get_cookies(self,
|
||||
as_dict: bool = False,
|
||||
all_domains: bool = False,
|
||||
all_info: bool = False) -> Union[dict, list]: ...
|
||||
def cookies(self,
|
||||
as_dict: bool = False,
|
||||
all_domains: bool = False,
|
||||
all_info: bool = False) -> Union[dict, list]: ...
|
||||
|
||||
def get_tab(self, id_or_num: Union[str, WebPageTab, int] = None) -> WebPageTab: ...
|
||||
|
||||
@ -169,12 +166,12 @@ class WebPage(SessionPage, ChromiumPage, BasePage):
|
||||
def set(self) -> WebPageSetter: ...
|
||||
|
||||
def _find_elements(self,
|
||||
loc_or_ele: Union[Tuple[str, str], str, ChromiumElement, SessionElement, ChromiumFrame],
|
||||
locator: Union[Tuple[str, str], str, ChromiumElement, SessionElement, ChromiumFrame],
|
||||
timeout: float = None,
|
||||
index: Optional[int] = 1,
|
||||
relative: bool = False,
|
||||
raise_err: bool = None) \
|
||||
-> Union[ChromiumElement, SessionElement, ChromiumFrame, NoneElement, List[SessionElement],
|
||||
-> Union[ChromiumElement, SessionElement, ChromiumFrame, List[SessionElement],
|
||||
List[Union[ChromiumElement, ChromiumFrame]]]: ...
|
||||
|
||||
def _set_start_options(self,
|
||||
|
@ -39,7 +39,7 @@ class Actions:
|
||||
is_loc = True
|
||||
lx = ele_or_loc[0] + offset_x
|
||||
ly = ele_or_loc[1] + offset_y
|
||||
elif isinstance(ele_or_loc, str) or 'ChromiumElement' in str(type(ele_or_loc)):
|
||||
elif isinstance(ele_or_loc, str) or ele_or_loc._type == 'ChromiumElement':
|
||||
ele_or_loc = self.page(ele_or_loc)
|
||||
self.page.scroll.to_see(ele_or_loc)
|
||||
x, y = ele_or_loc.rect.location if offset_x or offset_y else ele_or_loc.rect.midpoint
|
||||
|
@ -5,7 +5,7 @@
|
||||
@Copyright: (c) 2024 by g1879, Inc. All Rights Reserved.
|
||||
@License : BSD 3-Clause.
|
||||
"""
|
||||
from typing import Union, Optional
|
||||
from typing import Optional
|
||||
|
||||
from .._elements.chromium_element import ChromiumElement
|
||||
|
||||
|
@ -100,6 +100,9 @@ class Listener(object):
|
||||
Manifest, SignedExchange, Ping, CSPViolationReport, Preflight, Other
|
||||
:return: None
|
||||
"""
|
||||
if targets is not None:
|
||||
if is_regex is None:
|
||||
is_regex = False
|
||||
if targets or is_regex is not None or method or res_type:
|
||||
self.set_targets(targets, is_regex, method, res_type)
|
||||
self.clear()
|
||||
|
@ -6,7 +6,7 @@
|
||||
@License : BSD 3-Clause.
|
||||
"""
|
||||
|
||||
from typing import Tuple, Union, List
|
||||
from typing import Tuple, Union
|
||||
|
||||
from .._elements.chromium_element import ChromiumElement
|
||||
from .._pages.chromium_base import ChromiumBase
|
||||
|
@ -87,7 +87,7 @@ class Scroller(object):
|
||||
if not self._wait_complete:
|
||||
return
|
||||
|
||||
page = self._driver.page if 'ChromiumElement' in str(type(self._driver)) else self._driver
|
||||
page = self._driver.page if self._driver._type == 'ChromiumElement' else self._driver
|
||||
r = page.run_cdp('Page.getLayoutMetrics')
|
||||
x = r['layoutViewport']['pageX']
|
||||
y = r['layoutViewport']['pageY']
|
||||
@ -173,5 +173,5 @@ class FrameScroller(PageScroller):
|
||||
:param center: 是否尽量滚动到页面正中,为None时如果被遮挡,则滚动到页面正中
|
||||
:return: None
|
||||
"""
|
||||
ele = loc_or_ele if 'ChromiumElement' in str(type(loc_or_ele)) else self._driver._ele(loc_or_ele)
|
||||
ele = loc_or_ele if loc_or_ele._type == 'ChromiumElement' else self._driver._ele(loc_or_ele)
|
||||
self._to_see(ele, center)
|
||||
|
@ -103,13 +103,13 @@ class SelectElement(object):
|
||||
"""
|
||||
return self._select(index, 'index', False, timeout)
|
||||
|
||||
def by_loc(self, loc, timeout=None):
|
||||
def by_locator(self, locator, timeout=None):
|
||||
"""用定位符选择指定的项
|
||||
:param loc: 定位符
|
||||
:param locator: 定位符
|
||||
:param timeout: 超时时间
|
||||
:return: 是否选择成功
|
||||
"""
|
||||
return self._by_loc(loc, timeout)
|
||||
return self._by_loc(locator, timeout)
|
||||
|
||||
def by_option(self, option):
|
||||
"""选中单个或多个option元素
|
||||
@ -142,13 +142,13 @@ class SelectElement(object):
|
||||
"""
|
||||
return self._select(index, 'index', True, timeout)
|
||||
|
||||
def cancel_by_loc(self, loc, timeout=None):
|
||||
def cancel_by_locator(self, locator, timeout=None):
|
||||
"""用定位符取消选择指定的项
|
||||
:param loc: 定位符
|
||||
:param locator: 定位符
|
||||
:param timeout: 超时时间
|
||||
:return: 是否选择成功
|
||||
"""
|
||||
return self._by_loc(loc, timeout, True)
|
||||
return self._by_loc(locator, timeout, True)
|
||||
|
||||
def cancel_by_option(self, option):
|
||||
"""取消选中单个或多个option元素
|
||||
|
@ -38,7 +38,7 @@ class SelectElement(object):
|
||||
|
||||
def by_index(self, index: Union[int, list, tuple], timeout: float = None) -> bool: ...
|
||||
|
||||
def by_loc(self, loc: Union[str, Tuple[str, str]], timeout: float = None) -> bool: ...
|
||||
def by_locator(self, locator: Union[Tuple[str, str], str], timeout: float = None) -> bool: ...
|
||||
|
||||
def by_option(self, option: Union[ChromiumElement, List[ChromiumElement], Tuple[ChromiumElement]]) -> None: ...
|
||||
|
||||
@ -48,7 +48,7 @@ class SelectElement(object):
|
||||
|
||||
def cancel_by_index(self, index: Union[int, list, tuple], timeout: float = None) -> bool: ...
|
||||
|
||||
def cancel_by_loc(self, loc: Union[str, Tuple[str, str]], timeout: float = None) -> bool: ...
|
||||
def cancel_by_locator(self, locator: Union[Tuple[str, str], str], timeout: float = None) -> bool: ...
|
||||
|
||||
def cancel_by_option(self,
|
||||
option: Union[ChromiumElement, List[ChromiumElement], Tuple[ChromiumElement]]) -> None: ...
|
||||
|
@ -6,6 +6,7 @@
|
||||
@License : BSD 3-Clause.
|
||||
"""
|
||||
from pathlib import Path
|
||||
from time import sleep
|
||||
|
||||
from requests.structures import CaseInsensitiveDict
|
||||
|
||||
@ -292,13 +293,13 @@ class SessionPageSetter(BasePageSetter):
|
||||
"""
|
||||
self._page._headers = CaseInsensitiveDict(headers)
|
||||
|
||||
def header(self, attr, value):
|
||||
def header(self, name, value):
|
||||
"""设置headers中一个项
|
||||
:param attr: 设置名称
|
||||
:param name: 设置名称
|
||||
:param value: 设置值
|
||||
:return: None
|
||||
"""
|
||||
self._page._headers[attr] = value
|
||||
self._page._headers[name] = value
|
||||
|
||||
def user_agent(self, ua):
|
||||
"""设置user agent
|
||||
@ -449,39 +450,46 @@ class ChromiumElementSetter(object):
|
||||
"""
|
||||
self._ele = ele
|
||||
|
||||
def attr(self, attr, value):
|
||||
def attr(self, name, value):
|
||||
"""设置元素attribute属性
|
||||
:param attr: 属性名
|
||||
:param name: 属性名
|
||||
:param value: 属性值
|
||||
:return: None
|
||||
"""
|
||||
self._ele.page.run_cdp('DOM.setAttributeValue', nodeId=self._ele._node_id, name=attr, value=str(value))
|
||||
self._ele.page.run_cdp('DOM.setAttributeValue', nodeId=self._ele._node_id, name=name, value=str(value))
|
||||
|
||||
def prop(self, prop, value):
|
||||
def property(self, name, value):
|
||||
"""设置元素property属性
|
||||
:param prop: 属性名
|
||||
:param name: 属性名
|
||||
:param value: 属性值
|
||||
:return: None
|
||||
"""
|
||||
value = value.replace('"', r'\"')
|
||||
self._ele.run_js(f'this.{prop}="{value}";')
|
||||
self._ele.run_js(f'this.{name}="{value}";')
|
||||
|
||||
def innerHTML(self, html):
|
||||
"""设置元素innerHTML
|
||||
:param html: html文本
|
||||
:return: None
|
||||
"""
|
||||
self.prop('innerHTML', html)
|
||||
self.property('innerHTML', html)
|
||||
|
||||
def value(self, value):
|
||||
"""设置元素value值
|
||||
:param value: value值
|
||||
:return: None
|
||||
"""
|
||||
self.property('value', value)
|
||||
|
||||
|
||||
class ChromiumFrameSetter(ChromiumBaseSetter):
|
||||
def attr(self, attr, value):
|
||||
def attr(self, name, value):
|
||||
"""设置frame元素attribute属性
|
||||
:param attr: 属性名
|
||||
:param name: 属性名
|
||||
:param value: 属性值
|
||||
:return: None
|
||||
"""
|
||||
self._page.frame_ele.set.attr(attr, value)
|
||||
self._page.frame_ele.set.attr(name, value)
|
||||
|
||||
|
||||
class LoadMode(object):
|
||||
@ -608,7 +616,11 @@ class WindowSetter(object):
|
||||
|
||||
def _get_info(self):
|
||||
"""获取窗口位置及大小信息"""
|
||||
return self._page.run_cdp('Browser.getWindowForTarget')
|
||||
for _ in range(50):
|
||||
try:
|
||||
return self._page.run_cdp('Browser.getWindowForTarget')
|
||||
except:
|
||||
sleep(.1)
|
||||
|
||||
def _perform(self, bounds):
|
||||
"""执行改变窗口大小操作
|
||||
|
@ -113,7 +113,7 @@ class SessionPageSetter(BasePageSetter):
|
||||
|
||||
def headers(self, headers: dict) -> None: ...
|
||||
|
||||
def header(self, attr: str, value: str) -> None: ...
|
||||
def header(self, name: str, value: str) -> None: ...
|
||||
|
||||
def user_agent(self, ua: str) -> None: ...
|
||||
|
||||
@ -168,17 +168,19 @@ class ChromiumElementSetter(object):
|
||||
def __init__(self, ele: ChromiumElement):
|
||||
self._ele: ChromiumElement = ...
|
||||
|
||||
def attr(self, attr: str, value: str) -> None: ...
|
||||
def attr(self, name: str, value: str) -> None: ...
|
||||
|
||||
def prop(self, prop: str, value: str) -> None: ...
|
||||
def property(self, name: str, value: str) -> None: ...
|
||||
|
||||
def innerHTML(self, html: str) -> None: ...
|
||||
|
||||
def value(self, value: str) -> None: ...
|
||||
|
||||
|
||||
class ChromiumFrameSetter(ChromiumBaseSetter):
|
||||
_page: ChromiumFrame = ...
|
||||
|
||||
def attr(self, attr: str, value: str) -> None: ...
|
||||
def attr(self, name: str, value: str) -> None: ...
|
||||
|
||||
|
||||
class LoadMode(object):
|
||||
|
@ -29,8 +29,9 @@ class ElementStates(object):
|
||||
@property
|
||||
def is_displayed(self):
|
||||
"""返回元素是否显示"""
|
||||
return not (self._ele.style('visibility') == 'hidden' or self._ele.run_js('return this.offsetParent === null;')
|
||||
or self._ele.style('display') == 'none' or self._ele.prop('hidden'))
|
||||
return not (self._ele.style('visibility') == 'hidden' or
|
||||
self._ele.run_js('return this.offsetParent === null;')
|
||||
or self._ele.style('display') == 'none' or self._ele.property('hidden'))
|
||||
|
||||
@property
|
||||
def is_enabled(self):
|
||||
|
@ -73,14 +73,14 @@ class BaseWaiter(object):
|
||||
return False
|
||||
return ele.wait.hidden(timeout, raise_err=raise_err)
|
||||
|
||||
def ele_loaded(self, loc, timeout=None, raise_err=None):
|
||||
def ele_loaded(self, locator, timeout=None, raise_err=None):
|
||||
"""等待元素加载到DOM
|
||||
:param loc: 要等待的元素,输入定位符
|
||||
:param locator: 要等待的元素,输入定位符
|
||||
:param timeout: 超时时间,默认读取页面超时时间
|
||||
:param raise_err: 等待失败时是否报错,为None时根据Settings设置
|
||||
:return: 成功返回元素对象,失败返回False
|
||||
"""
|
||||
ele = self._driver._ele(loc, raise_err=False, timeout=timeout)
|
||||
ele = self._driver._ele(locator, raise_err=False, timeout=timeout)
|
||||
if ele:
|
||||
return ele
|
||||
if raise_err is True or Settings.raise_when_wait_failed is True:
|
||||
@ -119,6 +119,8 @@ class BaseWaiter(object):
|
||||
:param cancel_it: 是否取消该任务
|
||||
:return: 成功返回任务对象,失败返回False
|
||||
"""
|
||||
if not self._driver.browser._dl_mgr._running:
|
||||
raise RuntimeError('使用下载管理功能前需显式设置下载路径(使用set.download_path()方法、配置对象或ini文件均可)。')
|
||||
self._driver.browser._dl_mgr.set_flag(self._driver.tab_id, False if cancel_it else True)
|
||||
if timeout is None:
|
||||
timeout = self._driver.timeout
|
||||
@ -232,6 +234,8 @@ class TabWaiter(BaseWaiter):
|
||||
:param cancel_if_timeout: 超时时是否取消剩余任务
|
||||
:return: 是否等待成功
|
||||
"""
|
||||
if not self._driver.browser._dl_mgr._running:
|
||||
raise RuntimeError('使用下载管理功能前需显式设置下载路径(使用set.download_path()方法、配置对象或ini文件均可)。')
|
||||
if not timeout:
|
||||
while self._driver.browser._dl_mgr.get_tab_missions(self._driver.tab_id):
|
||||
sleep(.5)
|
||||
@ -290,6 +294,8 @@ class PageWaiter(TabWaiter):
|
||||
:param cancel_if_timeout: 超时时是否取消剩余任务
|
||||
:return: 是否等待成功
|
||||
"""
|
||||
if not self._driver.browser._dl_mgr._running:
|
||||
raise RuntimeError('使用下载管理功能前需显式设置下载路径(使用set.download_path()方法、配置对象或ini文件均可)。')
|
||||
if not timeout:
|
||||
while self._driver.browser._dl_mgr._missions:
|
||||
sleep(.5)
|
||||
@ -458,7 +464,8 @@ class ElementWaiter(object):
|
||||
timeout = self._page.timeout
|
||||
end_time = perf_counter() + timeout
|
||||
while perf_counter() < end_time:
|
||||
if self._ele.states.__getattribute__(attr) == mode:
|
||||
a = self._ele.states.__getattribute__(attr)
|
||||
if (a and mode) or (not a and not mode):
|
||||
return True
|
||||
sleep(.05)
|
||||
|
||||
|
@ -5,7 +5,7 @@
|
||||
@Copyright: (c) 2024 by g1879, Inc. All Rights Reserved.
|
||||
@License : BSD 3-Clause.
|
||||
"""
|
||||
from typing import Union
|
||||
from typing import Union, Tuple
|
||||
|
||||
from .downloader import DownloadMission
|
||||
from .._elements.chromium_element import ChromiumElement
|
||||
@ -34,7 +34,7 @@ class BaseWaiter(object):
|
||||
raise_err: bool = None) -> bool: ...
|
||||
|
||||
def ele_loaded(self,
|
||||
loc: Union[str, tuple],
|
||||
locator: Union[Tuple[str, str], str],
|
||||
timeout: float = None,
|
||||
raise_err: bool = None) -> Union[bool, ChromiumElement]: ...
|
||||
|
||||
|
@ -10,6 +10,7 @@ from ._functions.by import By
|
||||
from ._functions.keys import Keys
|
||||
from ._functions.settings import Settings
|
||||
from ._functions.tools import wait_until, configs_to_here
|
||||
from ._functions.web import get_blob
|
||||
from ._units.actions import Actions
|
||||
|
||||
__all__ = ['make_session_ele', 'Actions', 'Keys', 'By', 'Settings', 'wait_until', 'configs_to_here']
|
||||
__all__ = ['make_session_ele', 'Actions', 'Keys', 'By', 'Settings', 'wait_until', 'configs_to_here', 'get_blob']
|
||||
|
15
DrissionPage/items.py
Normal file
15
DrissionPage/items.py
Normal file
@ -0,0 +1,15 @@
|
||||
# -*- coding:utf-8 -*-
|
||||
"""
|
||||
@Author : g1879
|
||||
@Contact : g1879@qq.com
|
||||
@Copyright: (c) 2024 by g1879, Inc. All Rights Reserved.
|
||||
@License : BSD 3-Clause.
|
||||
"""
|
||||
from ._elements.chromium_element import ChromiumElement, ShadowRoot
|
||||
from ._elements.none_element import NoneElement
|
||||
from ._elements.session_element import SessionElement
|
||||
from ._pages.chromium_frame import ChromiumFrame
|
||||
from ._pages.chromium_tab import ChromiumTab, WebPageTab
|
||||
|
||||
__all__ = ['ChromiumElement', 'ShadowRoot', 'NoneElement', 'SessionElement', 'ChromiumFrame', 'ChromiumTab',
|
||||
'WebPageTab']
|
@ -123,4 +123,4 @@ python 版本:3.6 及以上
|
||||
|
||||
如果本项目对您有所帮助,不妨请作者我喝杯咖啡 :)
|
||||
|
||||

|
||||

|
||||
|
3
setup.py
3
setup.py
@ -1,12 +1,13 @@
|
||||
# -*- coding:utf-8 -*-
|
||||
from setuptools import setup, find_packages
|
||||
from DrissionPage import __version__
|
||||
|
||||
with open("README.md", "r", encoding='utf-8') as fh:
|
||||
long_description = fh.read()
|
||||
|
||||
setup(
|
||||
name="DrissionPage",
|
||||
version="4.0.2",
|
||||
version=__version__,
|
||||
author="g1879",
|
||||
author_email="g1879@qq.com",
|
||||
description="Python based web automation tool. It can control the browser and send and receive data packets.",
|
||||
|
Loading…
x
Reference in New Issue
Block a user