【问题标题】:Communicate with html/javascript using QWebEngineView使用 QWebEngineView 与 html/javascript 通信
【发布时间】:2017-06-12 04:19:43
【问题描述】:

我需要获取一个动态内容,该内容正在由 ajax js 调用加载。

我真的不知道如何使用 PyQt,但我希望我能做到这一点。 HTML 类似于:

<a href="#" id="id" onclick="A4J.AJAX.Submit('j_id0:j_id1:j_id110',event,{'similarityGroupingId':'j_id0:j_id1:j_id110:j_id582:0:j_id584'});return false;">NETHERLANDS</a>`

我可以使用 PyQt 使用这个简单的代码渲染页面:

def render(source_html):

    import sys
    from PyQt5.QtCore import QEventLoop
    from PyQt5.QtWidgets import QApplication
    from PyQt5.QtWebEngineWidgets import QWebEngineView

    class Render(QWebEngineView):
        def __init__(self, html):
            self.html = None
            self.app = QApplication(sys.argv)
            QWebEngineView.__init__(self)
            self.loadFinished.connect(self._loadFinished)
            self.setHtml(html)

            while self.html is None:
                self.app.processEvents(QEventLoop.ExcludeUserInputEvents | QEventLoop.ExcludeSocketNotifiers | QEventLoop.WaitForMoreEvents)
            self.app.quit()

        def _callable(self, data):
            self.html = data

        def _loadFinished(self, result):
            self.page().toHtml(self._callable)

    return Render(source_html).html

import requests
sample_html = requests.get('https://riverbankcomputing.com/software/pyqt/').text
print(render(sample_html))

如何运行“onclick”并获取内容?

【问题讨论】:

    标签: javascript html pyqt pyqt5 qwebengineview


    【解决方案1】:

    这是一个老问题,但是...

    从 javascript 运行 PyQt 函数:

    虽然可能有很多方法可以做到这一点,但我已经通过使用QWebChannel 解决了这个问题,然后从您的 html 中调用 js 函数,然后使用网络通道与 Qt 进行通信。

    您需要qwebchannel.js。我是从本地机器上的 Qt5 示例目录中获取的。同一个文件存在于网络上的许多地方。我会让你找到它。

    这里描述了大部分这种方法:http://doc.qt.io/qt-5/qtwebchannel-javascript.html

    在您的__init__ 中,创建一个网络频道:

    self.webchannel = QtWebChannel.QWebChannel(self)
    

    然后设置你的webengineview的主页面使用频道,并注册你想要在PyQt和js之间共享的对象:

    self.page().setWebChannel(self.webchannel)
    self.webchannel.registerObject('MyChannel', self)
    

    在您的 .js(或 .html 的 javascript 部分)中,设置网络频道:

    var MyChannel = null;
    new QWebChannel(qt.webChannelTransport, function(channel) {
                    MyChannel = channel.objects.MyChannel;
    });
    

    (这是qwebchannel.js发挥作用的地方。你的js或html文件必须能够包含它。对我来说,我在做任何其他js之前加载了&lt;script src="scripts/qwebchannel.js"&gt;&lt;/script&gt;

    现在你已经设置好通过通道从 js 调用 PyQt,但是你可以调用什么呢?任何装饰为 PyQt 插槽的东西。因此,例如,如果在 javascript 中,您想在 Render 中调用一个将字符串作为参数的“foo”函数,那么您可以这样创建它(作为 Render 的成员):

    @QtCore.pyqtSlot(str)
    def foo(self, some_tring):
        print ("Some string: %s" % some_string)
    

    ...然后在 js 文件(或 index.html)中,您只需调用 MyChannel.foo('whatever')。您可以通过 onclick 执行此操作,也可以从您从 onclick 调用的另一个函数的主体中执行此操作。

    通过MyChannel.foo('whatever') 交谈:您调用MyChannel,因为这是您分配给您在频道中注册的对象的名称(在python 中),以及您在创建new QWebChannel 时在js 中使用的名称。当您创建注册时,您将 self 作为要注册的对象传递 - 因此由 MyChannel 标识的通道是您的 Render 对象。您只能通过通道发出信号,因此您“调用”的任何东西都必须是插槽 - 因此是装饰器。


    另外,如果你想从 PyQt 调用一个 js 函数,它会更容易一些。在这种情况下,您只需调用

    self.page().runJavaScript('someJsFunction("whatever");')
    

    如果您需要对其响应进行处理,因为它被称为异步,您需要设置一个响应处理程序:

    self.page().runJavaScript('someJsFunction("whatever");', self.__callback)
    

    ...然后定义回调(可能作为Render的成员):

    def __callback(self, response):
        if response:
            print ("Handling JS response: %s", response)
    

    【讨论】:

    • 使用 Qt WebEngine 浏览器,您可以简单地使用 qwebchannel.js 的内置副本,如下所示:&lt;script src="qrc:///qtwebchannel/qwebchannel.js"&gt;&lt;/srcipt&gt;。仅当您通过第三方浏览器使用网络频道时,才需要该文件的单独副本。请参阅:Qt WebChannel JavaScript API
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-10-11
    • 2017-12-29
    • 1970-01-01
    • 2018-01-03
    • 2010-12-21
    • 2018-07-30
    • 2014-06-15
    相关资源
    最近更新 更多