diff --git a/DrissionPage/chrome_element.py b/DrissionPage/chrome_element.py index d909a1f..7dd980e 100644 --- a/DrissionPage/chrome_element.py +++ b/DrissionPage/chrome_element.py @@ -322,7 +322,7 @@ return true;}""" :param args: 参数,按顺序在js文本中对应argument[0]、argument[2]... :return: 运行的结果 """ - return _run_script(self, script, as_expr, *args) + return _run_script(self, script, as_expr, args) def ele(self, loc_or_str: Union[Tuple[str, str], str], @@ -747,7 +747,7 @@ else{a.push(e.snapshotItem(i));}}""" return js -def _run_script(page_or_ele, script: str, as_expr: bool = False, *args: Any) -> Any: +def _run_script(page_or_ele, script: str, as_expr: bool = False, args: tuple = None) -> Any: """运行javascript代码 \n :param page_or_ele: 页面对象或元素对象 :param script: js文本 @@ -769,6 +769,7 @@ def _run_script(page_or_ele, script: str, as_expr: bool = False, *args: Any) -> awaitPromise=True, userGesture=True) else: + args = args or () if not is_js_func(script): script = script if script.strip().startswith('return') else f'return {script}' script = f'function(){{{script}}}' @@ -937,7 +938,7 @@ class ChromeSelect(object): :param ele: select 元素对象 """ if ele.tag != 'select': - raise TypeError(f"select方法只能在元素使用。") self._ele = ele @@ -947,9 +948,9 @@ class ChromeSelect(object): :param timeout: 超时时间,不输入默认实用页面超时时间 :return: None """ - i = 'index' if isinstance(text_or_index, int) else 'text' + para_type = 'index' if isinstance(text_or_index, int) else 'text' timeout = timeout if timeout is not None else self._ele.page.timeout - return self._select(text_or_index, timeout=timeout) + return self._select(text_or_index, para_type, timeout=timeout) @property def is_multi(self) -> bool: @@ -979,9 +980,13 @@ class ChromeSelect(object): def clear(self) -> None: """清除所有已选项""" - self.select_ele.deselect_all() + if not self.is_multi: + raise NotImplementedError("只能在多选菜单执行此操作。") + for opt in self.options: + if opt.is_selected(): + opt.click(by_js=True) - def select_by_text(self, text: Union[str, list, tuple], timeout=None) -> bool: + def by_text(self, text: Union[str, list, tuple], timeout=None) -> bool: """此方法用于根据text值选择项。当元素是多选列表时,可以接收list或tuple \n :param text: text属性值,传入list或tuple可选择多项 :param timeout: 超时时间,不输入默认实用页面超时时间 @@ -990,7 +995,7 @@ class ChromeSelect(object): timeout = timeout if timeout is not None else self._ele.page.timeout return self._select(text, 'text', False, timeout) - def select_by_value(self, value: Union[str, list, tuple], timeout=None) -> bool: + def by_value(self, value: Union[str, list, tuple], timeout=None) -> bool: """此方法用于根据value值选择项。当元素是多选列表时,可以接收list或tuple \n :param value: value属性值,传入list或tuple可选择多项 :param timeout: 超时时间,不输入默认实用页面超时时间 @@ -999,7 +1004,7 @@ class ChromeSelect(object): timeout = timeout if timeout is not None else self._ele.page.timeout return self._select(value, 'value', False, timeout) - def select_by_index(self, index: Union[int, list, tuple], timeout=None) -> bool: + def by_index(self, index: Union[int, list, tuple], timeout=None) -> bool: """此方法用于根据index值选择项。当元素是多选列表时,可以接收list或tuple \n :param index: index属性值,传入list或tuple可选择多项 :param timeout: 超时时间,不输入默认实用页面超时时间 @@ -1008,7 +1013,7 @@ class ChromeSelect(object): timeout = timeout if timeout is not None else self._ele.page.timeout return self._select(index, 'index', False, timeout) - def deselect_by_text(self, text: Union[str, list, tuple], timeout=None) -> bool: + def cancel_by_text(self, text: Union[str, list, tuple], timeout=None) -> bool: """此方法用于根据text值取消选择项。当元素是多选列表时,可以接收list或tuple \n :param text: text属性值,传入list或tuple可取消多项 :param timeout: 超时时间,不输入默认实用页面超时时间 @@ -1017,7 +1022,7 @@ class ChromeSelect(object): timeout = timeout if timeout is not None else self._ele.page.timeout return self._select(text, 'text', True, timeout) - def deselect_by_value(self, value: Union[str, list, tuple], timeout=None) -> bool: + def cancel_by_value(self, value: Union[str, list, tuple], timeout=None) -> bool: """此方法用于根据value值取消选择项。当元素是多选列表时,可以接收list或tuple \n :param value: value属性值,传入list或tuple可取消多项 :param timeout: 超时时间,不输入默认实用页面超时时间 @@ -1026,7 +1031,7 @@ class ChromeSelect(object): timeout = timeout if timeout is not None else self._ele.page.timeout return self._select(value, 'value', True, timeout) - def deselect_by_index(self, index: Union[int, list, tuple], timeout=None) -> bool: + def cancel_by_index(self, index: Union[int, list, tuple], timeout=None) -> bool: """此方法用于根据index值取消选择项。当元素是多选列表时,可以接收list或tuple \n :param index: value属性值,传入list或tuple可取消多项 :param timeout: 超时时间,不输入默认实用页面超时时间 diff --git a/DrissionPage/chrome_page.py b/DrissionPage/chrome_page.py index 6374610..cd573d0 100644 --- a/DrissionPage/chrome_page.py +++ b/DrissionPage/chrome_page.py @@ -25,6 +25,11 @@ class ChromePage(BasePage): super().__init__(timeout) self._connect_debugger(Tab_or_Options, tab_handle) + def _ready(self): + self._alert = Alert() + self.driver.Page.javascriptDialogOpening = self._on_alert_open + self.driver.Page.javascriptDialogClosed = self._on_alert_close + def _connect_debugger(self, Tab_or_Options: Union[Tab, DriverOptions] = None, tab_handle: str = None): if isinstance(Tab_or_Options, Tab): self._driver = Tab_or_Options @@ -41,6 +46,7 @@ class ChromePage(BasePage): self._driver.start() self._driver.DOM.enable() + self._driver.Page.enable() root = self._driver.DOM.getDocument() self.root = ChromeElement(self, node_id=root['root']['nodeId']) @@ -123,7 +129,7 @@ class ChromePage(BasePage): :param args: 参数,按顺序在js文本中对应argument[0]、argument[2]... :return: 运行的结果 """ - return _run_script(self, script, as_expr, *args) + return _run_script(self, script, as_expr, args) def get(self, url: str, @@ -497,6 +503,47 @@ class ChromePage(BasePage): return is_ok + def _on_alert_close(self, **kwargs): + self._alert.activated = False + self._alert.text = None + self._alert.type = None + self._alert.defaultPrompt = None + + def _on_alert_open(self, **kwargs): + self._alert.activated = True + self._alert.text = kwargs['message'] + self._alert.type = kwargs['message'] + self._alert.defaultPrompt = kwargs.get('defaultPrompt', None) + + def handle_alert(self, accept: bool = True, send: str = None, timeout: float = None) -> Union[str, None]: + """处理提示框 \n + :param accept: True表示确认,False表示取消,其它值不会按按钮但依然返回文本值 + :param send: 处理prompt提示框时可输入文本 + :param timeout: 等待提示框出现的超时时间 + :return: 提示框内容文本,未等到提示框则返回None + """ + timeout = timeout or self.timeout + t1 = perf_counter() + while not self._alert.activated and perf_counter() - t1 < timeout: + sleep(.1) + if not self._alert.activated: + return None + + res_text = self._alert.text + if self._alert.type == 'prompt': + self.driver.Page.handleJavaScriptDialog(accept=accept, promptText=send) + else: + self.driver.Page.handleJavaScriptDialog(accept=accept) + return res_text + + +class Alert(object): + def __init__(self): + self.activated = False + self.text = None + self.type = None + self.defaultPrompt = None + def _get_tabs(handles: list, num_or_handles: Union[int, str, list, tuple, set]) -> set: """返回指定标签页handle组成的set \n diff --git a/DrissionPage/configs.ini b/DrissionPage/configs.ini index 0452c56..a90da88 100644 --- a/DrissionPage/configs.ini +++ b/DrissionPage/configs.ini @@ -1,11 +1,11 @@ [paths] -chromedriver_path = +chromedriver_path = D:\coding\Chrome92\chromedriver.exe tmp_path = [chrome_options] debugger_address = 127.0.0.1:9222 -binary_location = chromium-browser -arguments = ['--no-sandbox', '--disable-gpu', '--ignore-certificate-errors', '--disable-infobars', '--disable-popup-blocking'] +binary_location = D:\coding\Chrome92\chrome.exe +arguments = ['--no-sandbox', '--disable-gpu', '--ignore-certificate-errors', '--disable-infobars', '--disable-popup-blocking', '--user-data-dir=D:\\coding\\Chrome92\\user_data'] extensions = [] experimental_options = {'prefs': {'profile.default_content_settings.popups': 0, 'profile.default_content_setting_values': {'notifications': 2}, 'plugins.plugins_list': [{'enabled': False, 'name': 'Chrome PDF Viewer'}]}, 'useAutomationExtension': False, 'excludeSwitches': ['enable-automation']} timeouts = {'implicit': 10.0, 'pageLoad': 30.0, 'script': 30.0} diff --git a/DrissionPage/driver_page.py b/DrissionPage/driver_page.py index 2f93d13..aaa760b 100644 --- a/DrissionPage/driver_page.py +++ b/DrissionPage/driver_page.py @@ -512,9 +512,9 @@ class DriverPage(BasePage): """ return glob(f'{download_path}{sep}*.crdownload') - def process_alert(self, ok: bool = True, send: str = None, timeout: float = None) -> Union[str, None]: + def handle_alert(self, accept: bool = True, send: str = None, timeout: float = None) -> Union[str, None]: """处理提示框 \n - :param ok: True表示确认,False表示取消,其它值不会按按钮但依然返回文本值 + :param accept: True表示确认,False表示取消,其它值不会按按钮但依然返回文本值 :param send: 处理prompt提示框时可输入文本 :param timeout: 等待提示框出现的超时时间 :return: 提示框内容文本,未等到提示框则返回None @@ -540,9 +540,9 @@ class DriverPage(BasePage): if send is not None: alert.send_keys(send) - if ok is True: + if accept is True: alert.accept() - elif ok is False: + elif accept is False: alert.dismiss() return res_text diff --git a/DrissionPage/web_page.py b/DrissionPage/web_page.py index 61b3a7c..170df11 100644 --- a/DrissionPage/web_page.py +++ b/DrissionPage/web_page.py @@ -42,7 +42,7 @@ class WebPage(SessionPage, ChromePage, BasePage): self._response = None if self._mode == 'd': - self.driver + self._ready() # if self._mode == 'd': # try: @@ -199,6 +199,8 @@ class WebPage(SessionPage, ChromePage, BasePage): # s模式转d模式 if self._mode == 'd': + if not self._has_driver: + self._ready() self._has_driver = True self._url = None if not self._has_driver else super(SessionPage, self).url