diff --git a/DrissionPage/chromium_base.py b/DrissionPage/chromium_base.py index 5bb649c..fe56694 100644 --- a/DrissionPage/chromium_base.py +++ b/DrissionPage/chromium_base.py @@ -667,6 +667,9 @@ class Timeout(object): self.page_load = 30 self.script = 30 + def __repr__(self): + return str({'implicit': self.implicit, 'page_load': self.page_load, 'script': self.script}) + class PageLoadStrategy(object): """用于设置页面加载策略的类""" diff --git a/DrissionPage/chromium_driver.py b/DrissionPage/chromium_driver.py index e325f4a..bf86780 100644 --- a/DrissionPage/chromium_driver.py +++ b/DrissionPage/chromium_driver.py @@ -43,6 +43,7 @@ class ChromiumDriver(object): self.id = kwargs.get("id") self.type = kwargs.get("type") self.debug = getenv("DEBUG", False) + self.has_alert = False self._websocket_url = kwargs.get("webSocketDebuggerUrl") self._kwargs = kwargs @@ -95,6 +96,8 @@ class ChromiumDriver(object): return self.method_results[message['id']].get(timeout=q_timeout) except queue.Empty: + if self.has_alert: + return {'result': {'alert': True}} if isinstance(timeout, (int, float)) and timeout <= 0: raise TimeoutError(f"调用{message['method']}超时。") diff --git a/DrissionPage/chromium_page.py b/DrissionPage/chromium_page.py index 052989d..b8409b7 100644 --- a/DrissionPage/chromium_page.py +++ b/DrissionPage/chromium_page.py @@ -89,9 +89,9 @@ class ChromiumPage(ChromiumBase): def _set_options(self): """从配置中读取设置""" - self.set_timeouts(page_load=self.options.timeouts['pageLoad'] / 1000, - script=self.options.timeouts['script'] / 1000, - implicit=self.options.timeouts['implicit'] / 1000) + self.set_timeouts(page_load=self.options.timeouts['pageLoad'], + script=self.options.timeouts['script'], + implicit=self.options.timeouts['implicit']) self._page_load_strategy = self.options.page_load_strategy @property @@ -339,6 +339,7 @@ class ChromiumPage(ChromiumBase): self._alert.defaultPrompt = None self._alert.response_accept = kwargs.get('result') self._alert.response_text = kwargs['userInput'] + self._tab_obj.has_alert = False def _on_alert_open(self, **kwargs): """alert出现时触发的方法""" @@ -348,6 +349,7 @@ class ChromiumPage(ChromiumBase): self._alert.defaultPrompt = kwargs.get('defaultPrompt', None) self._alert.response_accept = None self._alert.response_text = None + self._tab_obj.has_alert = True class Alert(object): diff --git a/DrissionPage/common.py b/DrissionPage/common.py index 1988367..09d1bcb 100644 --- a/DrissionPage/common.py +++ b/DrissionPage/common.py @@ -356,7 +356,7 @@ def unzip(zip_path, to_path): return [f.extract(f.namelist()[0], path=to_path)] -def get_exe_path_from_port(port): +def get_exe_from_port(port): """获取端口号第一条进程的可执行文件路径 \n :param port: 端口号 :return: 可执行文件的绝对路径 @@ -529,8 +529,7 @@ def connect_browser(option): return None, None if _port_is_using(ip, port): - chrome_path = get_exe_path_from_port(port) if chrome_path == 'chrome' and system_type == 'windows' \ - else chrome_path + chrome_path = get_exe_from_port(port) if chrome_path == 'chrome' and system_type == 'windows' else chrome_path return chrome_path, None args = _get_running_args(option) @@ -539,7 +538,7 @@ def connect_browser(option): try: debugger = _run_browser(port, chrome_path, args) if chrome_path == 'chrome' and system_type == 'windows': - chrome_path = get_exe_path_from_port(port) + chrome_path = get_exe_from_port(port) # 传入的路径找不到,主动在ini文件、注册表、系统变量中找 except FileNotFoundError: diff --git a/DrissionPage/common.pyi b/DrissionPage/common.pyi index 2da55d3..6d62a4d 100644 --- a/DrissionPage/common.pyi +++ b/DrissionPage/common.pyi @@ -33,7 +33,7 @@ def clean_folder(folder_path: str, ignore: list = None) -> None: ... def unzip(zip_path: str, to_path: str) -> Union[list, None]: ... -def get_exe_path_from_port(port: Union[str, int]) -> Union[str, None]: ... +def get_exe_from_port(port: Union[str, int]) -> Union[str, None]: ... def get_pid_from_port(port: Union[str, int]) -> Union[str, None]: ... diff --git a/DrissionPage/config.py b/DrissionPage/config.py index c09af09..b332296 100644 --- a/DrissionPage/config.py +++ b/DrissionPage/config.py @@ -148,7 +148,7 @@ class SessionOptions(object): self._stream = None self._trust_env = None self._max_redirects = None - self.timeout = 10 + self._timeout = 10 if read_file: self.ini_path = ini_path or str(Path(__file__).parent / 'configs.ini') @@ -191,7 +191,12 @@ class SessionOptions(object): if options_dict.get('max_redirects', None) is not None: self._max_redirects = options_dict['max_redirects'] - self.timeout = options_dict.get('timeout', 10) + self._timeout = options_dict.get('timeout', 10) + + @property + def timeout(self): + """返回timeout属性信息""" + return self._timeout @property def headers(self): @@ -205,7 +210,6 @@ class SessionOptions(object): """返回cookies设置信息""" if self._cookies is None: self._cookies = [] - return self._cookies @property @@ -218,7 +222,6 @@ class SessionOptions(object): """返回proxies设置信息""" if self._proxies is None: self._proxies = {} - return self._proxies @property @@ -226,7 +229,6 @@ class SessionOptions(object): """返回hooks设置信息""" if self._hooks is None: self._hooks = {} - return self._hooks @property @@ -266,6 +268,11 @@ class SessionOptions(object): """返回max_redirects设置信息""" return self._max_redirects + @timeout.setter + def timeout(self, second): + """返回timeout属性信息""" + self._timeout = second + @headers.setter def headers(self, headers): """设置headers参数 \n @@ -362,6 +369,13 @@ class SessionOptions(object): """ self._max_redirects = max_redirects + def set_timeout(self, second): + """设置超时信息 + :param second: 秒数 + :return: 返回当前对象 + """ + self._timeout = second + def set_headers(self, headers): """设置headers参数 \n :param headers: 参数值 @@ -460,10 +474,7 @@ class DriverOptions(Options): :param ini_path: ini文件路径,为None则读取默认ini文件 """ super().__init__() - self._driver_path = None self._user_data_path = None - self.ini_path = None - self.timeouts = {'implicit': 10000, 'pageLoad': 30000, 'script': 30000} if read_file: self.ini_path = ini_path or str(Path(__file__).parent / 'configs.ini') @@ -484,9 +495,12 @@ class DriverOptions(Options): break self.timeouts = options_dict.get('timeouts', {'implicit': 10, 'pageLoad': 30, 'script': 30}) - self.timeouts['implicit'] *= 1000 - self.timeouts['pageLoad'] *= 1000 - self.timeouts['script'] *= 1000 + return + + self._driver_path = None + self.ini_path = None + self.timeouts = {'implicit': 10, 'pageLoad': 30, 'script': 30} + self._debugger_address = '127.0.0.1:9222' @property def driver_path(self): @@ -649,14 +663,12 @@ class DriverOptions(Options): :param script: 脚本运行超时时间 :return: 当前对象 """ - # timeouts = self._caps.get('timeouts', {'implicit': 10, 'pageLoad': 3000, 'script': 3000}) if implicit is not None: self.timeouts['implicit'] = implicit if pageLoad is not None: - self.timeouts['pageLoad'] = pageLoad * 1000 + self.timeouts['pageLoad'] = pageLoad if script is not None: - self.timeouts['script'] = script * 1000 - # self.timeouts = timeouts + self.timeouts['script'] = script return self @@ -778,7 +790,7 @@ def chrome_options_to_dict(options): re_dict = dict() attrs = ['debugger_address', 'binary_location', 'arguments', 'extensions', 'experimental_options', 'driver_path', - 'set_window_rect', 'page_load_strategy'] + 'page_load_strategy'] options_dir = options.__dir__() for attr in attrs: @@ -789,9 +801,6 @@ def chrome_options_to_dict(options): if 'timeouts' in options_dir and 'timeouts' in options._caps: timeouts = options.__getattribute__('timeouts') - timeouts['implicit'] /= 1000 - timeouts['pageLoad'] /= 1000 - timeouts['script'] /= 1000 re_dict['timeouts'] = timeouts return re_dict @@ -809,7 +818,8 @@ def session_options_to_dict(options): return options re_dict = dict() - attrs = ['headers', 'proxies', 'hooks', 'params', 'verify', 'stream', 'trust_env', 'max_redirects'] # 'adapters', + attrs = ['headers', 'proxies', 'hooks', 'params', 'verify', 'stream', 'trust_env', + 'max_redirects', 'timeout'] # 'adapters', cookies = options.__getattribute__('_cookies') diff --git a/DrissionPage/config.pyi b/DrissionPage/config.pyi index ffe58c9..4319af3 100644 --- a/DrissionPage/config.pyi +++ b/DrissionPage/config.pyi @@ -58,7 +58,10 @@ class SessionOptions(object): self._stream: bool = ... self._trust_env: bool = ... self._max_redirects: int = ... - self.timeout: float = ... + self._timeout: float = ... + + @property + def timeout(self) -> Union[int, float]: ... @property def headers(self) -> dict: ... @@ -96,6 +99,9 @@ class SessionOptions(object): @property def max_redirects(self) -> int: ... + @timeout.setter + def timeout(self, second: Union[int, float]) -> None: ... + @headers.setter def headers(self, headers: dict) -> None: ... @@ -132,13 +138,15 @@ class SessionOptions(object): @max_redirects.setter def max_redirects(self, max_redirects: int) -> None: ... - def set_headers(self, headers: dict) -> 'SessionOptions': ... + def set_timeout(self, second: Union[int, float]) -> SessionOptions: ... - def set_a_header(self, attr: str, value: str) -> 'SessionOptions': ... + def set_headers(self, headers: dict) -> SessionOptions: ... - def remove_a_header(self, attr: str) -> 'SessionOptions': ... + def set_a_header(self, attr: str, value: str) -> SessionOptions: ... - def set_proxies(self, proxies: dict) -> 'SessionOptions': ... + def remove_a_header(self, attr: str) -> SessionOptions: ... + + def set_proxies(self, proxies: dict) -> SessionOptions: ... def save(self, path: str = None) -> str: ... diff --git a/DrissionPage/mix_page.py b/DrissionPage/mix_page.py index 1e65f8c..9196efa 100644 --- a/DrissionPage/mix_page.py +++ b/DrissionPage/mix_page.py @@ -39,8 +39,8 @@ class MixPage(SessionPage, DriverPage, BasePage): if self._mode == 'd': try: timeouts = self.drission.driver_options.timeouts - t = timeout if timeout is not None else timeouts['implicit'] / 1000 - self.set_timeouts(t, timeouts['pageLoad'] / 1000, timeouts['script'] / 1000) + t = timeout if timeout is not None else timeouts['implicit'] + self.set_timeouts(t, timeouts['pageLoad'], timeouts['script']) except Exception: self.timeout = timeout if timeout is not None else 10 diff --git a/DrissionPage/web_page.py b/DrissionPage/web_page.py index c95fdfc..a1905ac 100644 --- a/DrissionPage/web_page.py +++ b/DrissionPage/web_page.py @@ -37,8 +37,7 @@ class WebPage(SessionPage, ChromiumPage, BasePage): self._tab_obj = None self._is_loading = False self.timeouts = Timeout(self) - self._set_session_options(session_or_options) - self._set_driver_options(driver_or_options) + self._set_both_options(driver_or_options, session_or_options) self._setting_tab_id = tab_id self._has_driver, self._has_session = (None, True) if self._mode == 's' else (True, None) self._response = None @@ -383,58 +382,61 @@ class WebPage(SessionPage, ChromiumPage, BasePage): elif self._mode == 'd': return super(SessionPage, self)._ele(loc_or_ele, timeout=timeout, single=single, relative=relative) - def _set_driver_options(self, driver_or_Options): - """处理driver设置 - :param driver_or_Options: ChromiumDriver对象或DriverOptions对象 + def _set_both_options(self, dr_opt, se_opt): + """处理两种模式的设置 + :param dr_opt: ChromiumDriver或DriverOptions对象,为None则从ini读取,为False用默认信息创建 + :param se_opt: Session、SessionOptions对象或配置信息,为None则从ini读取,为False用默认信息创建 :return: None """ - if isinstance(driver_or_Options, ChromiumDriver): - self._connect_browser(driver_or_Options) + if isinstance(dr_opt, ChromiumDriver): + self._connect_browser(dr_opt) self._has_driver = True - return - - if driver_or_Options is None: - self._driver_options = DriverOptions() - - elif driver_or_Options is False: - self._driver_options = DriverOptions(read_file=False) - - elif isinstance(driver_or_Options, DriverOptions): - self._driver_options = driver_or_Options + self._driver_options = None + dr_opt = False else: - raise TypeError('driver_or_options参数只能接收WebDriver, Options, DriverOptions或False。') + if dr_opt is None: + self._driver_options = DriverOptions() - timeouts = self._driver_options.timeouts - self.set_timeouts(timeouts['implicit'], timeouts['pageLoad'], timeouts['script']) + elif dr_opt is False: + self._driver_options = DriverOptions(read_file=False) - def _set_session_options(self, Session_or_Options): - """处理session设置 - :param Session_or_Options: Session对象或SessionOptions对象 - :return: None - """ - if isinstance(Session_or_Options, Session): - self._session = Session_or_Options + elif isinstance(dr_opt, DriverOptions): + self._driver_options = dr_opt + + else: + raise TypeError('driver_or_options参数只能接收ChromiumDriver, DriverOptions、None或False。') + + if isinstance(se_opt, Session): + self._session = se_opt self._has_session = True - return - - if Session_or_Options is None: - so = SessionOptions() - - elif Session_or_Options is False: - so = SessionOptions(read_file=False) - - elif isinstance(Session_or_Options, SessionOptions): - so = Session_or_Options - - elif isinstance(Session_or_Options, dict): - so = Session_or_Options + self._session_options = None + se_opt = False else: - raise TypeError('session_or_options参数只能接收Session, dict, SessionOptions或False。') + if se_opt is None: + so = SessionOptions().as_dict() - self._session_options = so.as_dict() - self.set_timeouts(implicit=so.timeout) + elif se_opt is False: + so = SessionOptions(read_file=False).as_dict() + + elif isinstance(se_opt, SessionOptions): + so = se_opt.as_dict() + + elif isinstance(se_opt, dict): + so = se_opt + + else: + raise TypeError('session_or_options参数只能接收Session, dict, SessionOptions、None或False。') + + self._session_options = so + + if se_opt is not False: + self.set_timeouts(implicit=self._session_options.get('timeout', 10)) + + if dr_opt is not False: + t = self._driver_options.timeouts + self.set_timeouts(t['implicit'], t['pageLoad'], t['script']) def quit(self): """关闭浏览器,关闭session""" diff --git a/DrissionPage/web_page.pyi b/DrissionPage/web_page.pyi index b068044..ce105ee 100644 --- a/DrissionPage/web_page.pyi +++ b/DrissionPage/web_page.pyi @@ -22,7 +22,7 @@ class WebPage(SessionPage, ChromiumPage, BasePage): def __init__(self, mode: str = 'd', - timeout: float = 10, + timeout: float = None, tab_id: str = None, driver_or_options: Union[ChromiumDriver, DriverOptions, bool] = None, session_or_options: Union[Session, SessionOptions, bool] = None) -> None: @@ -159,6 +159,9 @@ class WebPage(SessionPage, ChromiumPage, BasePage): -> Union[ChromiumElement, SessionElement, ChromiumFrame, str, None, List[Union[SessionElement, str]], List[ Union[ChromiumElement, str, ChromiumFrame]]]: ... + def _set_both_options(self, dr_opt: Union[ChromiumDriver, DriverOptions], + se_opt: Union[Session, SessionOptions, dict, bool, None]) -> None: ... + def _set_driver_options(self, driver_or_Options: Union[ChromiumDriver, DriverOptions]) -> None: ... def _set_session_options(self, Session_or_Options: Union[Session, SessionOptions]) -> None: ... diff --git a/README.md b/README.md index 462b125..886072d 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,3 @@ -# - DrissionPage 是一个基于 python 的网页自动化工具。 它既能控制浏览器,也能收发数据包,甚至能把两者合而为一, @@ -10,9 +8,21 @@ DrissionPage 是一个基于 python 的网页自动化工具。 它的语法简洁而优雅,代码量少,对新手友好。 -**使用文档:** 📒[点击打开](http://g1879.gitee.io/drissionpage) +*** -**QQ群:** 897838127 +支持系统:Windows、Linux、Mac + +python 版本:3.6 及以上 + +支持浏览器:Chromium 内核浏览器(如 Chrome 和 edge) + +*** + +star fork + +项目地址:[gitee](https://gitee.com/g1879/DrissionPage) | [github](https://github.com/g1879/DrissionPage) + +**交流QQ群:** 897838127 **联系邮箱:** g1879@qq.com @@ -22,8 +32,9 @@ DrissionPage 是一个基于 python 的网页自动化工具。 使用浏览器,可以很大程度上绕过这些坑,但浏览器运行效率不高。 因此,这个库设计初衷,是将它们合而为一,能够在不同须要时切换相应模式,并提供一种人性化的使用方法,提高开发和运行效率。 -除了合并两者,本库还以网页为单位封装了常用功能,提供非常简便的操作和语句,在用于网页自动化操作时,减少考虑细节,专注功能实现,使用更方便。 -一切从简,尽量提供简单直接的使用方法,对新手更友好。 +除了合并两者,本库还以网页为单位封装了常用功能,提供非常简便的操作和语句,在用于网页自动化操作时,减少考虑细节,专注功能实现,使用更方便。 一切从简,尽量提供简单直接的使用方法,使代码更优雅。 + +以前的版本是对 selenium 进行重新封装实现的。从 3.0 开始,作者另起炉灶,对底层进行了重新开发,摆脱对 selenium 的依赖,增强了功能,提升了运行效率。 # 💡 理念 diff --git a/setup.py b/setup.py index 45a505c..5188c3b 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="3.0.33", + version="3.0.34", author="g1879", author_email="g1879@qq.com", description="A module that integrates selenium and requests session, encapsulates common page operations.",