mirror of
https://gitee.com/g1879/DrissionPage.git
synced 2024-12-10 04:00:23 +08:00
Tab可处理自己的alert;重构处理alert逻辑,alert存在时也可处理非js命令
This commit is contained in:
parent
d587ca6095
commit
2939e4d42b
@ -24,7 +24,7 @@ class ChromiumDriver(object):
|
||||
self.address = address
|
||||
self.type = tab_type
|
||||
self._debug = False
|
||||
self.has_alert = False
|
||||
self.alert_flag = False # 标记alert出现,跳过一条请求后复原
|
||||
|
||||
self._websocket_url = f'ws://{address}/devtools/{tab_type}/{tab_id}'
|
||||
self._cur_id = 0
|
||||
@ -77,8 +77,9 @@ class ChromiumDriver(object):
|
||||
return self.method_results[message['id']].get_nowait()
|
||||
|
||||
except Empty:
|
||||
if self.has_alert:
|
||||
return {'error': {'message': 'alert exists'}, 'type': 'alert_exists'}
|
||||
if self.alert_flag:
|
||||
self.alert_flag = False
|
||||
return {'result': []}
|
||||
|
||||
if timeout is not None and perf_counter() > timeout:
|
||||
return {'error': {'message': 'timeout'}}
|
||||
@ -114,7 +115,10 @@ class ChromiumDriver(object):
|
||||
print(f'<收 {msg_json}')
|
||||
break
|
||||
|
||||
if "method" in msg:
|
||||
if 'method' in msg:
|
||||
if msg['method'].startswith('Page.javascriptDialog'):
|
||||
self.alert_flag = msg['method'].endswith('Opening')
|
||||
|
||||
self.event_queue.put(msg)
|
||||
|
||||
elif msg.get('id') in self.method_results:
|
||||
|
@ -23,7 +23,7 @@ class ChromiumDriver(object):
|
||||
address: str
|
||||
type: str
|
||||
_debug: bool
|
||||
has_alert: bool
|
||||
alert_flag: bool
|
||||
_websocket_url: str
|
||||
_cur_id: int
|
||||
_ws: Optional[WebSocket]
|
||||
|
@ -5,7 +5,6 @@
|
||||
"""
|
||||
from ..errors import ElementNotFoundError
|
||||
|
||||
HANDLE_ALERT_METHOD = 'Page.handleJavaScriptDialog'
|
||||
FRAME_ELEMENT = ('iframe', 'frame')
|
||||
ERROR = 'error'
|
||||
|
||||
|
@ -18,7 +18,7 @@ from .._units.clicker import Clicker
|
||||
from .._units.setter import ChromiumElementSetter
|
||||
from .._units.waiter import ChromiumElementWaiter
|
||||
from ..errors import ContextLossError, ElementLossError, JavaScriptError, ElementNotFoundError, \
|
||||
CDPError, NoResourceError, NoRectError
|
||||
CDPError, NoResourceError, NoRectError, AlertExistsError
|
||||
|
||||
|
||||
class ChromiumElement(DrissionElement):
|
||||
@ -206,6 +206,14 @@ class ChromiumElement(DrissionElement):
|
||||
|
||||
return self._select
|
||||
|
||||
def check(self, uncheck=False):
|
||||
"""选中或取消选中当前元素
|
||||
:param uncheck: 是否取消选中
|
||||
:return: None
|
||||
"""
|
||||
js = 'this.checked=false' if uncheck else 'this.checked=true'
|
||||
self.run_js(js)
|
||||
|
||||
def parent(self, level_or_loc=1, index=1):
|
||||
"""返回上面某一级父元素,可指定层数或用查询语法定位
|
||||
:param level_or_loc: 第几级父元素,或定位符
|
||||
@ -1303,6 +1311,9 @@ def run_js(page_or_ele, script, as_expr=False, timeout=None, args=None):
|
||||
obj_id = page_or_ele._root_id
|
||||
is_page = True
|
||||
|
||||
if page.has_alert:
|
||||
raise AlertExistsError
|
||||
|
||||
try:
|
||||
if as_expr:
|
||||
res = page.run_cdp('Runtime.evaluate', expression=script, returnByValue=False,
|
||||
|
@ -150,6 +150,8 @@ class ChromiumElement(DrissionElement):
|
||||
@property
|
||||
def select(self) -> ChromiumSelect: ...
|
||||
|
||||
def check(self, uncheck: bool = False) -> None: ...
|
||||
|
||||
def attr(self, attr: str) -> Union[str, None]: ...
|
||||
|
||||
def remove_attr(self, attr: str) -> None: ...
|
||||
|
@ -15,7 +15,7 @@ from requests import get
|
||||
|
||||
from .._base.base import BasePage
|
||||
from .._base.chromium_driver import ChromiumDriver
|
||||
from .._commons.constants import HANDLE_ALERT_METHOD, ERROR, NoneElement
|
||||
from .._commons.constants import ERROR, NoneElement
|
||||
from .._commons.locator import get_loc
|
||||
from .._commons.tools import get_usable_path, clean_folder
|
||||
from .._commons.web import location_in_viewport
|
||||
@ -47,6 +47,7 @@ class ChromiumBase(BasePage):
|
||||
self._screencast = None
|
||||
self._actions = None
|
||||
self._listener = None
|
||||
self._has_alert = False
|
||||
|
||||
self._download_path = str(Path('../..').absolute())
|
||||
|
||||
@ -103,6 +104,9 @@ class ChromiumBase(BasePage):
|
||||
if is_init and hasattr(self, '_driver'):
|
||||
return # ChromiumPage接收ChromiumDriver方式启动时
|
||||
self._driver = ChromiumDriver(tab_id=tab_id, tab_type='page', address=self.address)
|
||||
self._alert = Alert()
|
||||
self._driver.set_listener('Page.javascriptDialogOpening', self._on_alert_open)
|
||||
self._driver.set_listener('Page.javascriptDialogClosed', self._on_alert_close)
|
||||
|
||||
self._driver.call_method('DOM.enable')
|
||||
self._driver.call_method('Page.enable')
|
||||
@ -429,14 +433,19 @@ class ChromiumBase(BasePage):
|
||||
self._listener = NetworkListener(self)
|
||||
return self._listener
|
||||
|
||||
@property
|
||||
def has_alert(self):
|
||||
"""返回是否存在提示框"""
|
||||
return self._has_alert
|
||||
|
||||
def run_cdp(self, cmd, **cmd_args):
|
||||
"""执行Chrome DevTools Protocol语句
|
||||
:param cmd: 协议项目
|
||||
:param cmd_args: 参数
|
||||
:return: 执行的结果
|
||||
"""
|
||||
if self.driver.has_alert and cmd != HANDLE_ALERT_METHOD:
|
||||
raise AlertExistsError
|
||||
# if self.driver.has_alert and cmd != HANDLE_ALERT_METHOD:
|
||||
# raise AlertExistsError
|
||||
|
||||
r = self.driver.call_method(cmd, **cmd_args)
|
||||
if ERROR not in r:
|
||||
@ -824,6 +833,48 @@ class ChromiumBase(BasePage):
|
||||
if cookies:
|
||||
self.run_cdp_loaded('Network.clearBrowserCookies')
|
||||
|
||||
def handle_alert(self, accept=True, send=None, timeout=None):
|
||||
"""处理提示框,可以自动等待提示框出现
|
||||
:param accept: True表示确认,False表示取消,其它值不会按按钮但依然返回文本值
|
||||
:param send: 处理prompt提示框时可输入文本
|
||||
:param timeout: 等待提示框出现的超时时间,为None则使用self.timeout属性的值
|
||||
:return: 提示框内容文本,未等到提示框则返回False
|
||||
"""
|
||||
timeout = self.timeout if timeout is None else timeout
|
||||
timeout = .1 if timeout <= 0 else timeout
|
||||
end_time = perf_counter() + timeout
|
||||
while not self._alert.activated and perf_counter() < end_time:
|
||||
sleep(.1)
|
||||
if not self._alert.activated:
|
||||
return False
|
||||
|
||||
res_text = self._alert.text
|
||||
if self._alert.type == 'prompt':
|
||||
self.driver.call_method('Page.handleJavaScriptDialog', accept=accept, promptText=send)
|
||||
else:
|
||||
self.driver.call_method('Page.handleJavaScriptDialog', accept=accept)
|
||||
return res_text
|
||||
|
||||
def _on_alert_close(self, **kwargs):
|
||||
"""alert关闭时触发的方法"""
|
||||
self._alert.activated = False
|
||||
self._alert.text = None
|
||||
self._alert.type = None
|
||||
self._alert.defaultPrompt = None
|
||||
self._alert.response_accept = kwargs.get('result')
|
||||
self._alert.response_text = kwargs['userInput']
|
||||
self._has_alert = False
|
||||
|
||||
def _on_alert_open(self, **kwargs):
|
||||
"""alert出现时触发的方法"""
|
||||
self._alert.activated = True
|
||||
self._alert.text = kwargs['message']
|
||||
self._alert.type = kwargs['message']
|
||||
self._alert.defaultPrompt = kwargs.get('defaultPrompt', None)
|
||||
self._alert.response_accept = None
|
||||
self._alert.response_text = None
|
||||
self._has_alert = True
|
||||
|
||||
def _d_connect(self, to_url, times=0, interval=1, show_errmsg=False, timeout=None):
|
||||
"""尝试连接,重试若干次
|
||||
:param to_url: 要访问的url
|
||||
@ -1166,3 +1217,15 @@ class ScreencastMode(object):
|
||||
|
||||
def imgs_mode(self):
|
||||
self._screencast._mode = 'imgs'
|
||||
|
||||
|
||||
class Alert(object):
|
||||
"""用于保存alert信息的类"""
|
||||
|
||||
def __init__(self):
|
||||
self.activated = False
|
||||
self.text = None
|
||||
self.type = None
|
||||
self.defaultPrompt = None
|
||||
self.response_accept = None
|
||||
self.response_text = None
|
||||
|
@ -47,10 +47,12 @@ class ChromiumBase(BasePage):
|
||||
self._screencast: Screencast = ...
|
||||
self._actions: ActionChains = ...
|
||||
self._listener: NetworkListener = ...
|
||||
self._alert: Alert = ...
|
||||
self._has_alert: bool = ...
|
||||
|
||||
def _connect_browser(self, tab_id: str = None) -> None: ...
|
||||
|
||||
def _driver_init(self, tab_id: str, is_init:bool=True) -> None: ...
|
||||
def _driver_init(self, tab_id: str, is_init: bool = True) -> None: ...
|
||||
|
||||
def _get_document(self) -> None: ...
|
||||
|
||||
@ -156,6 +158,9 @@ class ChromiumBase(BasePage):
|
||||
@property
|
||||
def listen(self) -> NetworkListener: ...
|
||||
|
||||
@property
|
||||
def has_alert(self) -> bool: ...
|
||||
|
||||
def run_js(self, script: str, *args: Any, as_expr: bool = False) -> Any: ...
|
||||
|
||||
def run_js_loaded(self, script: str, *args: Any, as_expr: bool = False) -> Any: ...
|
||||
@ -226,6 +231,12 @@ class ChromiumBase(BasePage):
|
||||
cache: bool = True,
|
||||
cookies: bool = True) -> None: ...
|
||||
|
||||
def handle_alert(self, accept: bool = True, send: str = None, timeout: float = None) -> Union[str, False]: ...
|
||||
|
||||
def _on_alert_close(self, **kwargs): ...
|
||||
|
||||
def _on_alert_open(self, **kwargs): ...
|
||||
|
||||
def _d_connect(self,
|
||||
to_url: str,
|
||||
times: int = 0,
|
||||
@ -286,3 +297,14 @@ class ScreencastMode(object):
|
||||
def frugal_imgs_mode(self) -> None: ...
|
||||
|
||||
def imgs_mode(self) -> None: ...
|
||||
|
||||
|
||||
class Alert(object):
|
||||
|
||||
def __init__(self):
|
||||
self.activated: bool = ...
|
||||
self.text: str = ...
|
||||
self.type: str = ...
|
||||
self.defaultPrompt: str = ...
|
||||
self.response_accept: str = ...
|
||||
self.response_text: str = ...
|
||||
|
@ -4,7 +4,7 @@
|
||||
@Contact : g1879@qq.com
|
||||
"""
|
||||
from pathlib import Path
|
||||
from time import perf_counter, sleep
|
||||
from time import sleep
|
||||
|
||||
from requests import get
|
||||
|
||||
@ -85,13 +85,8 @@ class ChromiumPage(ChromiumBase):
|
||||
|
||||
def _page_init(self):
|
||||
"""浏览器相关设置"""
|
||||
self._alert = Alert()
|
||||
self._driver.set_listener('Page.javascriptDialogOpening', self._on_alert_open)
|
||||
self._driver.set_listener('Page.javascriptDialogClosed', self._on_alert_close)
|
||||
|
||||
self._rect = None
|
||||
self._main_tab = self.tab_id
|
||||
|
||||
self._browser.connect_to_page()
|
||||
|
||||
@property
|
||||
@ -284,64 +279,10 @@ class ChromiumPage(ChromiumBase):
|
||||
"""
|
||||
self.close_tabs(tabs_or_ids, True)
|
||||
|
||||
def handle_alert(self, accept=True, send=None, timeout=None):
|
||||
"""处理提示框,可以自动等待提示框出现
|
||||
:param accept: True表示确认,False表示取消,其它值不会按按钮但依然返回文本值
|
||||
:param send: 处理prompt提示框时可输入文本
|
||||
:param timeout: 等待提示框出现的超时时间,为None则使用self.timeout属性的值
|
||||
:return: 提示框内容文本,未等到提示框则返回False
|
||||
"""
|
||||
timeout = self.timeout if timeout is None else timeout
|
||||
timeout = .1 if timeout <= 0 else timeout
|
||||
end_time = perf_counter() + timeout
|
||||
while not self._alert.activated and perf_counter() < end_time:
|
||||
sleep(.1)
|
||||
if not self._alert.activated:
|
||||
return False
|
||||
|
||||
res_text = self._alert.text
|
||||
if self._alert.type == 'prompt':
|
||||
self.driver.call_method('Page.handleJavaScriptDialog', accept=accept, promptText=send)
|
||||
else:
|
||||
self.driver.call_method('Page.handleJavaScriptDialog', accept=accept)
|
||||
return res_text
|
||||
|
||||
def quit(self):
|
||||
"""关闭浏览器"""
|
||||
self.browser.quit()
|
||||
|
||||
def _on_alert_close(self, **kwargs):
|
||||
"""alert关闭时触发的方法"""
|
||||
self._alert.activated = False
|
||||
self._alert.text = None
|
||||
self._alert.type = None
|
||||
self._alert.defaultPrompt = None
|
||||
self._alert.response_accept = kwargs.get('result')
|
||||
self._alert.response_text = kwargs['userInput']
|
||||
self._driver.has_alert = False
|
||||
|
||||
def _on_alert_open(self, **kwargs):
|
||||
"""alert出现时触发的方法"""
|
||||
self._alert.activated = True
|
||||
self._alert.text = kwargs['message']
|
||||
self._alert.type = kwargs['message']
|
||||
self._alert.defaultPrompt = kwargs.get('defaultPrompt', None)
|
||||
self._alert.response_accept = None
|
||||
self._alert.response_text = None
|
||||
self._driver.has_alert = True
|
||||
|
||||
|
||||
class Alert(object):
|
||||
"""用于保存alert信息的类"""
|
||||
|
||||
def __init__(self):
|
||||
self.activated = False
|
||||
self.text = None
|
||||
self.type = None
|
||||
self.defaultPrompt = None
|
||||
self.response_accept = None
|
||||
self.response_text = None
|
||||
|
||||
|
||||
def get_rename(original, rename):
|
||||
if '.' in rename:
|
||||
|
@ -23,7 +23,6 @@ class ChromiumPage(ChromiumBase):
|
||||
timeout: float = None):
|
||||
self._driver_options: ChromiumOptions = ...
|
||||
self._main_tab: str = ...
|
||||
self._alert: Alert = ...
|
||||
self._browser: Browser = ...
|
||||
self._rect: Optional[ChromiumTabRect] = ...
|
||||
|
||||
@ -83,24 +82,7 @@ class ChromiumPage(ChromiumBase):
|
||||
def close_other_tabs(self, tabs_or_ids: Union[
|
||||
str, ChromiumTab, List[Union[str, ChromiumTab]], Tuple[Union[str, ChromiumTab]]] = None) -> None: ...
|
||||
|
||||
def handle_alert(self, accept: bool = True, send: str = None, timeout: float = None) -> Union[str, False]: ...
|
||||
|
||||
def quit(self) -> None: ...
|
||||
|
||||
def _on_alert_close(self, **kwargs): ...
|
||||
|
||||
def _on_alert_open(self, **kwargs): ...
|
||||
|
||||
|
||||
class Alert(object):
|
||||
|
||||
def __init__(self):
|
||||
self.activated: bool = ...
|
||||
self.text: str = ...
|
||||
self.type: str = ...
|
||||
self.defaultPrompt: str = ...
|
||||
self.response_accept: str = ...
|
||||
self.response_text: str = ...
|
||||
|
||||
|
||||
def get_rename(original: str, rename: str) -> str: ...
|
||||
|
Loading…
x
Reference in New Issue
Block a user