增加NoResourceError;click()删除retry和timeout参数;get_src()和save()增加timeout参数

This commit is contained in:
g1879 2023-03-03 15:00:37 +08:00
parent d7a046f4f6
commit c000bec826
11 changed files with 73 additions and 88 deletions

View File

@ -930,7 +930,7 @@ class ChromiumBaseWaiter(object):
:param timeout: 超时时间为None时使用页面timeout属性
:return: 是否等待成功
"""
return self._loading(timeout=timeout)
return self._loading(timeout=timeout, gap=.002)
def load_complete(self, timeout=None):
"""等待页面开始加载
@ -944,10 +944,11 @@ class ChromiumBaseWaiter(object):
while self._driver._upload_list:
sleep(.01)
def _loading(self, timeout=None, start=True):
def _loading(self, timeout=None, start=True, gap=.01):
"""等待页面开始加载或加载完成
:param timeout: 超时时间为None时使用页面timeout属性
:param start: 等待开始还是结束
:param gap: 间隔秒数
:return: 是否等待成功
"""
if timeout != 0:
@ -956,7 +957,7 @@ class ChromiumBaseWaiter(object):
while perf_counter() < end_time:
if self._driver.is_loading == start:
return True
sleep(.01)
sleep(gap)
return False

View File

@ -13,7 +13,7 @@ from requests.cookies import RequestsCookieJar
from .commons.constants import NoneElement
from .base import BasePage
from .chromium_driver import ChromiumDriver
from .chromium_element import ChromiumElement, ChromiumScroll, ChromiumWaiter
from .chromium_element import ChromiumElement, ChromiumScroll
from .chromium_frame import ChromiumFrame
from .session_element import SessionElement
@ -193,21 +193,21 @@ class ChromiumBase(BasePage):
timeout: float = None) -> Union[bool, None]: ...
class ChromiumBaseWaiter(ChromiumWaiter):
class ChromiumBaseWaiter(object):
def __init__(self, page: ChromiumBase):
self._driver: ChromiumBase = ...
def ele_delete(self, loc_or_ele: Union[str, tuple, ChromiumElement], timeout: Union[int, float]=None)->bool:...
def ele_delete(self, loc_or_ele: Union[str, tuple, ChromiumElement], timeout: float = None) -> bool: ...
def ele_display(self, loc_or_ele: Union[str, tuple, ChromiumElement], timeout: Union[int, float]=None)->bool:...
def ele_display(self, loc_or_ele: Union[str, tuple, ChromiumElement], timeout: float = None) -> bool: ...
def ele_hidden(self, loc_or_ele: Union[str, tuple, ChromiumElement], timeout: Union[int, float]=None)->bool:...
def ele_hidden(self, loc_or_ele: Union[str, tuple, ChromiumElement], timeout: float = None) -> bool: ...
def _loading(self, timeout: Union[int, float] = None, start: bool = True) -> bool: ...
def _loading(self, timeout: float = None, start: bool = True, gap: float = .01) -> bool: ...
def load_start(self, timeout: Union[int, float] = None) -> bool: ...
def load_start(self, timeout: float = None) -> bool: ...
def load_complete(self, timeout: Union[int, float] = None) -> bool: ...
def load_complete(self, timeout: float = None) -> bool: ...
def upload_paths_inputted(self) -> None: ...
@ -225,8 +225,7 @@ class ChromiumBaseSetter(object):
@property
def load_strategy(self) -> PageLoadStrategy: ...
def timeouts(self, implicit: Union[int, float] = None, page_load: Union[int, float] = None,
script: Union[int, float] = None): ...
def timeouts(self, implicit: float = None, page_load: float = None, script: float = None): ...
def user_agent(self, ua: str, platform: str = None) -> None: ...

View File

@ -39,7 +39,7 @@ class ChromiumDriver(object):
def __init__(self, tab_id: str, tab_type: str, address: str): ...
def _send(self, message: dict, timeout: Union[int, float] = None) -> dict: ...
def _send(self, message: dict, timeout: float = None) -> dict: ...
def _recv_loop(self) -> None: ...

View File

