使用 QWebEngineView 与 html/javascript 通信
Communicate with html/javascript using QWebEngineView
我需要获取一个动态内容,它正在通过 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 到 运行 PyQt 函数:
虽然可能有很多方法可以做到这一点,但我已经通过使用 QWebChannel
解决了它,然后从您的 html 调用 js 函数,然后使用网络通道与 Qt 通信.
您将需要 qwebchannel.js
。我从本地机器上的 Qt5 示例目录中获取了我的。 Web 上很多地方都存在相同的文件。我会留给你找到它。
此处描述了此方法的大部分内容: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
现在您已经设置好通过通道从 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
对象。您只能通过通道发送信号,因此您 "call" 必须是插槽 - 因此是装饰器。
或者,如果您想从 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)
我需要获取一个动态内容,它正在通过 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 到 运行 PyQt 函数:
虽然可能有很多方法可以做到这一点,但我已经通过使用 QWebChannel
解决了它,然后从您的 html 调用 js 函数,然后使用网络通道与 Qt 通信.
您将需要 qwebchannel.js
。我从本地机器上的 Qt5 示例目录中获取了我的。 Web 上很多地方都存在相同的文件。我会留给你找到它。
此处描述了此方法的大部分内容: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
现在您已经设置好通过通道从 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
对象。您只能通过通道发送信号,因此您 "call" 必须是插槽 - 因此是装饰器。
或者,如果您想从 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)