From 655895c560630334b581d7b541fe26b43a595ea3 Mon Sep 17 00:00:00 2001 From: g1879 Date: Wed, 27 Dec 2023 23:45:58 +0800 Subject: [PATCH] =?UTF-8?q?4.0.0b32(+)=20=E4=BC=98=E5=8C=96WebPage?= =?UTF-8?q?=E7=9A=84post()=E8=BF=94=E5=9B=9E=E5=80=BC=EF=BC=9B=20=E4=BC=98?= =?UTF-8?q?=E5=8C=96run=5Fasync=5Fjs()=E9=80=BB=E8=BE=91=EF=BC=8C=E5=88=A0?= =?UTF-8?q?=E9=99=A4timeout=E5=8F=82=E6=95=B0=EF=BC=9B=20=E4=BF=AE?= =?UTF-8?q?=E5=A4=8D=E5=88=A4=E6=96=AD=E8=A6=86=E7=9B=96=E5=A4=B1=E6=95=88?= =?UTF-8?q?=E9=97=AE=E9=A2=98=EF=BC=9B=20=E4=BF=AE=E5=A4=8D=E9=A1=B5?= =?UTF-8?q?=E9=9D=A2=E6=BB=9A=E5=8A=A8=E6=9C=89=E6=97=B6=E6=8A=A5=E9=94=99?= =?UTF-8?q?=E9=97=AE=E9=A2=98=EF=BC=9B=20=E4=BC=98=E5=8C=96=5Fmake=5Frespo?= =?UTF-8?q?nse()=E8=BF=94=E5=9B=9E=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- DrissionPage/__init__.py | 2 +- DrissionPage/_elements/chromium_element.py | 3 +- DrissionPage/_pages/chromium_base.py | 7 +-- DrissionPage/_pages/chromium_base.pyi | 2 +- DrissionPage/_pages/chromium_tab.py | 13 +++-- DrissionPage/_pages/chromium_tab.pyi | 2 +- DrissionPage/_pages/session_page.py | 66 +++++++++++----------- DrissionPage/_pages/session_page.pyi | 4 +- DrissionPage/_pages/web_page.py | 13 +++-- DrissionPage/_pages/web_page.pyi | 2 +- DrissionPage/_units/scroller.py | 3 +- DrissionPage/_units/scroller.pyi | 6 +- DrissionPage/_units/states.py | 2 +- setup.py | 6 +- 14 files changed, 63 insertions(+), 68 deletions(-) diff --git a/DrissionPage/__init__.py b/DrissionPage/__init__.py index 9d09b17..3a5cb9f 100644 --- a/DrissionPage/__init__.py +++ b/DrissionPage/__init__.py @@ -13,4 +13,4 @@ from ._configs.chromium_options import ChromiumOptions from ._configs.session_options import SessionOptions __all__ = ['ChromiumPage', 'ChromiumOptions', 'SessionOptions', 'SessionPage', 'WebPage', '__version__'] -__version__ = '4.0.0b31' +__version__ = '4.0.0b32' diff --git a/DrissionPage/_elements/chromium_element.py b/DrissionPage/_elements/chromium_element.py index ce88ff5..0916987 100644 --- a/DrissionPage/_elements/chromium_element.py +++ b/DrissionPage/_elements/chromium_element.py @@ -1409,7 +1409,8 @@ def run_js(page_or_ele, script, as_expr=False, timeout=None, args=None): res = page.run_cdp('Runtime.callFunctionOn', functionDeclaration=script, objectId=obj_id, arguments=[convert_argument(arg) for arg in args], returnByValue=False, awaitPromise=True, userGesture=True, _timeout=timeout, _ignore=AlertExistsError) - + except TimeoutError: + raise TimeoutError('执行js超时。') except ContextLostError: if is_page: raise ContextLostError('页面已被刷新,请尝试等待页面加载完成再执行操作。') diff --git a/DrissionPage/_pages/chromium_base.py b/DrissionPage/_pages/chromium_base.py index b2862ef..ea9a04d 100644 --- a/DrissionPage/_pages/chromium_base.py +++ b/DrissionPage/_pages/chromium_base.py @@ -485,17 +485,14 @@ class ChromiumBase(BasePage): self.wait.load_complete() return run_js(self, script, as_expr, self.timeouts.script if timeout is None else timeout, args) - def run_async_js(self, script, *args, as_expr=False, timeout=None): + def run_async_js(self, script, *args, as_expr=False): """以异步方式执行js代码 :param script: js文本 :param args: 参数,按顺序在js文本中对应arguments[0]、arguments[1]... :param as_expr: 是否作为表达式运行,为True时args无效 - :param timeout: js超时时间(秒),为None则使用页面timeouts.script属性值 :return: None """ - from threading import Thread - Thread(target=run_js, args=(self, script, as_expr, self.timeouts.script if timeout is None else timeout, - args)).start() + run_js(self, script, as_expr, 0, args) def get(self, url, show_errmsg=False, retry=None, interval=None, timeout=None): """访问url diff --git a/DrissionPage/_pages/chromium_base.pyi b/DrissionPage/_pages/chromium_base.pyi index abef890..4ed83cb 100644 --- a/DrissionPage/_pages/chromium_base.pyi +++ b/DrissionPage/_pages/chromium_base.pyi @@ -167,7 +167,7 @@ class ChromiumBase(BasePage): def run_js_loaded(self, script: str, *args, as_expr: bool = False, timeout: float = None) -> Any: ... - def run_async_js(self, script: str, *args, as_expr: bool = False, timeout: float = None) -> None: ... + def run_async_js(self, script: str, *args, as_expr: bool = False) -> None: ... def get(self, url: str, show_errmsg: bool = False, retry: int = None, interval: float = None, timeout: float = None) -> Union[None, bool]: ... diff --git a/DrissionPage/_pages/chromium_tab.py b/DrissionPage/_pages/chromium_tab.py index ce8d901..124cc4d 100644 --- a/DrissionPage/_pages/chromium_tab.py +++ b/DrissionPage/_pages/chromium_tab.py @@ -212,19 +212,20 @@ class WebPageTab(SessionPage, ChromiumTab, BasePage): timeout = self.timeouts.page_load if self._has_driver else self.timeout return super().get(url, show_errmsg, retry, interval, timeout, **kwargs) - def post(self, url: str, data=None, show_errmsg=False, retry=None, interval=None, **kwargs): + def post(self, url, show_errmsg=False, retry=None, interval=None, **kwargs): """用post方式跳转到url,会切换到s模式 :param url: 目标url - :param data: post方式时提交的数据 :param show_errmsg: 是否显示和抛出异常 - :param retry: 重试次数 - :param interval: 重试间隔(秒) + :param retry: 重试次数,为None时使用页面对象retry_times属性值 + :param interval: 重试间隔(秒),为None时使用页面对象retry_interval属性值 :param kwargs: 连接参数 - :return: url是否可用 + :return: s模式时返回url是否可用,d模式时返回获取到的Response对象 """ if self.mode == 'd': self.cookies_to_session() - return super().post(url, data, show_errmsg, retry, interval, **kwargs) + super().post(url, show_errmsg, retry, interval, **kwargs) + return self.response + return super().post(url, show_errmsg, retry, interval, **kwargs) def ele(self, loc_or_ele, timeout=None): """返回第一个符合条件的元素、属性或节点文本 diff --git a/DrissionPage/_pages/chromium_tab.pyi b/DrissionPage/_pages/chromium_tab.pyi index ec3798a..f80d0a6 100644 --- a/DrissionPage/_pages/chromium_tab.pyi +++ b/DrissionPage/_pages/chromium_tab.pyi @@ -165,7 +165,7 @@ class WebPageTab(SessionPage, ChromiumTab): hooks: Any | None = ..., stream: Any | None = ..., verify: Any | None = ..., - cert: Any | None = ...) -> bool: ... + cert: Any | None = ...) -> Union[bool, Response]: ... @property def set(self) -> WebPageTabSetter: ... diff --git a/DrissionPage/_pages/session_page.py b/DrissionPage/_pages/session_page.py index 5abcf09..0f3ddce 100644 --- a/DrissionPage/_pages/session_page.py +++ b/DrissionPage/_pages/session_page.py @@ -25,7 +25,7 @@ class SessionPage(BasePage): def __init__(self, session_or_options=None, timeout=None): """ :param session_or_options: Session对象或SessionOptions对象 - :param timeout: 连接超时时间(秒),为None时从ini文件读取 + :param timeout: 连接超时时间(秒),为None时从ini文件读取或默认10 """ super(SessionPage, SessionPage).__init__(self) self._headers = None @@ -41,7 +41,7 @@ class SessionPage(BasePage): def _s_set_start_options(self, session_or_options): """启动配置 - :param session_or_options: Session、SessionOptions + :param session_or_options: Session、SessionOptions对象 :return: None """ if not session_or_options or isinstance(session_or_options, SessionOptions): @@ -117,12 +117,12 @@ class SessionPage(BasePage): @property def session(self): - """返回session对象""" + """返回Session对象""" return self._session @property def response(self): - """返回访问url得到的response对象""" + """返回访问url得到的Response对象""" return self._response @property @@ -159,7 +159,18 @@ class SessionPage(BasePage): r.status_code = 200 self._response = r return - return self._s_connect(url, 'get', None, show_errmsg, retry, interval, **kwargs) + return self._s_connect(url, 'get', show_errmsg, retry, interval, **kwargs) + + def post(self, url, show_errmsg=False, retry=None, interval=None, **kwargs): + """用post方式跳转到url + :param url: 目标url + :param show_errmsg: 是否显示和抛出异常 + :param retry: 重试次数,为None时使用页面对象retry_times属性值 + :param interval: 重试间隔(秒),为None时使用页面对象timeout属性值 + :param kwargs: 连接参数 + :return: url是否可用 + """ + return self._s_connect(url, 'post', show_errmsg, retry, interval, **kwargs) def ele(self, loc_or_ele, timeout=None): """返回页面中符合条件的第一个元素、属性或节点文本 @@ -230,18 +241,6 @@ class SessionPage(BasePage): r.append({'name': c['name'], 'value': c['value'], 'domain': c['domain']}) return r - def post(self, url, data=None, show_errmsg=False, retry=None, interval=None, **kwargs): - """用post方式跳转到url - :param url: 目标url - :param data: 提交的数据 - :param show_errmsg: 是否显示和抛出异常 - :param retry: 重试次数 - :param interval: 重试间隔(秒) - :param kwargs: 连接参数 - :return: url是否可用 - """ - return self._s_connect(url, 'post', data, show_errmsg, retry, interval, **kwargs) - def close(self): """关闭Session对象""" self._session.close() @@ -260,11 +259,10 @@ class SessionPage(BasePage): interval = interval if interval is not None else self.retry_interval return retry, interval - def _s_connect(self, url, mode, data=None, show_errmsg=False, retry=None, interval=None, **kwargs): + def _s_connect(self, url, mode, show_errmsg=False, retry=None, interval=None, **kwargs): """执行get或post连接 :param url: 目标url :param mode: 'get' 或 'post' - :param data: 提交的数据 :param show_errmsg: 是否显示和抛出异常 :param retry: 重试次数 :param interval: 重试间隔(秒) @@ -272,7 +270,7 @@ class SessionPage(BasePage): :return: url是否可用 """ retry, interval = self._before_connect(url, retry, interval) - self._response, info = self._make_response(self._url, mode, data, retry, interval, show_errmsg, **kwargs) + self._response, info = self._make_response(self._url, mode, retry, interval, show_errmsg, **kwargs) if self._response is None: self._url_available = False @@ -288,11 +286,10 @@ class SessionPage(BasePage): return self._url_available - def _make_response(self, url, mode='get', data=None, retry=None, interval=None, show_errmsg=False, **kwargs): + def _make_response(self, url, mode='get', retry=None, interval=None, show_errmsg=False, **kwargs): """生成Response对象 :param url: 目标url :param mode: 'get' 或 'post' - :param data: post方式要提交的数据 :param show_errmsg: 是否显示和抛出异常 :param kwargs: 其它参数 :return: tuple,第一位为Response或None,第二位为出错信息或 'Success' @@ -325,7 +322,7 @@ class SessionPage(BasePage): if mode == 'get': r = self.session.get(url, **kwargs) elif mode == 'post': - r = self.session.post(url, data=data, **kwargs) + r = self.session.post(url, **kwargs) if r and r.content: if self._encoding: @@ -344,18 +341,19 @@ class SessionPage(BasePage): if show_errmsg: print(f'重试 {url}') - if r is None: - if show_errmsg: - if err: - raise err - else: - raise ConnectionError('连接失败') - return None, '连接失败' if err is None else err + if show_errmsg: + if err: + raise err + elif r is not None: + raise ConnectionError(f'状态码:{r.status_code}') if r.content else ConnectionError('返回内容为空。') + else: + raise ConnectionError('连接失败') - if not r.ok: - if show_errmsg: - raise ConnectionError(f'状态码:{r.status_code}') - return r, f'状态码:{r.status_code}' + else: + if r is not None: + return (r, f'状态码:{r.status_code}') if r.content else (None, '返回内容为空') + else: + return None, '连接失败' if err is None else err def __repr__(self): return f'' diff --git a/DrissionPage/_pages/session_page.pyi b/DrissionPage/_pages/session_page.pyi index b3116b2..dd4da4e 100644 --- a/DrissionPage/_pages/session_page.pyi +++ b/DrissionPage/_pages/session_page.pyi @@ -128,10 +128,10 @@ class SessionPage(BasePage): def post(self, url: str, - data: Union[dict, str, None] = ..., show_errmsg: bool = False, retry: int | None = None, interval: float | None = None, + data: Union[dict, str, None] = ..., timeout: float | None = ..., params: dict | None = ..., json: Union[dict, str, None] = ..., @@ -153,7 +153,6 @@ class SessionPage(BasePage): def _s_connect(self, url: str, mode: str, - data: Union[dict, str, None] = None, show_errmsg: bool = False, retry: int = None, interval: float = None, @@ -162,7 +161,6 @@ class SessionPage(BasePage): def _make_response(self, url: str, mode: str = 'get', - data: Union[dict, str] = None, retry: int = None, interval: float = None, show_errmsg: bool = False, diff --git a/DrissionPage/_pages/web_page.py b/DrissionPage/_pages/web_page.py index c12ed00..7fec00d 100644 --- a/DrissionPage/_pages/web_page.py +++ b/DrissionPage/_pages/web_page.py @@ -165,19 +165,20 @@ class WebPage(SessionPage, ChromiumPage, BasePage): timeout = self.timeouts.page_load if self._has_driver else self.timeout return super().get(url, show_errmsg, retry, interval, timeout, **kwargs) - def post(self, url: str, data=None, show_errmsg=False, retry=None, interval=None, **kwargs): + def post(self, url, show_errmsg=False, retry=None, interval=None, **kwargs): """用post方式跳转到url,会切换到s模式 :param url: 目标url - :param data: post方式时提交的数据 :param show_errmsg: 是否显示和抛出异常 - :param retry: 重试次数 - :param interval: 重试间隔(秒) + :param retry: 重试次数,为None时使用页面对象retry_times属性值 + :param interval: 重试间隔(秒),为None时使用页面对象retry_interval属性值 :param kwargs: 连接参数 - :return: url是否可用 + :return: s模式时返回url是否可用,d模式时返回获取到的Response对象 """ if self.mode == 'd': self.cookies_to_session() - return super().post(url, data, show_errmsg, retry, interval, **kwargs) + super().post(url, show_errmsg, retry, interval, **kwargs) + return self.response + return super().post(url, show_errmsg, retry, interval, **kwargs) def ele(self, loc_or_ele, timeout=None): """返回第一个符合条件的元素、属性或节点文本 diff --git a/DrissionPage/_pages/web_page.pyi b/DrissionPage/_pages/web_page.pyi index 9c80c71..2b1671d 100644 --- a/DrissionPage/_pages/web_page.pyi +++ b/DrissionPage/_pages/web_page.pyi @@ -157,7 +157,7 @@ class WebPage(SessionPage, ChromiumPage, BasePage): hooks: Any | None = ..., stream: Any | None = ..., verify: Any | None = ..., - cert: Any | None = ...) -> bool: ... + cert: Any | None = ...) -> Union[bool, Response]: ... @property def set(self) -> WebPageSetter: ... diff --git a/DrissionPage/_units/scroller.py b/DrissionPage/_units/scroller.py index 6e3606e..b1b987e 100644 --- a/DrissionPage/_units/scroller.py +++ b/DrissionPage/_units/scroller.py @@ -81,6 +81,7 @@ class Scroller(object): self._run_js(f'{{}}.scrollBy({pixel}, 0);') def _wait_scrolled(self): + """等待滚动结束""" if not self._wait_complete: return @@ -89,7 +90,7 @@ class Scroller(object): x = r['layoutViewport']['pageX'] y = r['layoutViewport']['pageY'] - end_time = perf_counter() + self._driver.page.timeout + end_time = perf_counter() + page.timeout while perf_counter() < end_time: sleep(.1) r = page.run_cdp('Page.getLayoutMetrics') diff --git a/DrissionPage/_units/scroller.pyi b/DrissionPage/_units/scroller.pyi index 438da32..510543d 100644 --- a/DrissionPage/_units/scroller.pyi +++ b/DrissionPage/_units/scroller.pyi @@ -3,15 +3,13 @@ from typing import Union from .._elements.chromium_element import ChromiumElement from .._pages.chromium_base import ChromiumBase -from .._pages.chromium_frame import ChromiumFrame -from .._pages.chromium_page import ChromiumPage class Scroller(object): - def __init__(self, page_or_ele: Union[ChromiumBase, ChromiumElement, ChromiumFrame]): + def __init__(self, page_or_ele: Union[ChromiumBase, ChromiumElement]): self.t1: str = ... self.t2: str = ... - self._driver: Union[ChromiumPage, ChromiumElement, ChromiumFrame] = ... + self._driver: Union[ChromiumBase, ChromiumElement] = ... self._wait_complete: bool = ... def _run_js(self, js: str): ... diff --git a/DrissionPage/_units/states.py b/DrissionPage/_units/states.py index 8294fab..1ae731f 100644 --- a/DrissionPage/_units/states.py +++ b/DrissionPage/_units/states.py @@ -64,7 +64,7 @@ class ElementStates(object): """返回元素是否被覆盖,与是否在视口中无关,如被覆盖返回覆盖元素的backend id,否则返回False""" lx, ly = self._ele.rect.click_point try: - bid = self._ele.page.run_cdp('DOM.getNodeForLocation', x=lx, y=ly).get('backendNodeId') + bid = self._ele.page.run_cdp('DOM.getNodeForLocation', x=int(lx), y=int(ly)).get('backendNodeId') return bid if bid != self._ele._backend_id else False except CDPError: return False diff --git a/setup.py b/setup.py index 713e0f2..102fcd8 100644 --- a/setup.py +++ b/setup.py @@ -6,7 +6,7 @@ with open("README.md", "r", encoding='utf-8') as fh: setup( name="DrissionPage", - version="4.0.0b31", + version="4.0.0b32", author="g1879", author_email="g1879@qq.com", description="Python based web automation tool. It can control the browser and send and receive data packets.", @@ -29,12 +29,12 @@ setup( 'psutil' ], classifiers=[ - "Programming Language :: Python :: 3.6", + "Programming Language :: Python :: 3.8", "Development Status :: 4 - Beta", "Topic :: Utilities", "License :: OSI Approved :: BSD License", ], - python_requires='>=3.6', + python_requires='>=3.8', entry_points={ 'console_scripts': [ 'dp = DrissionPage.commons.cli:main',