@ -15,7 +15,7 @@ from .commons.keys import keys_to_typing, keyDescriptionForString, keyDefinition
from .commons.locator import get_loc
from .commons.web import make_absolute_link, get_ele_txt, format_html, is_js_func, location_in_viewport, offset_scroll
from .errors import ContextLossError, ElementLossError, JavaScriptError, NoRectError, ElementNotFoundError, \
CallMethodError
CallMethodError, NoResourceError
from .session_element import make_session_ele
@ -401,26 +401,39 @@ class ChromiumElement(DrissionElement):
js = f'return window.getComputedStyle(this{pseudo_ele}).getPropertyValue("{style}");'
return self.run_js(js)
def get_src(self):
"""返回元素src资源base64的会转为bytes返回其它返回str"""
def get_src(self, timeout=None):
"""返回元素src资源base64的会转为bytes返回其它返回str
:param timeout: 等待资源加载的超时时间
:return: 资源内容
"""
src = self.prop('currentSrc')
if not src:
return None
timeout = self.page.timeout if timeout is None else timeout
if self.tag == 'img': # 等待图片加载完成
js = ('return this.complete && typeof this.naturalWidth != "undefined" '
'&& this.naturalWidth > 0 && typeof this.naturalHeight != "undefined" '
'&& this.naturalHeight > 0')
end_time = perf_counter() + self.page.timeout
end_time = perf_counter() + timeout
while not self.run_js(js) and perf_counter() < end_time:
sleep(.1)
node = self.page.run_cdp('DOM.describeNode', backendNodeId=self._backend_id)['node']
frame = node.get('frameId', None)
frame = frame or self.page.tab_id
try:
result = self.page.run_cdp('Page.getResourceContent', frameId=frame, url=src)
except Exception:
result = None
end_time = perf_counter() + timeout
while perf_counter() < end_time:
try:
result = self.page.run_cdp('Page.getResourceContent', frameId=frame, url=src)
except CallMethodError:
pass
sleep(.1)
if not result:
return None
if result['base64Encoded']:
@ -430,15 +443,16 @@ class ChromiumElement(DrissionElement):
data = result['content']
return data
def save(self, path=None, rename=None):
def save(self, path=None, rename=None, timeout=None):
"""保存图片或其它有src属性的元素的资源
:param path: 文件保存路径为None时保存到当前文件夹
:param rename: 文件名称为None时从资源url获取
:param timeout: 等待资源加载的超时时间
:return: None
"""
data = self.get_src()
data = self.get_src(timeout=timeout)
if not data:
raise TypeError('该元素无可保存的内容或保存失败。')
raise NoResourceError
path = path or '.'
rename = rename or basename(self.prop('currentSrc'))
@ -1615,61 +1629,30 @@ class Click(object):
"""
self._ele = ele
def __call__(self, by_js=None, retry=False, timeout=.2, wait_loading=0):
def __call__(self, by_js=None, wait_loading=0):
"""点击元素
如果遇到遮挡会重新尝试点击直到超时若都失败就改用js点击
:param by_js: 是否用js点击为True时直接用js点击为False时重试失败也不会改用js
:param retry: 遇到其它元素遮挡时是否重试
:param timeout: 尝试点击的超时时间不指定则使用父页面的超时时间retry为True时才生效
如果遇到遮挡可选择是否用js点击
:param by_js: 是否用js点击为None时先用模拟点击遇到遮挡改用js为True时直接用js点击为False时只用模拟点击
:param wait_loading: 等待页面进入加载状态超时时间
:return: 是否点击成功
"""
return self.left(by_js, retry, timeout, wait_loading)
return self.left(by_js, wait_loading)
def left(self, by_js=None, retry=False, timeout=.2, wait_loading=0):
def left(self, by_js=None, wait_loading=0):
"""点击元素
如果遇到遮挡会重新尝试点击直到超时若都失败就改用js点击
:param by_js: 是否用js点击为True时直接用js点击为False时重试失败也不会改用js
:param retry: 遇到其它元素遮挡时是否重试
:param timeout: 尝试点击的超时时间不指定则使用父页面的超时时间retry为True时才生效
如果遇到遮挡可选择是否用js点击
:param by_js: 是否用js点击为None时先用模拟点击遇到遮挡改用js为True时直接用js点击为False时只用模拟点击
:param wait_loading: 等待页面进入加载状态超时时间
:return: 是否点击成功
"""
def do_it(cx, cy, lx, ly):
"""无遮挡返回True有遮挡返回False无元素返回None"""
try:
r = self._ele.page.run_cdp('DOM.getNodeForLocation', x=lx, y=ly)
except CallMethodError:
return None
if retry and r.get('backendNodeId') != self._ele.ids.backend_id:
return False
self._click(cx, cy)
return True
if not by_js:
try:
self._ele.page.scroll.to_see(self._ele)
if self._ele.states.is_in_viewport:
if self._ele.states.is_in_viewport and not self._ele.states.is_covered:
client_x, client_y = self._ele.locations.viewport_click_point
if client_x:
loc_x, loc_y = self._ele.locations.click_point
click = do_it(client_x, client_y, loc_x, loc_y)
if click:
self._ele.page.wait.load_start(wait_loading)
return True
timeout = timeout if timeout is not None else self._ele.page.timeout
end_time = perf_counter() + timeout
while click is False and perf_counter() < end_time:
click = do_it(client_x, client_y, loc_x, loc_y)
if click is not None:
self._ele.page.wait.load_start(wait_loading)
return True
self._click(client_x, client_y)
self._ele.page.wait.load_start(wait_loading)
return True
except NoRectError:
by_js = True

View File

@ -30,7 +30,7 @@ class ChromiumElement(DrissionElement):
self._scroll: ChromiumScroll = ...
self._click: Click = ...
self._select: ChromiumSelect = ...
self._wait: ChromiumWaiter = ...
self._wait: ChromiumElementWaiter = ...
self._locations: Locations = ...
self._set: ChromiumElementSetter = ...
self._states: ChromiumElementStates = ...
@ -167,9 +167,9 @@ class ChromiumElement(DrissionElement):
def style(self, style: str, pseudo_ele: str = '') -> str: ...
def get_src(self) -> Union[bytes, str, None]: ...
def get_src(self, timeout: float = None) -> Union[bytes, str, None]: ...
def save(self, path: [str, bool] = None, rename: str = None) -> None: ...
def save(self, path: [str, bool] = None, rename: str = None, timeout: float = None) -> None: ...
def get_screenshot(self, path: [str, Path] = None, as_bytes: [bool, str] = None) -> Union[str, bytes]: ...
@ -430,11 +430,9 @@ class Click(object):
def __init__(self, ele: ChromiumElement):
self._ele: ChromiumElement = ...
def __call__(self, by_js: bool = None, retry: bool = False, timeout: float = 0.2,
wait_loading: Union[bool, float] = 0) -> bool: ...
def __call__(self, by_js: bool = None, wait_loading: Union[bool, float] = 0) -> bool: ...
def left(self, by_js: bool = None, retry: bool = False, timeout: float = 0.2,
wait_loading: Union[bool, float] = 0) -> bool: ...
def left(self, by_js: bool = None, wait_loading: Union[bool, float] = 0) -> bool: ...
def right(self): ...
@ -531,19 +529,19 @@ class ChromiumElementWaiter(object):
self._loc_or_ele: Union[str, tuple, ChromiumElement] = ...
self._driver: Union[ChromiumPage, ChromiumPage] = ...
def delete(self, timeout: Union[int, float] = None) -> bool: ...
def delete(self, timeout: float = None) -> bool: ...
def display(self, timeout: Union[int, float] = None) -> bool: ...
def display(self, timeout: float = None) -> bool: ...
def hidden(self, timeout: Union[int, float] = None) -> bool: ...
def hidden(self, timeout: float = None) -> bool: ...
def _covered(self, mode: bool = False, timeout: Union[int, float] = None) -> bool: ...
def _covered(self, mode: bool = False, timeout: float = None) -> bool: ...
def covered(self, timeout: Union[int, float] = None) -> bool: ...
def covered(self, timeout: float = None) -> bool: ...
def not_covered(self, timeout: Union[int, float] = None) -> bool: ...
def not_covered(self, timeout: float = None) -> bool: ...
def _wait_ele(self, mode: str, timeout: Union[int, float] = None) -> Union[None, bool]: ...
def _wait_ele(self, mode: str, timeout: float = None) -> Union[None, bool]: ...
class Pseudo(object):

View File

@ -109,7 +109,7 @@ class ChromiumPage(ChromiumBase):
class ChromiumPageWaiter(ChromiumBaseWaiter):
_driver: ChromiumPage = ...
def download_begin(self, timeout: Union[int, float] = None) -> bool: ...
def download_begin(self, timeout: float = None) -> bool: ...
class ChromiumTabRect(object):
@ -163,7 +163,7 @@ class ChromiumDownloadSetter(DownloadSetter):
def by_DownloadKit(self) -> None: ...
def wait_download_begin(self, timeout: Union[int, float] = None) -> bool: ...
def wait_download_begin(self, timeout: float = None) -> bool: ...
def _cookies_to_session(self) -> None: ...

View File

@ -75,8 +75,8 @@ class ChromiumOptions(object):
def remove_pref_from_file(self, arg: str) -> ChromiumOptions: ...
def set_timeouts(self, implicit: Union[int, float] = None, pageLoad: Union[int, float] = None,
script: Union[int, float] = None) -> ChromiumOptions: ...
def set_timeouts(self, implicit: float = None, pageLoad: float = None,
script: float = None) -> ChromiumOptions: ...
def set_user(self, user: str = 'Default') -> ChromiumOptions: ...

View File

@ -37,9 +37,9 @@ class SessionOptions(object):
def set_paths(self, download_path: Union[str, Path]) -> SessionOptions: ...
@property
def timeout(self) -> Union[int, float]: ...
def timeout(self) -> float: ...
def set_timeout(self, second: Union[int, float]) -> SessionOptions: ...
def set_timeout(self, second: float) -> SessionOptions: ...
@property
def headers(self) -> dict: ...

View File

@ -46,3 +46,7 @@ class NoRectError(BaseError):
class BrowserConnectError(BaseError):
_info = '浏览器连接失败。'
class NoResourceError(BaseError):
_info = '该元素无可保存的内容或保存失败。'

View File

@ -170,7 +170,7 @@ class SessionPageSetter(object):
def __init__(self, page: SessionPage):
self._page: SessionPage = ...
def timeout(self, second: Union[int, float]) -> None: ...
def timeout(self, second: float) -> None: ...
def cookies(self, cookies: Union[RequestsCookieJar, list, tuple, str, dict]) -> None: ...

View File

@ -164,7 +164,7 @@ class SessionPageSetter(object):
def __init__(self, page: SessionPage):
self._page: SessionPage = ...
def timeout(self, second: Union[int, float]) -> None: ...
def timeout(self, second: float) -> None: ...
def cookies(self, cookies: Union[RequestsCookieJar, list, tuple, str, dict]) -> None: ...