4.1.0.0b16增加控制台监听;优化Frame稳定性

This commit is contained in:
g1879 2024-07-30 11:19:56 +08:00
parent 9736f16e8e
commit cf858d5574
10 changed files with 145 additions and 20 deletions

View File

@ -14,4 +14,4 @@ from ._pages.chromium_page import ChromiumPage
from ._pages.mix_page import MixPage
from ._pages.mix_page import MixPage as WebPage
__version__ = '4.1.0.0b15'
__version__ = '4.1.0.0b16'

View File

@ -25,6 +25,7 @@ from .._functions.settings import Settings
from .._functions.tools import raise_error
from .._functions.web import location_in_viewport
from .._units.actions import Actions
from .._units.console import Console
from .._units.listener import Listener
from .._units.rect import TabRect
from .._units.screencast import Screencast
@ -58,6 +59,7 @@ class ChromiumBase(BasePage):
self._rect = None
self._wait = None
self._scroll = None
self._console = None
self._upload_list = None
self._doc_got = False # 用于在LoadEventFired和FrameStoppedLoading间标记是否已获取doc
self._download_path = None
@ -314,6 +316,13 @@ class ChromiumBase(BasePage):
self._rect = TabRect(self)
return self._rect
@property
def console(self):
"""返回获取控制台信息的对象"""
if self._console is None:
self._console = Console(self)
return self._console
@property
def timeout(self):
"""返回timeout设置"""

View File

@ -19,6 +19,7 @@ from .._functions.elements import SessionElementsList, ChromiumElementsList
from .._pages.chromium_frame import ChromiumFrame
from .._pages.chromium_page import ChromiumPage
from .._units.actions import Actions
from .._units.console import Console
from .._units.listener import Listener
from .._units.rect import TabRect
from .._units.screencast import Screencast
@ -61,6 +62,7 @@ class ChromiumBase(BasePage):
self._init_jss: list = ...
self._ready_state: Optional[str] = ...
self._rect: TabRect = ...
self._console: Console = ...
self._type: str = ...
def _connect_browser(self, target_id: str = None) -> None: ...
@ -143,6 +145,9 @@ class ChromiumBase(BasePage):
@property
def rect(self) -> TabRect: ...
@property
def console(self) -> Console: ...
@property
def timeout(self) -> float: ...

View File

@ -37,6 +37,7 @@ class ChromiumFrame(ChromiumBase):
sleep(.1)
return r
r = object.__new__(cls)
r._frame_id = node['frameId']
cls._Frames[node['frameId']] = r
return r
@ -53,7 +54,6 @@ class ChromiumFrame(ChromiumBase):
self._reloading = False
node = info['node'] if info else owner._run_cdp('DOM.describeNode', backendNodeId=ele._backend_id)['node']
self._frame_id = node['frameId']
if self._is_inner_frame():
self._is_diff_domain = False
self.doc_ele = ChromiumElement(self._target_page, backend_id=node['contentDocument']['backendNodeId'])
@ -195,6 +195,8 @@ class ChromiumFrame(ChromiumBase):
"""同域变异域"""
self.browser._frames.pop(kwargs['frameId'], None)
ChromiumFrame._Frames.pop(kwargs['frameId'], None)
while not hasattr(self, '_frame_id'):
sleep(.1)
if kwargs['frameId'] == self._frame_id:
self._reload()

View File

@ -375,10 +375,11 @@ class MixPage(SessionPage, ChromiumPage, BasePage):
elif self._mode == 'd':
return super(SessionPage, self)._find_elements(locator, timeout=timeout, index=index, relative=relative)
def quit(self, timeout=5, force=True):
def quit(self, timeout=5, force=True, del_data=False):
"""关闭浏览器和Session
:param timeout: 等待浏览器关闭超时时间
:param force: 关闭超时是否强制终止进程
:param del_data: 是否删除用户文件夹
:return: None
"""
if self._has_session:
@ -387,7 +388,7 @@ class MixPage(SessionPage, ChromiumPage, BasePage):
self._response = None
self._has_session = None
if self._has_driver:
super(SessionPage, self).quit(timeout, force)
super(SessionPage, self).quit(timeout, force, del_data=del_data)
self._driver = None
self._has_driver = None

View File

@ -188,4 +188,4 @@ class MixPage(SessionPage, ChromiumPage, BasePage):
dr_opt: Union[Driver, bool, None],
se_opt: Union[Session, SessionOptions, bool, None]) -> None: ...
def quit(self, timeout: float = 5, force: bool = True) -> None: ...
def quit(self, timeout: float = 5, force: bool = True, del_data: bool = False) -> None: ...

View File

@ -0,0 +1,61 @@
# -*- coding:utf-8 -*-
from queue import Queue
from time import perf_counter, sleep
class Console(object):
def __init__(self, owner):
self.owner = owner
self.listening = False
self._caught = None
@property
def messages(self):
if self._caught is None:
return []
lst = []
while not self._caught.empty():
lst.append(self._caught.get_nowait())
return lst
def start(self):
self._caught = Queue(maxsize=0)
self.owner._driver.set_callback("Console.messageAdded", self._console)
self.owner._run_cdp("Console.enable")
self.listening = True
def stop(self):
if self.listening:
self.owner._run_cdp("Console.disable")
self.owner._driver.set_callback('Console.messageAdded', None)
self.listening = False
def clear(self):
self._caught = Queue(maxsize=0)
def steps(self, timeout=None):
end = perf_counter() + timeout if timeout else None
while self.owner._driver.is_running:
if timeout and perf_counter() > end:
return
if self._caught.qsize():
yield self._caught.get_nowait()
sleep(0.05)
def _console(self, **kwargs):
self._caught.put(ConsoleData(kwargs['message']))
class ConsoleData(object):
__slots__ = ('_data', 'source', 'level', 'text', 'url', 'line', 'column')
def __init__(self, data):
self._data = data
def __getattr__(self, item):
"""获取属性"""
return self._data.get(item, None)
def __repr__(self):
return (f'<ConsoleData source={self.source} level={self.level} text={self.text} url={self.url} '
f'line={self.line} column={self.column} >')

