PyQt5:QWebEngineView 中的 mouseClick 和源代码

PyQt5: mouseClick and source-code in QWebEngineView

提问人:nostradamus 提问时间:11/20/2016 最后编辑:ekhumoronostradamus 更新时间:12/17/2021 访问量:4900

问:

我有一个使用 PyQt-5.5.1 的工作脚本,我现在想将其移植到新的 PyQt 版本 (5.7)。调整大部分内容都很好,但我面临两个主要问题:(1)执行(模拟)鼠标点击,(2)访问(假设:打印)当前分别显示在QWebView或QWebEngineView中的网页的html源代码。

例如,我可以在 PyQt-5.5.1 中使用 QWebView 执行以下操作:

QTest.mouseClick(self.wvTest, Qt.LeftButton, QPoint(x, y))

frame = self.wvTest.page().mainFrame()
print(frame.toHtml().encode('utf-8'))

我知道有关移植到 QWebEngineView 的文档以及此页面,但无法将 C++ 表示法转换为有效的 Python 代码。

如何将其适配到 PyQt-5.7 中的 QWebEngineView?以下是 PyQt-5.5.1 的完整代码片段,对于新的 PyQt 版本来说,它失败了:

  • 对于 Button1:完全没有鼠标点击反应。
  • 对于 Button2: ,当我删除 mainframe(): 时。AttributeError: 'QWebEnginePage' object has no attribute 'mainFrame'TypeError: toHtml(self, Callable[..., None]): not enough arguments

import sys
from PyQt5.QtWidgets import QWidget, QPushButton, QApplication
from PyQt5.QtCore import QRect, Qt, QUrl, QPoint, QEvent
from PyQt5.QtTest import QTest
from PyQt5.Qt import PYQT_VERSION_STR

if PYQT_VERSION_STR=='5.5.1': from PyQt5 import QtWebKitWidgets else: from PyQt5 import QtWebEngineWidgets

class Example(QWidget): def __init__(self): super().__init__() self.initUI() def initUI(self): self.button1 = QPushButton('Button1', self) self.button1.clicked.connect(self.buttonOne) self.button1.setGeometry(QRect(10, 10, 90, 20)) self.button2 = QPushButton('Button2', self) self.button2.clicked.connect(self.buttonTwo) self.button2.setGeometry(QRect(110, 10, 90, 20)) if PYQT_VERSION_STR=='5.5.1': self.wvTest = QtWebKitWidgets.QWebView(self) else: self.wvTest = QtWebEngineWidgets.QWebEngineView(self) self.wvTest.setGeometry(QRect(10, 40, 430, 550)) self.wvTest.setUrl(QUrl('http://www.startpage.com')) self.wvTest.setObjectName('wvTest') self.setGeometry(300, 300, 450, 600) self.setWindowTitle('WebView minimalistic') self.show() def buttonOne(self): qp = QPoint(38, 314) QTest.mouseClick(self.wvTest, Qt.LeftButton, pos=qp) # or: QTest.mouseMove(self.wvTest, pos=self.qp) print('Button1 pressed.') def buttonTwo(self): frame = self.wvTest.page().mainFrame() print(frame.toHtml().encode('utf-8')) if __name__ == '__main__': app = QApplication(sys.argv) ex = Example() sys.exit(app.exec_())

python pyqt5 qtwebkit qtwebengine qtestlib

评论


答:

8赞 ekhumoro 11/20/2016 #1

该类不是 的直接替代品。正如移植指南所明确指出的那样,许多 API 已经发生了根本性的变化,一些主要功能完全缺失。这可能会使编写兼容层变得不可能,除非您的浏览器实现非常非常简单。编写一个单独的测试套件可能会更容易(除非你不介意编写大量的条件代码)。QWebEngineViewQWebView

首先,您需要实施 QTBUG-43602 的解决方法。当前的设计意味着内部处理鼠标事件,因此每当加载页面时,您的代码都需要获得对它的新引用:QWebEngineViewQOpenGLWidget

class Example(QWidget):
    ...

    def initUI(self):
        ...    
        self._glwidget = None

        if PYQT_VERSION_STR=='5.5.1':
            self.wvTest = QtWebKitWidgets.QWebView(self)
        else:
            self.wvTest = QtWebEngineWidgets.QWebEngineView(self)
            self.wvTest.installEventFilter(self)
        ...

    def eventFilter(self, source, event):
        if (event.type() == QEvent.ChildAdded and
            source is self.wvTest and
            event.child().isWidgetType()):
            self._glwidget = event.child()
            self._glwidget.installEventFilter(self)
        elif (event.type() == QEvent.MouseButtonPress and
              source is self._glwidget):
            print('web-view mouse-press:', event.pos())
        return super().eventFilter(source, event)

    def buttonOne(self):
        qp = QPoint(38, 314)
        widget = self._glwidget or self.wvTest
        QTest.mouseClick(widget, Qt.LeftButton, pos=qp)

为了访问页面的 html,您将需要一些条件代码,因为 Web 引擎 API 是异步工作的,并且需要回调。此外,在 Web 引擎中没有用于处理框架的内置 API(您需要为此使用 javascript),因此一切都需要通过网页:

    def buttonTwo(self):
        if PYQT_VERSION_STR=='5.5.1':
            print(self.wvTest.page().toHtml())
        else:
            self.wvTest.page().toHtml(self.processHtml)

    def processHtml(self, html):
        print(html)
    

评论

0赞 nostradamus 11/20/2016
多谢!这完美无缺。但是,通过将其实现回我的原始脚本,出现了两个小的后续问题:(1)是否有可能使单击适用于QWebEngineView的不同缩放系数,即?(2) 如何将html代码保存到字符串中进行进一步处理而不是打印?对不起,我根本不熟悉回调的东西。self.wvTest.setZoomFactor(0.8)
0赞 ekhumoro 11/21/2016
(1) 这似乎是一个完全独立的问题,与移植无关。显然,如果更改缩放系数,输入字段的位置会发生变化,因此需要相应地进行调整。(2) 我更新了答案中的示例代码。
0赞 nostradamus 11/21/2016
不知何故,(1) 不适用于不同的 ,尽管我相应地调整了坐标。我正在考虑一个可能的错误,但我必须再次研究它。(2):所以,没有办法直接提取它......好吧,这样就可以了。 :)非常感谢您的帮助。ZoomFactor
0赞 ekhumoro 11/21/2016
@nostradamus。(1)我试过了,效果很好。(2) 是的,它是异步的,就像其他几个 API(例如 )。QPoint(30, 270)runJavaScript
0赞 iMath 12/16/2021
如果你右键单击加载的网页,你会得到另一个新_glwidget,你需要删除该部分中的复选以使其仍然有效source is self._glwidgetelif