mirror of
https://gitee.com/g1879/DrissionPage.git
synced 2024-12-10 04:00:23 +08:00
4.1.0.0b16增加控制台监听;优化Frame稳定性
This commit is contained in:
parent
9736f16e8e
commit
cf858d5574
@ -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'
|
||||
|
@ -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设置"""
|
||||
|
@ -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: ...
|
||||
|
||||
|
@ -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()
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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: ...
|
||||
|
61
DrissionPage/_units/console.py
Normal file
61
DrissionPage/_units/console.py
Normal 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} >')
|
45
DrissionPage/_units/console.pyi
Normal file
45
DrissionPage/_units/console.pyi
Normal 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: ...
|
@ -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)]
|
||||
|
30
README.md
30
README.md
@ -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 及以上
|
||||
|
||||
# ☕ 请我喝咖啡
|
||||
|
||||
如果本项目对您有所帮助,不妨请作者我喝杯咖啡 :)
|
||||
作者是单人开发者,开发和写文档工作量较为繁重。
|
||||
|
||||
如果本项目对您有所帮助,不妨打赏一下作者 :)
|
||||
|
||||

|
||||
|
Loading…
x
Reference in New Issue
Block a user