问题描述
我需要获取动态内容,该内容由ajax js调用加载.
I need to get a dynamic content, that is being loaded by a ajax js call.
我真的不知道如何使用PyQt,但我希望可以做到这一点. HTML类似于:
I really don't know how to use PyQt but i was hoping i could do this. The HTML is something like:
<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渲染页面:
I can render the page with PyQt using this simple code:
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"并获取内容?
How can i run that 'onclick' and get the content?
推荐答案
这是一个老问题,但是...
This is an old question, but...
要通过javascript运行PyQt函数:
To run PyQt functions from javascript:
虽然有许多方法可以做到这一点,但我已经通过使用QWebChannel
解决了这一问题,然后从您的html调用js函数,然后使用网络渠道与Qt进行通信.
While there may be numerous ways of doing this, I've solved it by using QWebChannel
, and then calling js functions from your html, then use the web channel to communicate with Qt.
您将需要qwebchannel.js
.我是从本地计算机上的Qt5示例目录获得的.网路上的许多地方都存在相同的档案.我让你找它.
You will need qwebchannel.js
. I got mine from the Qt5 examples directory on my local machine. The same file exists on the web in many places. I'll leave it up to you to find it.
此处介绍了许多这种方法: http://doc.qt .io/qt-5/qtwebchannel-javascript.html
Much of this method is described here: http://doc.qt.io/qt-5/qtwebchannel-javascript.html
在您的__init__
中,创建一个网络频道:
In your __init__
, create a web channel:
self.webchannel = QtWebChannel.QWebChannel(self)
然后将您的webengineview的主页设置为使用频道,并注册要在PyQt和js之间共享的对象:
then set your webengineview's main page to use the channel, and register the object you want to be shared between PyQt and js:
self.page().setWebChannel(self.webchannel)
self.webchannel.registerObject('MyChannel', self)
在您的.js(或.html的javascript部分)中,设置网络渠道:
In your .js (or the javascript section of your .html), setup the 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>
(This is where qwebchannel.js
comes into play. Your js or html file must be able to include it. For me, I loaded <script src="scripts/qwebchannel.js"></script>
before doing any other js
现在,您已设置为通过通道从js到PyQt进行调用,但是您可以调用什么呢?任何装饰为PyQt插槽的东西.因此,例如,如果您要使用javascript在Render中调用一个以字符串作为参数的"foo"函数,则可以这样创建它(作为Render的成员):
Now you're setup to make calls from js to PyQt via the channel, but what can you call? Anything that's decorated as a PyQt slot. So, for example, if, in javascript, you wanted to call a "foo" function in Render that takes a string as an argument, then you would create it (as a member of Render) as such:
@QtCore.pyqtSlot(str)
def foo(self, some_tring):
print ("Some string: %s" % some_string)
...然后在js文件中(或在index.html中),只需调用MyChannel.foo('whatever')
.您可以将其作为onclick来实现,也可以从onclick调用的另一个函数的主体中实现.
...and then in the js file (or in your index.html), you would simply make a call to MyChannel.foo('whatever')
. You could do that as an onclick, or you can do it from the body of another function that you call from onclick.
讲解MyChannel.foo('whatever')
:之所以调用MyChannel
,是因为这是分配给在通道中注册的对象的名称(在python中),也是在创建new QWebChannel
时在js中使用的名称.创建注册时,将self
作为要注册的对象传递-因此,由MyChannel
标识的通道是您的Render
对象.您只能通过该通道发出信号,因此您呼叫"的任何内容都必须是插槽-装饰器.
Talking through MyChannel.foo('whatever')
: You call MyChannel
because that was the name you assigned to the object you registered with the channel (in python), and the name you used in js when you created the new QWebChannel
. When you created the registration, you passed self
as the object to register - so the channel, identified by MyChannel
, is your Render
object. You can only signal through the channel, so anything you "call" must be a slot - hence the decorator.
或者,如果您想从PyQt调用js函数,则要容易一些.在这种情况下,您只需致电
Alternatively, if you want to call a js function from PyQt, it's a bit easier. In that case, you simply call
self.page().runJavaScript('someJsFunction("whatever");')
如果您需要对响应做出某种处理,因为它被称为异步,则需要设置响应处理程序:
If you need to do something with the response from that, because it's called async, you'll need to setup a response handler:
self.page().runJavaScript('someJsFunction("whatever");', self.__callback)
...然后定义回调(可能是Render的成员):
...and then define the callback (likely as a member of Render):
def __callback(self, response):
if response:
print ("Handling JS response: %s", response)
这篇关于使用QWebEngineView与html/javascript进行通信的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!