使用QWebEngineView与HTML/JavaScript交互通信

10

我需要获取通过 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' 并获取内容?

1个回答

12

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

要从JavaScript运行PyQt函数:

虽然可能有多种方法可以实现此目的,但我通过使用QWebChannel解决了这个问题,然后从您的HTML调用js函数,然后使用Web Channel与Qt通信。

您将需要 qwebchannel.js 。我从本地计算机上的Qt5示例目录中获取了我的文件。相同的文件在许多地方都存在于网络上。我会让你自己去找它。

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

在您的 __init__ 中,创建一个Web Channel:

self.webchannel = QtWebChannel.QWebChannel(self)

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

self.page().setWebChannel(self.webchannel)
self.webchannel.registerObject('MyChannel', self)
在您的 .js 文件(或者 .html 中的 JavaScript 部分)中设置 web channel:
var MyChannel = null;
new QWebChannel(qt.webChannelTransport, function(channel) {
                MyChannel = channel.objects.MyChannel;
});

这就是qwebchannel.js发挥作用的地方。您的js或html文件必须能够包含它。对于我来说,在执行任何其他js之前,我加载了<script src="scripts/qwebchannel.js"></script>

现在您已经设置好从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中向channel注册对象时分配的名称,也是你在创建new QWebChannel时在js中使用的名称。当你创建注册表时,你将self作为要注册的对象传递给了它 - 因此,由MyChannel标识的channel就是你的Render对象。你只能通过channel发送信号,所以你“调用”的任何东西都必须是一个slot - 因此需要装饰器。


或者,如果你想从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)

2
使用Qt WebEngine浏览器,您可以简单地使用内置的qwebchannel.js副本,如下所示:<script src="qrc:///qtwebchannel/qwebchannel.js"></srcipt>。仅在使用第三方浏览器时才需要单独的文件副本。请参阅:Qt WebChannel JavaScript API - ekhumoro

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接