diff --git a/DrissionPage/_elements/chromium_element.py b/DrissionPage/_elements/chromium_element.py index 6ba1317..ab52c10 100644 --- a/DrissionPage/_elements/chromium_element.py +++ b/DrissionPage/_elements/chromium_element.py @@ -505,11 +505,12 @@ class ChromiumElement(DrissionElement): sleep(.1) src = self.attr('src') + if not src: + raise RuntimeError('元素没有src值或该值为空。') if src.lower().startswith('data:image'): if base64_to_bytes: from base64 import b64decode return b64decode(src.split(',', 1)[-1]) - else: return src.split(',', 1)[-1] diff --git a/DrissionPage/_functions/tools.py b/DrissionPage/_functions/tools.py index 38640cf..d89ff05 100644 --- a/DrissionPage/_functions/tools.py +++ b/DrissionPage/_functions/tools.py @@ -107,7 +107,7 @@ def show_or_hide_browser(page, hide=True): except ImportError: raise ImportError('请先安装:pip install pypiwin32') - pid = page.process_id + pid = page._page.process_id if not pid: return None hds = get_hwnds_from_pid(pid, page.title) diff --git a/DrissionPage/_functions/tools.pyi b/DrissionPage/_functions/tools.pyi index 86d3527..a6fc535 100644 --- a/DrissionPage/_functions/tools.pyi +++ b/DrissionPage/_functions/tools.pyi @@ -10,7 +10,7 @@ from pathlib import Path from threading import Lock from typing import Union, Tuple -from .._pages.chromium_page import ChromiumPage +from .._pages.chromium_base import ChromiumBase class PortFinder(object): @@ -30,7 +30,7 @@ def port_is_using(ip: str, port: Union[str, int]) -> bool: ... def clean_folder(folder_path: Union[str, Path], ignore: Union[tuple, list] = None) -> None: ... -def show_or_hide_browser(page: ChromiumPage, hide: bool = True) -> None: ... +def show_or_hide_browser(page: ChromiumBase, hide: bool = True) -> None: ... def get_browser_progress_id(progress: Union[popen, None], address: str) -> Union[str, None]: ... diff --git a/DrissionPage/_pages/web_page.py b/DrissionPage/_pages/web_page.py index 39fa3a0..1e9cb6c 100644 --- a/DrissionPage/_pages/web_page.py +++ b/DrissionPage/_pages/web_page.py @@ -31,7 +31,7 @@ class WebPage(SessionPage, ChromiumPage, BasePage): """初始化函数 :param mode: 'd' 或 's',即driver模式和session模式 :param timeout: 超时时间(秒),d模式时为寻找元素时间,s模式时为连接时间,默认10秒 - :param chromium_options: Driver对象,只使用s模式时应传入False + :param chromium_options: ChromiumOptions对象,只使用s模式时应传入False :param session_or_options: Session对象或SessionOptions对象,只使用d模式时应传入False """ if hasattr(self, '_created'): diff --git a/DrissionPage/_units/clicker.py b/DrissionPage/_units/clicker.py index 0c9efc2..40113ed 100644 --- a/DrissionPage/_units/clicker.py +++ b/DrissionPage/_units/clicker.py @@ -184,17 +184,6 @@ class Clicker(object): raise RuntimeError('没有出现新标签页。') return self._ele.page.get_tab(tid) - def for_new_tab(self, by_js=False): - """点击后等待新tab出现并返回其对象 - :param by_js: 是否使用js点击,逻辑与click()一致 - :return: 新标签页对象,如果没有等到新标签页出现则抛出异常 - """ - self.left(by_js=by_js) - tid = self._ele.page._page.wait.new_tab() - if not tid: - raise RuntimeError('没有出现新标签页。') - return self._ele.page._page.get_tab(tid) - def _click(self, client_x, client_y, button='left', count=1): """实施点击 :param client_x: 视口中的x坐标 diff --git a/DrissionPage/_units/cookies_setter.py b/DrissionPage/_units/cookies_setter.py index 63bcc2f..ccdf70c 100644 --- a/DrissionPage/_units/cookies_setter.py +++ b/DrissionPage/_units/cookies_setter.py @@ -11,8 +11,11 @@ from .._functions.web import set_browser_cookies, set_session_cookies class CookiesSetter(object): - def __init__(self, page): - self._page = page + def __init__(self, owner): + """ + :param owner: ChromiumBase对象 + """ + self._owner = owner def __call__(self, cookies): """设置一个或多个cookie @@ -21,7 +24,7 @@ class CookiesSetter(object): """ if (isinstance(cookies, dict) and 'name' in cookies and 'value' in cookies) or isinstance(cookies, Cookie): cookies = [cookies] - set_browser_cookies(self._page, cookies) + set_browser_cookies(self._owner, cookies) def remove(self, name, url=None, domain=None, path=None): """删除一个cookie @@ -36,18 +39,20 @@ class CookiesSetter(object): d['url'] = url if domain is not None: d['domain'] = domain + if not url and not domain: + d['url'] = self._owner.url if path is not None: d['path'] = path - self._page.run_cdp('Network.deleteCookies', **d) + self._owner.run_cdp('Network.deleteCookies', **d) def clear(self): """清除cookies""" - self._page.run_cdp('Network.clearBrowserCookies') + self._owner.run_cdp('Network.clearBrowserCookies') class SessionCookiesSetter(object): - def __init__(self, page): - self._page = page + def __init__(self, owner): + self._owner = owner def __call__(self, cookies): """设置多个cookie,注意不要传入单个 @@ -56,18 +61,18 @@ class SessionCookiesSetter(object): """ if (isinstance(cookies, dict) and 'name' in cookies and 'value' in cookies) or isinstance(cookies, Cookie): cookies = [cookies] - set_session_cookies(self._page.session, cookies) + set_session_cookies(self._owner.session, cookies) def remove(self, name): """删除一个cookie :param name: cookie的name字段 :return: None """ - self._page.session.cookies.set(name, None) + self._owner.session.cookies.set(name, None) def clear(self): """清除cookies""" - self._page.session.cookies.clear() + self._owner.session.cookies.clear() class WebPageCookiesSetter(CookiesSetter, SessionCookiesSetter): @@ -77,9 +82,9 @@ class WebPageCookiesSetter(CookiesSetter, SessionCookiesSetter): :param cookies: cookies信息 :return: None """ - if self._page.mode == 'd' and self._page._has_driver: + if self._owner.mode == 'd' and self._owner._has_driver: super().__call__(cookies) - elif self._page.mode == 's' and self._page._has_session: + elif self._owner.mode == 's' and self._owner._has_session: super(CookiesSetter, self).__call__(cookies) def remove(self, name, url=None, domain=None, path=None): @@ -90,16 +95,16 @@ class WebPageCookiesSetter(CookiesSetter, SessionCookiesSetter): :param path: cookie的path字段,可选,d模式时才有效 :return: None """ - if self._page.mode == 'd' and self._page._has_driver: + if self._owner.mode == 'd' and self._owner._has_driver: super().remove(name, url, domain, path) - elif self._page.mode == 's' and self._page._has_session: + elif self._owner.mode == 's' and self._owner._has_session: if url or domain or path: raise AttributeError('url、domain、path参数只有d模式下有效。') super(CookiesSetter, self).remove(name) def clear(self): """清除cookies""" - if self._page.mode == 'd' and self._page._has_driver: + if self._owner.mode == 'd' and self._owner._has_driver: super().clear() - elif self._page.mode == 's' and self._page._has_session: + elif self._owner.mode == 's' and self._owner._has_session: super(CookiesSetter, self).clear() diff --git a/DrissionPage/_units/cookies_setter.pyi b/DrissionPage/_units/cookies_setter.pyi index 3c6f37a..fea2f13 100644 --- a/DrissionPage/_units/cookies_setter.pyi +++ b/DrissionPage/_units/cookies_setter.pyi @@ -17,7 +17,7 @@ from .._pages.web_page import WebPage class CookiesSetter(object): - _page: ChromiumBase + _owner: ChromiumBase def __init__(self, page: ChromiumBase): ... @@ -29,7 +29,7 @@ class CookiesSetter(object): class SessionCookiesSetter(object): - _page: SessionPage + _owner: SessionPage def __init__(self, page: SessionPage): ... @@ -41,7 +41,7 @@ class SessionCookiesSetter(object): class WebPageCookiesSetter(CookiesSetter, SessionCookiesSetter): - _page: Union[WebPage, WebPageTab] + _owner: Union[WebPage, WebPageTab] def __init__(self, page: SessionPage): ... diff --git a/DrissionPage/_units/downloader.pyi b/DrissionPage/_units/downloader.pyi index 45537f1..eadcc44 100644 --- a/DrissionPage/_units/downloader.pyi +++ b/DrissionPage/_units/downloader.pyi @@ -30,7 +30,7 @@ class DownloadManager(object): def set_rename(self, tab_id: str, rename: str = None, suffix: str = None) -> None: ... - def set_file_exists(self, tab_id: str, mode: Literal['rename', 'skip', 'overwrite']) -> None: ... + def set_file_exists(self, tab_id: str, mode: Literal['skip', 'rename', 'overwrite', 's', 'r', 'o']) -> None: ... def set_flag(self, tab_id: str, flag: Union[bool, DownloadMission, None]) -> None: ... diff --git a/DrissionPage/_units/listener.py b/DrissionPage/_units/listener.py index dd5de19..dc981f7 100644 --- a/DrissionPage/_units/listener.py +++ b/DrissionPage/_units/listener.py @@ -21,13 +21,13 @@ from ..errors import WaitTimeoutError class Listener(object): """监听器基类""" - def __init__(self, page): + def __init__(self, owner): """ - :param page: ChromiumBase对象 + :param owner: ChromiumBase对象 """ - self._page = page - self._address = page.address - self._target_id = page._target_id + self._owner = owner + self._address = owner.address + self._target_id = owner._target_id self._driver = None self._running_requests = 0 self._running_targets = 0 @@ -237,16 +237,16 @@ class Listener(object): else: return False - def _to_target(self, target_id, address, page): + def _to_target(self, target_id, address, owner): """切换监听的页面对象 :param target_id: 新页面对象_target_id :param address: 新页面对象address - :param page: 新页面对象 + :param owner: 新页面对象 :return: None """ self._target_id = target_id self._address = address - self._page = page + self._owner = owner debug = False if self._driver: debug = self._driver._debug @@ -275,7 +275,7 @@ class Listener(object): and (self._res_type is True or kwargs.get('type', '').upper() in self._res_type)): self._running_targets += 1 rid = kwargs['requestId'] - p = self._request_ids.setdefault(rid, DataPacket(self._page.tab_id, True)) + p = self._request_ids.setdefault(rid, DataPacket(self._owner.tab_id, True)) p._raw_request = kwargs if kwargs['request'].get('hasPostData', None) and not kwargs['request'].get('postData', None): p._raw_post_data = self._driver.run('Network.getRequestPostData', @@ -289,7 +289,7 @@ class Listener(object): and (self._method is True or kwargs['request']['method'] in self._method) and (self._res_type is True or kwargs.get('type', '').upper() in self._res_type)): self._running_targets += 1 - p = self._request_ids.setdefault(rid, DataPacket(self._page.tab_id, target)) + p = self._request_ids.setdefault(rid, DataPacket(self._owner.tab_id, target)) p._raw_request = kwargs break @@ -390,13 +390,13 @@ class Listener(object): class FrameListener(Listener): def _requestWillBeSent(self, **kwargs): """接收到请求时的回调函数""" - if not self._page._is_diff_domain and kwargs.get('frameId', None) != self._page._frame_id: + if not self._owner._is_diff_domain and kwargs.get('frameId', None) != self._owner._frame_id: return super()._requestWillBeSent(**kwargs) def _response_received(self, **kwargs): """接收到返回信息时处理方法""" - if not self._page._is_diff_domain and kwargs.get('frameId', None) != self._page._frame_id: + if not self._owner._is_diff_domain and kwargs.get('frameId', None) != self._owner._frame_id: return super()._response_received(**kwargs) diff --git a/DrissionPage/_units/listener.pyi b/DrissionPage/_units/listener.pyi index a8fc984..5de2033 100644 --- a/DrissionPage/_units/listener.pyi +++ b/DrissionPage/_units/listener.pyi @@ -19,8 +19,8 @@ __RES_TYPE__ = Literal['Document', 'Stylesheet', 'Image', 'Media', 'Font', 'Scri class Listener(object): - def __init__(self, page: ChromiumBase): - self._page: ChromiumBase = ... + def __init__(self, owner: ChromiumBase): + self._owner: ChromiumBase = ... self._address: str = ... self._target_id: str = ... self._targets: Union[str, dict, None] = ... @@ -69,7 +69,7 @@ class Listener(object): def wait_silent(self, timeout: float = None, targets_only: bool = False) -> bool: ... - def _to_target(self, target_id: str, address: str, page: ChromiumBase) -> None: ... + def _to_target(self, target_id: str, address: str, owner: ChromiumBase) -> None: ... def _requestWillBeSent(self, **kwargs) -> None: ... @@ -92,8 +92,8 @@ class Listener(object): class FrameListener(Listener): - def __init__(self, page: ChromiumFrame): - self._page: ChromiumFrame = ... + def __init__(self, owner: ChromiumFrame): + self._owner: ChromiumFrame = ... self._is_diff: bool = ... diff --git a/DrissionPage/_units/rect.py b/DrissionPage/_units/rect.py index 55baa6b..c6f26ee 100644 --- a/DrissionPage/_units/rect.py +++ b/DrissionPage/_units/rect.py @@ -113,8 +113,8 @@ class ElementRect(object): class TabRect(object): - def __init__(self, page): - self._page = page + def __init__(self, owner): + self._owner = owner @property def window_state(self): @@ -170,17 +170,17 @@ class TabRect(object): @property def viewport_size_with_scrollbar(self): """返回视口宽高,包括滚动条,格式:(宽, 高)""" - r = self._page.run_js('return window.innerWidth.toString() + " " + window.innerHeight.toString();') + r = self._owner.run_js('return window.innerWidth.toString() + " " + window.innerHeight.toString();') w, h = r.split(' ') return int(w), int(h) def _get_page_rect(self): """获取页面范围信息""" - return self._page.run_cdp_loaded('Page.getLayoutMetrics') + return self._owner.run_cdp_loaded('Page.getLayoutMetrics') def _get_window_rect(self): """获取窗口范围信息""" - return self._page.browser.get_window_bounds(self._page.tab_id) + return self._owner.browser.get_window_bounds(self._owner.tab_id) class FrameRect(object): diff --git a/DrissionPage/_units/rect.pyi b/DrissionPage/_units/rect.pyi index 62fadc1..4de0caf 100644 --- a/DrissionPage/_units/rect.pyi +++ b/DrissionPage/_units/rect.pyi @@ -62,8 +62,8 @@ class ElementRect(object): class TabRect(object): - def __init__(self, page: ChromiumBase): - self._page: Union[ChromiumPage, ChromiumTab, WebPage, WebPageTab] = ... + def __init__(self, owner: Union[ChromiumPage, ChromiumTab, WebPage, WebPageTab]): + self._owner: Union[ChromiumPage, ChromiumTab, WebPage, WebPageTab] = ... @property def window_state(self) -> str: ... diff --git a/DrissionPage/_units/screencast.py b/DrissionPage/_units/screencast.py index 958dbfc..fca2b68 100644 --- a/DrissionPage/_units/screencast.py +++ b/DrissionPage/_units/screencast.py @@ -16,8 +16,8 @@ from time import sleep, time class Screencast(object): - def __init__(self, page): - self._page = page + def __init__(self, owner): + self._owner = owner self._path = None self._tmp_path = None self._running = False @@ -39,16 +39,16 @@ class Screencast(object): raise ValueError('save_path必须设置。') if self._mode in ('frugal_video', 'video'): - if self._page.browser.page._chromium_options.tmp_path: + if self._owner.browser.page._chromium_options.tmp_path: self._tmp_path = Path( - self._page.browser.page._chromium_options.tmp_path) / f'screencast_tmp_{time()}_{randint(0, 100)}' + self._owner.browser.page._chromium_options.tmp_path) / f'screencast_tmp_{time()}_{randint(0, 100)}' else: self._tmp_path = Path(gettempdir()) / 'DrissionPage' / f'screencast_tmp_{time()}_{randint(0, 100)}' self._tmp_path.mkdir(parents=True, exist_ok=True) if self._mode.startswith('frugal'): - self._page.driver.set_callback('Page.screencastFrame', self._onScreencastFrame) - self._page.run_cdp('Page.startScreencast', everyNthFrame=1, quality=100) + self._owner.driver.set_callback('Page.screencastFrame', self._onScreencastFrame) + self._owner.run_cdp('Page.startScreencast', everyNthFrame=1, quality=100) elif not self._mode.startswith('js'): self._running = True @@ -79,8 +79,8 @@ class Screencast(object): } ''' print('请手动选择要录制的目标。') - self._page.run_js('var DrissionPage_Screencast_blob;var DrissionPage_Screencast_blob_ok=false;') - self._page.run_js(js) + self._owner.run_js('var DrissionPage_Screencast_blob;var DrissionPage_Screencast_blob_ok=false;') + self._owner.run_js(js) def stop(self, video_name=None): """停止录屏 @@ -93,19 +93,19 @@ class Screencast(object): path = f'{self._path}{sep}{name}' if self._mode.startswith('js'): - self._page.run_js('mediaRecorder.stop();', as_expr=True) - while not self._page.run_js('return DrissionPage_Screencast_blob_ok;'): + self._owner.run_js('mediaRecorder.stop();', as_expr=True) + while not self._owner.run_js('return DrissionPage_Screencast_blob_ok;'): sleep(.1) - blob = self._page.run_js('return DrissionPage_Screencast_blob;') - uuid = self._page.run_cdp('IO.resolveBlob', objectId=blob['result']['objectId'])['uuid'] - data = self._page.run_cdp('IO.read', handle=f'blob:{uuid}')['data'] + blob = self._owner.run_js('return DrissionPage_Screencast_blob;') + uuid = self._owner.run_cdp('IO.resolveBlob', objectId=blob['result']['objectId'])['uuid'] + data = self._owner.run_cdp('IO.read', handle=f'blob:{uuid}')['data'] with open(path, 'wb') as f: f.write(b64decode(data)) return path if self._mode.startswith('frugal'): - self._page.driver.set_callback('Page.screencastFrame', None) - self._page.run_cdp('Page.stopScreencast') + self._owner.driver.set_callback('Page.screencastFrame', None) + self._owner.run_cdp('Page.stopScreencast') else: self._enable = False while self._running: @@ -155,7 +155,7 @@ class Screencast(object): self._running = True path = self._tmp_path or self._path while self._enable: - self._page.get_screenshot(path=path, name=f'{time()}.jpg') + self._owner.get_screenshot(path=path, name=f'{time()}.jpg') sleep(.04) self._running = False @@ -164,7 +164,7 @@ class Screencast(object): path = self._tmp_path or self._path with open(f'{path}{sep}{kwargs["metadata"]["timestamp"]}.jpg', 'wb') as f: f.write(b64decode(kwargs['data'])) - self._page.run_cdp('Page.screencastFrameAck', sessionId=kwargs['sessionId']) + self._owner.run_cdp('Page.screencastFrameAck', sessionId=kwargs['sessionId']) class ScreencastMode(object): diff --git a/DrissionPage/_units/screencast.pyi b/DrissionPage/_units/screencast.pyi index 92d7d0f..ec69ea4 100644 --- a/DrissionPage/_units/screencast.pyi +++ b/DrissionPage/_units/screencast.pyi @@ -12,8 +12,8 @@ from .._pages.chromium_base import ChromiumBase class Screencast(object): - def __init__(self, page: ChromiumBase): - self._page: ChromiumBase = ... + def __init__(self, owner: ChromiumBase): + self._owner: ChromiumBase = ... self._path: Path = ... self._tmp_path: Path = ... self._running: bool = ... diff --git a/DrissionPage/_units/scroller.py b/DrissionPage/_units/scroller.py index cacdfee..6a15fd6 100644 --- a/DrissionPage/_units/scroller.py +++ b/DrissionPage/_units/scroller.py @@ -87,15 +87,15 @@ class Scroller(object): if not self._wait_complete: return - page = self._driver.owner if self._driver._type == 'ChromiumElement' else self._driver - r = page.run_cdp('Page.getLayoutMetrics') + owner = self._driver.owner if self._driver._type == 'ChromiumElement' else self._driver + r = owner.run_cdp('Page.getLayoutMetrics') x = r['layoutViewport']['pageX'] y = r['layoutViewport']['pageY'] - end_time = perf_counter() + page.timeout + end_time = perf_counter() + owner.timeout while perf_counter() < end_time: sleep(.1) - r = page.run_cdp('Page.getLayoutMetrics') + r = owner.run_cdp('Page.getLayoutMetrics') x1 = r['layoutViewport']['pageX'] y1 = r['layoutViewport']['pageY'] @@ -120,11 +120,11 @@ class ElementScroller(Scroller): class PageScroller(Scroller): - def __init__(self, page): + def __init__(self, owner): """ - :param page: 页面对象 + :param owner: 页面对象 """ - super().__init__(page) + super().__init__(owner) self.t1 = 'window' self.t2 = 'document.documentElement' diff --git a/DrissionPage/_units/scroller.pyi b/DrissionPage/_units/scroller.pyi index 8233948..7e8b7c6 100644 --- a/DrissionPage/_units/scroller.pyi +++ b/DrissionPage/_units/scroller.pyi @@ -51,7 +51,7 @@ class ElementScroller(Scroller): class PageScroller(Scroller): - def __init__(self, page: ChromiumBase): ... + def __init__(self, owner: ChromiumBase): ... def to_see(self, loc_or_ele: Union[str, tuple, ChromiumElement], center: Union[bool, None] = None) -> None: ... diff --git a/DrissionPage/_units/setter.py b/DrissionPage/_units/setter.py index d625d95..473d73a 100644 --- a/DrissionPage/_units/setter.py +++ b/DrissionPage/_units/setter.py @@ -16,8 +16,11 @@ from .._functions.web import format_headers class BasePageSetter(object): - def __init__(self, page): - self._page = page + def __init__(self, owner): + """ + :param owner: BasePage对象 + """ + self._owner = owner def NoneElement_value(self, value=None, on_off=True): """设置空元素是否返回设定值 @@ -25,39 +28,42 @@ class BasePageSetter(object): :param on_off: 是否启用 :return: None """ - self._page._none_ele_return_value = on_off - self._page._none_ele_value = value + self._owner._none_ele_return_value = on_off + self._owner._none_ele_value = value class ChromiumBaseSetter(BasePageSetter): - def __init__(self, page): - super().__init__(page) + def __init__(self, owner): + """ + :param owner: ChromiumBase对象 + """ + super().__init__(owner) self._cookies_setter = None @property def load_mode(self): """返回用于设置页面加载策略的对象""" - return LoadMode(self._page) + return LoadMode(self._owner) @property def scroll(self): """返回用于设置页面滚动设置的对象""" - return PageScrollSetter(self._page.scroll) + return PageScrollSetter(self._owner.scroll) @property def cookies(self): """返回用于设置cookies的对象""" if self._cookies_setter is None: - self._cookies_setter = CookiesSetter(self._page) + self._cookies_setter = CookiesSetter(self._owner) return self._cookies_setter def retry_times(self, times): """设置连接失败重连次数""" - self._page.retry_times = times + self._owner.retry_times = times def retry_interval(self, interval): """设置连接失败重连间隔""" - self._page.retry_interval = interval + self._owner.retry_interval = interval def timeouts(self, base=None, page_load=None, script=None, implicit=None): """设置超时时间,单位为秒 @@ -68,14 +74,14 @@ class ChromiumBaseSetter(BasePageSetter): """ base = base if base is not None else implicit if base is not None: - self._page.timeouts.base = base - self._page._timeout = base + self._owner.timeouts.base = base + self._owner._timeout = base if page_load is not None: - self._page.timeouts.page_load = page_load + self._owner.timeouts.page_load = page_load if script is not None: - self._page.timeouts.script = script + self._owner.timeouts.script = script def user_agent(self, ua, platform=None): """为当前tab设置user agent,只在当前tab有效 @@ -86,7 +92,7 @@ class ChromiumBaseSetter(BasePageSetter): keys = {'userAgent': ua} if platform: keys['platform'] = platform - self._page.run_cdp('Emulation.setUserAgentOverride', **keys) + self._owner.run_cdp('Emulation.setUserAgentOverride', **keys) def session_storage(self, item, value): """设置或删除某项sessionStorage信息 @@ -94,15 +100,15 @@ class ChromiumBaseSetter(BasePageSetter): :param value: 项的值,设置为False时,删除该项 :return: None """ - self._page.run_cdp_loaded('DOMStorage.enable') - i = self._page.run_cdp('Storage.getStorageKeyForFrame', frameId=self._page._frame_id)['storageKey'] + self._owner.run_cdp_loaded('DOMStorage.enable') + i = self._owner.run_cdp('Storage.getStorageKeyForFrame', frameId=self._owner._frame_id)['storageKey'] if value is False: - self._page.run_cdp('DOMStorage.removeDOMStorageItem', - storageId={'storageKey': i, 'isLocalStorage': False}, key=item) + self._owner.run_cdp('DOMStorage.removeDOMStorageItem', + storageId={'storageKey': i, 'isLocalStorage': False}, key=item) else: - self._page.run_cdp('DOMStorage.setDOMStorageItem', storageId={'storageKey': i, 'isLocalStorage': False}, - key=item, value=value) - self._page.run_cdp_loaded('DOMStorage.disable') + self._owner.run_cdp('DOMStorage.setDOMStorageItem', storageId={'storageKey': i, 'isLocalStorage': False}, + key=item, value=value) + self._owner.run_cdp_loaded('DOMStorage.disable') def local_storage(self, item, value): """设置或删除某项localStorage信息 @@ -110,38 +116,38 @@ class ChromiumBaseSetter(BasePageSetter): :param value: 项的值,设置为False时,删除该项 :return: None """ - self._page.run_cdp_loaded('DOMStorage.enable') - i = self._page.run_cdp('Storage.getStorageKeyForFrame', frameId=self._page._frame_id)['storageKey'] + self._owner.run_cdp_loaded('DOMStorage.enable') + i = self._owner.run_cdp('Storage.getStorageKeyForFrame', frameId=self._owner._frame_id)['storageKey'] if value is False: - self._page.run_cdp('DOMStorage.removeDOMStorageItem', - storageId={'storageKey': i, 'isLocalStorage': True}, key=item) + self._owner.run_cdp('DOMStorage.removeDOMStorageItem', + storageId={'storageKey': i, 'isLocalStorage': True}, key=item) else: - self._page.run_cdp('DOMStorage.setDOMStorageItem', storageId={'storageKey': i, 'isLocalStorage': True}, - key=item, value=value) - self._page.run_cdp_loaded('DOMStorage.disable') + self._owner.run_cdp('DOMStorage.setDOMStorageItem', storageId={'storageKey': i, 'isLocalStorage': True}, + key=item, value=value) + self._owner.run_cdp_loaded('DOMStorage.disable') def upload_files(self, files): """等待上传的文件路径 :param files: 文件路径列表或字符串,字符串时多个文件用回车分隔 :return: None """ - if not self._page._upload_list: - self._page.driver.set_callback('Page.fileChooserOpened', self._page._onFileChooserOpened) - self._page.run_cdp('Page.setInterceptFileChooserDialog', enabled=True) + if not self._owner._upload_list: + self._owner.driver.set_callback('Page.fileChooserOpened', self._owner._onFileChooserOpened) + self._owner.run_cdp('Page.setInterceptFileChooserDialog', enabled=True) if isinstance(files, str): files = files.split('\n') elif isinstance(files, Path): - files = (files, ) - self._page._upload_list = [str(Path(i).absolute()) for i in files] + files = (files,) + self._owner._upload_list = [str(Path(i).absolute()) for i in files] def headers(self, headers) -> None: """设置固定发送的headers :param headers: dict格式的headers数据 :return: None """ - self._page.run_cdp('Network.enable') - self._page.run_cdp('Network.setExtraHTTPHeaders', headers=format_headers(headers)) + self._owner.run_cdp('Network.enable') + self._owner.run_cdp('Network.setExtraHTTPHeaders', headers=format_headers(headers)) def auto_handle_alert(self, on_off=True, accept=True): """设置是否启用自动处理弹窗 @@ -149,7 +155,7 @@ class ChromiumBaseSetter(BasePageSetter): :param accept: bool表示确定还是取消 :return: None """ - self._page._alert.auto = accept if on_off else None + self._owner._alert.auto = accept if on_off else None def blocked_urls(self, urls): """设置要忽略的url @@ -162,25 +168,28 @@ class ChromiumBaseSetter(BasePageSetter): urls = (urls,) if not isinstance(urls, (list, tuple)): raise TypeError('urls需传入str、list或tuple类型。') - self._page.run_cdp('Network.enable') - self._page.run_cdp('Network.setBlockedURLs', urls=urls) + self._owner.run_cdp('Network.enable') + self._owner.run_cdp('Network.setBlockedURLs', urls=urls) # --------------即将废弃--------------- @property def load_strategy(self): """返回用于设置页面加载策略的对象""" - return LoadMode(self._page) + return LoadMode(self._owner) class TabSetter(ChromiumBaseSetter): - def __init__(self, page): - super().__init__(page) + def __init__(self, owner): + """ + :param owner: 标签页对象 + """ + super().__init__(owner) @property def window(self): """返回用于设置浏览器窗口的对象""" - return WindowSetter(self._page) + return WindowSetter(self._owner) def download_path(self, path): """设置下载路径 @@ -188,10 +197,10 @@ class TabSetter(ChromiumBaseSetter): :return: None """ path = str(Path(path).absolute()) - self._page._download_path = path - self._page.browser._dl_mgr.set_path(self._page, path) - if self._page._DownloadKit: - self._page._DownloadKit.set.goal_path(path) + self._owner._download_path = path + self._owner.browser._dl_mgr.set_path(self._owner, path) + if self._owner._DownloadKit: + self._owner._DownloadKit.set.goal_path(path) def download_file_name(self, name=None, suffix=None): """设置下一个被下载文件的名称 @@ -199,7 +208,7 @@ class TabSetter(ChromiumBaseSetter): :param suffix: 后缀名,显式设置后缀名,不使用远程文件后缀 :return: None """ - self._page.browser._dl_mgr.set_rename(self._page.tab_id, name, suffix) + self._owner.browser._dl_mgr.set_rename(self._owner.tab_id, name, suffix) def when_download_file_exists(self, mode): """设置当存在同名文件时的处理方式 @@ -212,11 +221,11 @@ class TabSetter(ChromiumBaseSetter): if mode not in types: raise ValueError(f'''mode参数只能是 '{"', '".join(types.keys())}' 之一,现在是:{mode}''') - self._page.browser._dl_mgr.set_file_exists(self._page.tab_id, mode) + self._owner.browser._dl_mgr.set_file_exists(self._owner.tab_id, mode) def activate(self): """使标签页处于最前面""" - self._page.browser.activate_tab(self._page.tab_id) + self._owner.browser.activate_tab(self._owner.tab_id) class ChromiumPageSetter(TabSetter): @@ -227,39 +236,34 @@ class ChromiumPageSetter(TabSetter): :return: None """ if not tab_or_id: - tab_or_id = self._page.tab_id + tab_or_id = self._owner.tab_id elif not isinstance(tab_or_id, str): # 传入Tab对象 tab_or_id = tab_or_id.tab_id - self._page.browser.activate_tab(tab_or_id) - - @property - def window(self): - """返回用于设置浏览器窗口的对象""" - return PageWindowSetter(self._page) + self._owner.browser.activate_tab(tab_or_id) class SessionPageSetter(BasePageSetter): - def __init__(self, page): + def __init__(self, owner): """ - :param page: SessionPage对象 + :param owner: SessionPage对象 """ - super().__init__(page) + super().__init__(owner) self._cookies_setter = None @property def cookies(self): """返回用于设置cookies的对象""" if self._cookies_setter is None: - self._cookies_setter = SessionCookiesSetter(self._page) + self._cookies_setter = SessionCookiesSetter(self._owner) return self._cookies_setter def retry_times(self, times): """设置连接失败时重连次数""" - self._page.retry_times = times + self._owner.retry_times = times def retry_interval(self, interval): """设置连接失败时重连间隔""" - self._page.retry_interval = interval + self._owner.retry_interval = interval def download_path(self, path): """设置下载路径 @@ -267,16 +271,16 @@ class SessionPageSetter(BasePageSetter): :return: None """ path = str(Path(path).absolute()) - self._page._download_path = path - if self._page._DownloadKit: - self._page._DownloadKit.set.goal_path(path) + self._owner._download_path = path + if self._owner._DownloadKit: + self._owner._DownloadKit.set.goal_path(path) def timeout(self, second): """设置连接超时时间 :param second: 秒数 :return: None """ - self._page.timeout = second + self._owner.timeout = second def encoding(self, encoding, set_all=True): """设置编码 @@ -285,16 +289,16 @@ class SessionPageSetter(BasePageSetter): :return: None """ if set_all: - self._page._encoding = encoding if encoding else None - if self._page.response: - self._page.response.encoding = encoding + self._owner._encoding = encoding if encoding else None + if self._owner.response: + self._owner.response.encoding = encoding def headers(self, headers): """设置通用的headers :param headers: dict形式的headers :return: None """ - self._page._headers = CaseInsensitiveDict(format_headers(headers)) + self._owner._headers = CaseInsensitiveDict(format_headers(headers)) def header(self, name, value): """设置headers中一个项 @@ -302,14 +306,14 @@ class SessionPageSetter(BasePageSetter): :param value: 设置值 :return: None """ - self._page._headers[name] = value + self._owner._headers[name] = value def user_agent(self, ua): """设置user agent :param ua: user agent :return: None """ - self._page._headers['user-agent'] = ua + self._owner._headers['user-agent'] = ua def proxies(self, http=None, https=None): """设置proxies参数 @@ -317,63 +321,63 @@ class SessionPageSetter(BasePageSetter): :param https: https代理地址 :return: None """ - self._page.session.proxies = {'http': http, 'https': https} + self._owner.session.proxies = {'http': http, 'https': https} def auth(self, auth): """设置认证元组或对象 :param auth: 认证元组或对象 :return: None """ - self._page.session.auth = auth + self._owner.session.auth = auth def hooks(self, hooks): """设置回调方法 :param hooks: 回调方法 :return: None """ - self._page.session.hooks = hooks + self._owner.session.hooks = hooks def params(self, params): """设置查询参数字典 :param params: 查询参数字典 :return: None """ - self._page.session.params = params + self._owner.session.params = params def verify(self, on_off): """设置是否验证SSL证书 :param on_off: 是否验证 SSL 证书 :return: None """ - self._page.session.verify = on_off + self._owner.session.verify = on_off def cert(self, cert): """SSL客户端证书文件的路径(.pem格式),或(‘cert’, ‘key’)元组 :param cert: 证书路径或元组 :return: None """ - self._page.session.cert = cert + self._owner.session.cert = cert def stream(self, on_off): """设置是否使用流式响应内容 :param on_off: 是否使用流式响应内容 :return: None """ - self._page.session.stream = on_off + self._owner.session.stream = on_off def trust_env(self, on_off): """设置是否信任环境 :param on_off: 是否信任环境 :return: None """ - self._page.session.trust_env = on_off + self._owner.session.trust_env = on_off def max_redirects(self, times): """设置最大重定向次数 :param times: 最大重定向次数 :return: None """ - self._page.session.max_redirects = times + self._owner.session.max_redirects = times def add_adapter(self, url, adapter): """添加适配器 @@ -381,20 +385,20 @@ class SessionPageSetter(BasePageSetter): :param adapter: 适配器对象 :return: None """ - self._page.session.mount(url, adapter) + self._owner.session.mount(url, adapter) class WebPageSetter(ChromiumPageSetter): - def __init__(self, page): - super().__init__(page) - self._session_setter = SessionPageSetter(self._page) - self._chromium_setter = ChromiumPageSetter(self._page) + def __init__(self, owner): + super().__init__(owner) + self._session_setter = SessionPageSetter(self._owner) + self._chromium_setter = ChromiumPageSetter(self._owner) @property def cookies(self): """返回用于设置cookies的对象""" if self._cookies_setter is None: - self._cookies_setter = WebPageCookiesSetter(self._page) + self._cookies_setter = WebPageCookiesSetter(self._owner) return self._cookies_setter def headers(self, headers) -> None: @@ -402,30 +406,30 @@ class WebPageSetter(ChromiumPageSetter): :param headers: dict格式的headers数据 :return: None """ - if self._page.mode == 's': + if self._owner.mode == 's': self._session_setter.headers(headers) else: self._chromium_setter.headers(headers) def user_agent(self, ua, platform=None): """设置user agent,d模式下只有当前tab有效""" - if self._page.mode == 's': + if self._owner.mode == 's': self._session_setter.user_agent(ua) else: self._chromium_setter.user_agent(ua, platform) class WebPageTabSetter(TabSetter): - def __init__(self, page): - super().__init__(page) - self._session_setter = SessionPageSetter(self._page) - self._chromium_setter = ChromiumBaseSetter(self._page) + def __init__(self, owner): + super().__init__(owner) + self._session_setter = SessionPageSetter(self._owner) + self._chromium_setter = ChromiumBaseSetter(self._owner) @property def cookies(self): """返回用于设置cookies的对象""" if self._cookies_setter is None: - self._cookies_setter = WebPageCookiesSetter(self._page) + self._cookies_setter = WebPageCookiesSetter(self._owner) return self._cookies_setter def headers(self, headers) -> None: @@ -433,16 +437,16 @@ class WebPageTabSetter(TabSetter): :param headers: dict格式的headers数据 :return: None """ - if self._page._has_session: + if self._owner._has_session: self._session_setter.headers(headers) - if self._page._has_driver: + if self._owner._has_driver: self._chromium_setter.headers(headers) def user_agent(self, ua, platform=None): """设置user agent,d模式下只有当前tab有效""" - if self._page._has_session: + if self._owner._has_session: self._session_setter.user_agent(ua) - if self._page._has_driver: + if self._owner._has_driver: self._chromium_setter.user_agent(ua, platform) @@ -492,17 +496,17 @@ class ChromiumFrameSetter(ChromiumBaseSetter): :param value: 属性值 :return: None """ - self._page.frame_ele.set.attr(name, value) + self._owner.frame_ele.set.attr(name, value) class LoadMode(object): """用于设置页面加载策略的类""" - def __init__(self, page): + def __init__(self, owner): """ - :param page: ChromiumBase对象 + :param owner: ChromiumBase对象 """ - self._page = page + self._owner = owner def __call__(self, value): """设置加载策略 @@ -511,23 +515,26 @@ class LoadMode(object): """ if value.lower() not in ('normal', 'eager', 'none'): raise ValueError("只能选择 'normal', 'eager', 'none'。") - self._page._load_mode = value + self._owner._load_mode = value def normal(self): """设置页面加载策略为normal""" - self._page._load_mode = 'normal' + self._owner._load_mode = 'normal' def eager(self): """设置页面加载策略为eager""" - self._page._load_mode = 'eager' + self._owner._load_mode = 'eager' def none(self): """设置页面加载策略为none""" - self._page._load_mode = 'none' + self._owner._load_mode = 'none' class PageScrollSetter(object): def __init__(self, scroll): + """ + :param scroll: PageScroller对象 + """ self._scroll = scroll def wait_complete(self, on_off=True): @@ -554,11 +561,11 @@ class PageScrollSetter(object): class WindowSetter(object): """用于设置窗口大小的类""" - def __init__(self, page): + def __init__(self, owner): """ - :param page: 页面对象 + :param owner: 页面对象 """ - self._page = page + self._owner = owner self._window_id = self._get_info()['windowId'] def max(self): @@ -621,7 +628,7 @@ class WindowSetter(object): """获取窗口位置及大小信息""" for _ in range(50): try: - return self._page.run_cdp('Browser.getWindowForTarget') + return self._owner.run_cdp('Browser.getWindowForTarget') except: sleep(.1) @@ -631,7 +638,7 @@ class WindowSetter(object): :return: None """ try: - self._page.run_cdp('Browser.setWindowBounds', windowId=self._window_id, bounds=bounds) + self._owner.run_cdp('Browser.setWindowBounds', windowId=self._window_id, bounds=bounds) except: raise RuntimeError('浏览器全屏或最小化状态时请先调用set.window.normal()恢复正常状态。') @@ -649,12 +656,10 @@ class WindowSetter(object): """设置窗口为全屏""" self.full() - -class PageWindowSetter(WindowSetter): def hide(self): """隐藏浏览器窗口,只在Windows系统可用""" - show_or_hide_browser(self._page, hide=True) + show_or_hide_browser(self._owner, hide=True) def show(self): """显示浏览器窗口,只在Windows系统可用""" - show_or_hide_browser(self._page, hide=False) + show_or_hide_browser(self._owner, hide=False) diff --git a/DrissionPage/_units/setter.pyi b/DrissionPage/_units/setter.pyi index 4e6f852..4a974bf 100644 --- a/DrissionPage/_units/setter.pyi +++ b/DrissionPage/_units/setter.pyi @@ -6,7 +6,7 @@ @License : BSD 3-Clause. """ from pathlib import Path -from typing import Union, Tuple, Literal, Any +from typing import Union, Tuple, Literal, Any, Optional from requests.adapters import HTTPAdapter from requests.auth import HTTPBasicAuth @@ -18,7 +18,7 @@ from .._elements.chromium_element import ChromiumElement from .._pages.chromium_base import ChromiumBase from .._pages.chromium_frame import ChromiumFrame from .._pages.chromium_page import ChromiumPage -from .._pages.chromium_tab import ChromiumTab +from .._pages.chromium_tab import ChromiumTab, WebPageTab from .._pages.session_page import SessionPage from .._pages.web_page import WebPage @@ -26,15 +26,15 @@ FILE_EXISTS = Literal['skip', 'rename', 'overwrite', 's', 'r', 'o'] class BasePageSetter(object): - def __init__(self, page: BasePage): - self._page: BasePage = ... + def __init__(self, owner: BasePage): + self._owner: BasePage = ... def NoneElement_value(self, value: Any = None, on_off: bool = True) -> None: ... class ChromiumBaseSetter(BasePageSetter): - def __init__(self, page): - self._page: ChromiumBase = ... + def __init__(self, owner): + self._owner: ChromiumBase = ... self._cookies_setter: CookiesSetter = ... @property @@ -68,7 +68,9 @@ class ChromiumBaseSetter(BasePageSetter): class TabSetter(ChromiumBaseSetter): - def __init__(self, page): ... + _owner: ChromiumTab = ... + + def __init__(self, owner: Union[ChromiumTab, WebPage]): ... @property def window(self) -> WindowSetter: ... @@ -83,20 +85,16 @@ class TabSetter(ChromiumBaseSetter): class ChromiumPageSetter(TabSetter): - _page: ChromiumPage = ... - - @property - def window(self) -> PageWindowSetter: ... - - def main_tab(self, tab_id: str = None) -> None: ... + _owner: ChromiumPage = ... def tab_to_front(self, tab_or_id: Union[str, ChromiumTab] = None) -> None: ... class SessionPageSetter(BasePageSetter): - def __init__(self, page: SessionPage): - self._page: SessionPage = ... - self._cookies_setter: SessionCookiesSetter = ... + _owner: SessionPage = ... + _cookies_setter: Optional[SessionCookiesSetter] = ... + + def __init__(self, owner: SessionPage): ... @property def cookies(self) -> SessionCookiesSetter: ... @@ -139,7 +137,7 @@ class SessionPageSetter(BasePageSetter): class WebPageSetter(ChromiumPageSetter): - _page: WebPage = ... + _owner: WebPage = ... _session_setter: SessionPageSetter = ... _chromium_setter: ChromiumPageSetter = ... @@ -152,7 +150,7 @@ class WebPageSetter(ChromiumPageSetter): class WebPageTabSetter(TabSetter): - _page: WebPage = ... + _owner: WebPageTab = ... _session_setter: SessionPageSetter = ... _chromium_setter: ChromiumBaseSetter = ... @@ -178,14 +176,14 @@ class ChromiumElementSetter(object): class ChromiumFrameSetter(ChromiumBaseSetter): - _page: ChromiumFrame = ... + _owner: ChromiumFrame = ... def attr(self, name: str, value: str) -> None: ... class LoadMode(object): - def __init__(self, page: ChromiumBase): - self._page: ChromiumBase = ... + def __init__(self, owner: ChromiumBase): + self._owner: ChromiumBase = ... def __call__(self, value: str) -> None: ... @@ -206,8 +204,8 @@ class PageScrollSetter(object): class WindowSetter(object): - def __init__(self, page: ChromiumBase): - self._page: ChromiumBase = ... + def __init__(self, owner: ChromiumBase): + self._owner: ChromiumBase = ... self._window_id: str = ... def max(self) -> None: ... @@ -226,10 +224,6 @@ class WindowSetter(object): def _perform(self, bounds: dict) -> None: ... - -class PageWindowSetter(WindowSetter): - _page: ChromiumPage = ... - def hide(self) -> None: ... def show(self) -> None: ... diff --git a/DrissionPage/_units/states.py b/DrissionPage/_units/states.py index cda3d77..a038624 100644 --- a/DrissionPage/_units/states.py +++ b/DrissionPage/_units/states.py @@ -105,22 +105,22 @@ class ShadowRootStates(object): class PageStates(object): """Page对象、Tab对象使用""" - def __init__(self, page): + def __init__(self, owner): """ - :param page: ChromiumBase对象 + :param owner: ChromiumBase对象 """ - self._page = page + self._owner = owner @property def is_loading(self): """返回页面是否在加载状态""" - return self._page._is_loading + return self._owner._is_loading @property def is_alive(self): """返回页面对象是否仍然可用""" try: - self._page.run_cdp('Page.getLayoutMetrics') + self._owner.run_cdp('Page.getLayoutMetrics') return True except PageDisconnectedError: return False @@ -128,12 +128,12 @@ class PageStates(object): @property def ready_state(self): """返回当前页面加载状态,'connecting' 'loading' 'interactive' 'complete'""" - return self._page._ready_state + return self._owner._ready_state @property def has_alert(self): """返回当前页面是否存在弹窗""" - return self._page._has_alert + return self._owner._has_alert class FrameStates(object): diff --git a/DrissionPage/_units/states.pyi b/DrissionPage/_units/states.pyi index 067c0bd..71a673b 100644 --- a/DrissionPage/_units/states.pyi +++ b/DrissionPage/_units/states.pyi @@ -59,8 +59,8 @@ class ShadowRootStates(object): class PageStates(object): - def __init__(self, page: ChromiumBase): - self._page: ChromiumBase = ... + def __init__(self, owner: ChromiumBase): + self._owner: ChromiumBase = ... @property def is_loading(self) -> bool: ... diff --git a/DrissionPage/_units/waiter.py b/DrissionPage/_units/waiter.py index 6450dec..5d9a44d 100644 --- a/DrissionPage/_units/waiter.py +++ b/DrissionPage/_units/waiter.py @@ -272,7 +272,6 @@ class TabWaiter(BaseWaiter): class PageWaiter(TabWaiter): def __init__(self, page): super().__init__(page) - # self._listener = None def new_tab(self, timeout=None, raise_err=None): """等待新标签页出现 @@ -325,12 +324,12 @@ class PageWaiter(TabWaiter): class ElementWaiter(object): """等待元素在dom中某种状态,如删除、显示、隐藏""" - def __init__(self, page, ele): + def __init__(self, owner, ele): """等待元素在dom中某种状态,如删除、显示、隐藏 - :param page: 元素所在页面 + :param owner: 元素所在页面 :param ele: 要等待的元素 """ - self._page = page + self._owner = owner self._ele = ele def __call__(self, second, scope=None): @@ -408,7 +407,7 @@ class ElementWaiter(object): :return: 是否等待成功 """ if timeout is None: - timeout = self._page.timeout + timeout = self._owner.timeout end_time = perf_counter() + timeout while perf_counter() < end_time: if not self._ele.states.is_enabled or not self._ele.states.is_alive: @@ -428,7 +427,7 @@ class ElementWaiter(object): :return: 是否等待成功 """ if timeout is None: - timeout = self._page.timeout + timeout = self._owner.timeout end_time = perf_counter() + timeout while perf_counter() < end_time: try: @@ -471,7 +470,7 @@ class ElementWaiter(object): """ err_text = err_text or '等待元素状态改变失败(等待{}秒)。' if timeout is None: - timeout = self._page.timeout + timeout = self._owner.timeout end_time = perf_counter() + timeout while perf_counter() < end_time: a = self._ele.states.__getattribute__(attr) diff --git a/DrissionPage/_units/waiter.pyi b/DrissionPage/_units/waiter.pyi index 300c176..6c63f45 100644 --- a/DrissionPage/_units/waiter.pyi +++ b/DrissionPage/_units/waiter.pyi @@ -74,9 +74,9 @@ class PageWaiter(TabWaiter): class ElementWaiter(object): - def __init__(self, page: ChromiumBase, ele: ChromiumElement): + def __init__(self, owner: ChromiumBase, ele: ChromiumElement): self._ele: ChromiumElement = ... - self._page: ChromiumBase = ... + self._owner: ChromiumBase = ... def __call__(self, second: float, scope: float = None) -> None: ...