View File

@ -0,0 +1,45 @@
# -*- coding:utf-8 -*-
from queue import Queue
from typing import Optional, Iterable, List
from .._pages.chromium_base import ChromiumBase
class Console(object):
listening: bool = ...
owner: ChromiumBase = ...
_caught: Optional[Queue] = ...
def __init__(self, owner: ChromiumBase) -> None: ...
@property
def messages(self) -> List[ConsoleData]: ...
def start(self) -> None:
"""开启console监听"""
...
def stop(self) -> None:
"""停止监听,清空已监听到的列表"""
...
def clear(self) -> None:
"""清空已获取但未返回的信息"""
...
def steps(self, timeout: Optional[float] = None) -> Iterable[ConsoleData]:
"""每监听到一个信息就返回用于for循环
:param timeout: 等待一个信息的超时时间为None无限等待
:return: None
"""
...
def _console(self, **kwargs) -> None: ...
class ConsoleData(object):
__slots__ = ('_data', 'source', 'level', 'text', 'url', 'line', 'column')
def __init__(self, data: dict) -> None: ...
def __getattr__(self, item: str) -> str: ...

View File

@ -168,7 +168,7 @@ class Listener(object):
caught = 0
end = perf_counter() + timeout if timeout else None
while self._driver.is_running:
if (timeout and perf_counter() > end) or not self._driver.is_running:
if timeout and perf_counter() > end:
return
if self._caught.qsize() >= gap:
yield self._caught.get_nowait() if gap == 1 else [self._caught.get_nowait() for _ in range(gap)]

View File

@ -12,7 +12,7 @@ DrissionPage 是一个基于 python 的网页自动化工具。
---
官方网站:[https://drissionpage.cn](https://drissionpage.cn)
官方网站:[https://DrissionPage.cn](https://drissionpage.cn)
<a href='https://gitee.com/g1879/DrissionPage/stargazers'><img src='https://gitee.com/g1879/DrissionPage/badge/star.svg?theme=dark' alt='star'></img></a> <a href='https://gitee.com/g1879/DrissionPage/members'><img src='https://gitee.com/g1879/DrissionPage/badge/fork.svg?theme=dark' alt='fork'></img></a>
@ -32,7 +32,7 @@ python 版本3.6 及以上
# 🛠 如何使用
**📖 使用文档:** [点击查看](https://g1879.gitee.io/drissionpagedocs)
**📖 使用文档:** [点击查看](https://DrissionPage.cn)
**交流 QQ 群:** 636361957
@ -55,27 +55,27 @@ python 版本3.6 及以上
- 不基于 webdriver
- 无需为不同版本的浏览器下载不同的驱动
- 运行速度更快
- 可以跨`<iframe>`查找元素,无需切入切出
- 把`<iframe>`看作普通元素,获取后可直接在其中查找元素,逻辑更清晰
- 可同时操作浏览器中的多个标签页,即使标签页为非激活状态,无需切换
- 可以直接读取浏览器缓存保存图片,无需用 GUI 点击另存
- 可以对整个网页截图,包括视口外的部分90以上版本浏览器支持
- 可以跨 iframe 查找元素,无需切入切出
- 把 iframe 看作普通元素,逻辑更清晰
- 可同时操作多个标签页,无需切换
- 可以直接读取浏览器缓存保存图片,无需用 GUI 点击另存
- 可以对整个网页截图,包括视口外的部分
- 可处理非`open`状态的 shadow-root
## 🎇 亮点功能
除了以上优点,本库还内置了无数人性化设计。
- 极简的语法规则。集成大量常用功能,代码更优雅
- 定位元素更加容易,功能更强大稳定
- 无处不在的等待和自动重试功能。使不稳定的网络变得易于控制,程序更稳定,编写更省心
- 提供强大的下载工具操作浏览器时也能享受快捷可靠的下载功能
- 允许反复使用已经打开的浏览器。无须每次运行从头启动浏览器,调试超方便
- 极简的定位语法,查找元素更加容易
- 集成大量常用功能,代码更优雅,功能强大稳定
- 无处不在的等待和自动重试使不稳定的网络变得易于控制,程序更稳定,编写更省心
- 提供强大的下载工具操作浏览器时也能享受快捷可靠的下载功能
- 允许反复使用已经打开的浏览器,无需每次运行从头启动浏览器,调试方便
- 使用 ini 文件保存常用配置,自动调用,提供便捷的设置,远离繁杂的配置项
- 内置 lxml 作为解析引擎,解析速度成几个数量级提升
- 使用 POM 模式封装,可直接用于测试,便于扩展
- 高度集成的便利功能,从每个细节中体现
- 还有很多细节,这里不一一列举,欢迎实际使用中体验:
- 还有很多细节,这里不一一列举,欢迎实际使用中体验:D
---
@ -90,6 +90,8 @@ python 版本3.6 及以上
# ☕ 请我喝咖啡
如果本项目对您有所帮助,不妨请作者我喝杯咖啡
作者是单人开发者,开发和写文档工作量较为繁重。
如果本项目对您有所帮助,不妨打赏一下作者
![](https://gitee.com/g1879/DrissionPageDocs/raw/master/static/img/code.jpg)