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.address = address
|
||||||
self.type = tab_type
|
self.type = tab_type
|
||||||
self._debug = False
|
self._debug = False
|
||||||
self.has_alert = False
|
self.alert_flag = False # 标记alert出现,跳过一条请求后复原
|
||||||
|
|
||||||
self._websocket_url = f'ws://{address}/devtools/{tab_type}/{tab_id}'
|
self._websocket_url = f'ws://{address}/devtools/{tab_type}/{tab_id}'
|
||||||
self._cur_id = 0
|
self._cur_id = 0
|
||||||
@ -77,8 +77,9 @@ class ChromiumDriver(object):
|
|||||||
return self.method_results[message['id']].get_nowait()
|
return self.method_results[message['id']].get_nowait()
|
||||||
|
|
||||||
except Empty:
|
except Empty:
|
||||||
if self.has_alert:
|
if self.alert_flag:
|
||||||
return {'error': {'message': 'alert exists'}, 'type': 'alert_exists'}
|
self.alert_flag = False
|
||||||
|
return {'result': []}
|
||||||
|
|
||||||
if timeout is not None and perf_counter() > timeout:
|
if timeout is not None and perf_counter() > timeout:
|
||||||
return {'error': {'message': 'timeout'}}
|
return {'error': {'message': 'timeout'}}
|
||||||
@ -114,7 +115,10 @@ class ChromiumDriver(object):
|
|||||||
print(f'<收 {msg_json}')
|
print(f'<收 {msg_json}')
|
||||||
break
|
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)
|
self.event_queue.put(msg)
|
||||||
|
|
||||||
elif msg.get('id') in self.method_results:
|
elif msg.get('id') in self.method_results:
|
||||||
|
@ -23,7 +23,7 @@ class ChromiumDriver(object):
|
|||||||
address: str
|
address: str
|
||||||
type: str
|
type: str
|
||||||
_debug: bool
|
_debug: bool
|
||||||
has_alert: bool
|
alert_flag: bool
|
||||||
_websocket_url: str
|
_websocket_url: str
|
||||||
_cur_id: int
|
_cur_id: int
|
||||||
_ws: Optional[WebSocket]
|
_ws: Optional[WebSocket]
|
||||||
|
@ -5,7 +5,6 @@
|
|||||||
"""
|
"""
|
||||||
from ..errors import ElementNotFoundError
|
from ..errors import ElementNotFoundError
|
||||||
|
|
||||||
HANDLE_ALERT_METHOD = 'Page.handleJavaScriptDialog'
|
|
||||||
FRAME_ELEMENT = ('iframe', 'frame')
|
FRAME_ELEMENT = ('iframe', 'frame')
|
||||||
ERROR = 'error'
|
ERROR = 'error'
|
||||||
|
|
||||||
|
@ -18,7 +18,7 @@ from .._units.clicker import Clicker
|
|||||||
from .._units.setter import ChromiumElementSetter
|
from .._units.setter import ChromiumElementSetter
|
||||||
from .._units.waiter import ChromiumElementWaiter
|
from .._units.waiter import ChromiumElementWaiter
|
||||||
from ..errors import ContextLossError, ElementLossError, JavaScriptError, ElementNotFoundError, \
|
from ..errors import ContextLossError, ElementLossError, JavaScriptError, ElementNotFoundError, \
|
||||||
CDPError, NoResourceError, NoRectError
|
CDPError, NoResourceError, NoRectError, AlertExistsError
|
||||||
|
|
||||||
|
|
||||||
class ChromiumElement(DrissionElement):
|
class ChromiumElement(DrissionElement):
|
||||||
@ -206,6 +206,14 @@ class ChromiumElement(DrissionElement):
|
|||||||
|
|
||||||
return self._select
|
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):
|
def parent(self, level_or_loc=1, index=1):
|
||||||
"""返回上面某一级父元素,可指定层数或用查询语法定位
|
"""返回上面某一级父元素,可指定层数或用查询语法定位
|
||||||
:param level_or_loc: 第几级父元素,或定位符
|
: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
|
obj_id = page_or_ele._root_id
|
||||||
is_page = True
|
is_page = True
|
||||||
|
|
||||||
|
if page.has_alert:
|
||||||
|
raise AlertExistsError
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if as_expr:
|
if as_expr:
|
||||||
res = page.run_cdp('Runtime.evaluate', expression=script, returnByValue=False,
|
res = page.run_cdp('Runtime.evaluate', expression=script, returnByValue=False,
|
||||||
|
@ -150,6 +150,8 @@ class ChromiumElement(DrissionElement):
|
|||||||
@property
|
@property
|
||||||
def select(self) -> ChromiumSelect: ...
|
def select(self) -> ChromiumSelect: ...
|
||||||
|
|
||||||
|
def check(self, uncheck: bool = False) -> None: ...
|
||||||
|
|
||||||
def attr(self, attr: str) -> Union[str, None]: ...
|
def attr(self, attr: str) -> Union[str, None]: ...
|
||||||
|
|
||||||
def remove_attr(self, attr: str) -> None: ...
|
def remove_attr(self, attr: str) -> None: ...
|
||||||
|
@ -15,7 +15,7 @@ from requests import get
|
|||||||
|
|
||||||
from .._base.base import BasePage
|
from .._base.base import BasePage
|
||||||
from .._base.chromium_driver import ChromiumDriver
|
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.locator import get_loc
|
||||||
from .._commons.tools import get_usable_path, clean_folder
|
from .._commons.tools import get_usable_path, clean_folder
|
||||||
from .._commons.web import location_in_viewport
|
from .._commons.web import location_in_viewport
|
||||||
@ -47,6 +47,7 @@ class ChromiumBase(BasePage):
|
|||||||
self._screencast = None
|
self._screencast = None
|
||||||
self._actions = None
|
self._actions = None
|
||||||
self._listener = None
|
self._listener = None
|
||||||
|
self._has_alert = False
|
||||||
|
|
||||||
self._download_path = str(Path('../..').absolute())
|
self._download_path = str(Path('../..').absolute())
|
||||||
|
|
||||||
@ -103,6 +104,9 @@ class ChromiumBase(BasePage):
|
|||||||
if is_init and hasattr(self, '_driver'):
|
if is_init and hasattr(self, '_driver'):
|
||||||
return # ChromiumPage接收ChromiumDriver方式启动时
|
return # ChromiumPage接收ChromiumDriver方式启动时
|
||||||
self._driver = ChromiumDriver(tab_id=tab_id, tab_type='page', address=self.address)
|
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('DOM.enable')
|
||||||
self._driver.call_method('Page.enable')
|
self._driver.call_method('Page.enable')
|
||||||
@ -429,14 +433,19 @@ class ChromiumBase(BasePage):
|
|||||||
self._listener = NetworkListener(self)
|
self._listener = NetworkListener(self)
|
||||||
return self._listener
|
return self._listener
|
||||||
|
|
||||||
|
@property
|
||||||
|
def has_alert(self):
|
||||||
|
"""返回是否存在提示框"""
|
||||||
|
return self._has_alert
|
||||||
|
|
||||||
def run_cdp(self, cmd, **cmd_args):
|
def run_cdp(self, cmd, **cmd_args):
|
||||||
"""执行Chrome DevTools Protocol语句
|
"""执行Chrome DevTools Protocol语句
|
||||||
:param cmd: 协议项目
|
:param cmd: 协议项目
|
||||||
:param cmd_args: 参数
|
:param cmd_args: 参数
|
||||||
:return: 执行的结果
|
:return: 执行的结果
|
||||||
"""
|
"""
|
||||||
if self.driver.has_alert and cmd != HANDLE_ALERT_METHOD:
|
# if self.driver.has_alert and cmd != HANDLE_ALERT_METHOD:
|
||||||
raise AlertExistsError
|
# raise AlertExistsError
|
||||||
|
|
||||||
r = self.driver.call_method(cmd, **cmd_args)
|
r = self.driver.call_method(cmd, **cmd_args)
|
||||||
if ERROR not in r:
|
if ERROR not in r:
|
||||||
@ -824,6 +833,48 @@ class ChromiumBase(BasePage):
|
|||||||
if cookies:
|
if cookies:
|
||||||
self.run_cdp_loaded('Network.clearBrowserCookies')
|
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):
|
def _d_connect(self, to_url, times=0, interval=1, show_errmsg=False, timeout=None):
|
||||||
"""尝试连接,重试若干次
|
"""尝试连接,重试若干次
|
||||||
:param to_url: 要访问的url
|
:param to_url: 要访问的url
|
||||||
@ -1166,3 +1217,15 @@ class ScreencastMode(object):
|
|||||||
|
|
||||||
def imgs_mode(self):
|
def imgs_mode(self):
|
||||||
self._screencast._mode = 'imgs'
|
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,6 +47,8 @@ class ChromiumBase(BasePage):
|
|||||||
self._screencast: Screencast = ...
|
self._screencast: Screencast = ...
|
||||||
self._actions: ActionChains = ...
|
self._actions: ActionChains = ...
|
||||||
self._listener: NetworkListener = ...
|
self._listener: NetworkListener = ...
|
||||||
|
self._alert: Alert = ...
|
||||||
|
self._has_alert: bool = ...
|
||||||
|
|
||||||
def _connect_browser(self, tab_id: str = None) -> None: ...
|
def _connect_browser(self, tab_id: str = None) -> None: ...
|
||||||
|
|
||||||
@ -156,6 +158,9 @@ class ChromiumBase(BasePage):
|
|||||||
@property
|
@property
|
||||||
def listen(self) -> NetworkListener: ...
|
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(self, script: str, *args: Any, as_expr: bool = False) -> Any: ...
|
||||||
|
|
||||||
def run_js_loaded(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,
|
cache: bool = True,
|
||||||
cookies: bool = True) -> None: ...
|
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,
|
def _d_connect(self,
|
||||||
to_url: str,
|
to_url: str,
|
||||||
times: int = 0,
|
times: int = 0,
|
||||||
@ -286,3 +297,14 @@ class ScreencastMode(object):
|
|||||||
def frugal_imgs_mode(self) -> None: ...
|
def frugal_imgs_mode(self) -> None: ...
|
||||||
|
|
||||||
def 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
|
@Contact : g1879@qq.com
|
||||||
"""
|
"""
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from time import perf_counter, sleep
|
from time import sleep
|
||||||
|
|
||||||
from requests import get
|
from requests import get
|
||||||
|
|
||||||
@ -85,13 +85,8 @@ class ChromiumPage(ChromiumBase):
|
|||||||
|
|
||||||
def _page_init(self):
|
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._rect = None
|
||||||
self._main_tab = self.tab_id
|
self._main_tab = self.tab_id
|
||||||
|
|
||||||
self._browser.connect_to_page()
|
self._browser.connect_to_page()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@ -284,64 +279,10 @@ class ChromiumPage(ChromiumBase):
|
|||||||
"""
|
"""
|
||||||
self.close_tabs(tabs_or_ids, True)
|
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):
|
def quit(self):
|
||||||
"""关闭浏览器"""
|
"""关闭浏览器"""
|
||||||
self.browser.quit()
|
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):
|
def get_rename(original, rename):
|
||||||
if '.' in rename:
|
if '.' in rename:
|
||||||
|
@ -23,7 +23,6 @@ class ChromiumPage(ChromiumBase):
|
|||||||
timeout: float = None):
|
timeout: float = None):
|
||||||
self._driver_options: ChromiumOptions = ...
|
self._driver_options: ChromiumOptions = ...
|
||||||
self._main_tab: str = ...
|
self._main_tab: str = ...
|
||||||
self._alert: Alert = ...
|
|
||||||
self._browser: Browser = ...
|
self._browser: Browser = ...
|
||||||
self._rect: Optional[ChromiumTabRect] = ...
|
self._rect: Optional[ChromiumTabRect] = ...
|
||||||
|
|
||||||
@ -83,24 +82,7 @@ class ChromiumPage(ChromiumBase):
|
|||||||
def close_other_tabs(self, tabs_or_ids: Union[
|
def close_other_tabs(self, tabs_or_ids: Union[
|
||||||
str, ChromiumTab, List[Union[str, ChromiumTab]], Tuple[Union[str, ChromiumTab]]] = None) -> None: ...
|
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 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: ...
|
def get_rename(original: str, rename: str) -> str: ...
|
||||||
|
Loading…
x
Reference in New Issue
Block a user