如何在 Python 中从 Javascript 中读取值
Posted
技术标签:
【中文标题】如何在 Python 中从 Javascript 中读取值【英文标题】:How to read value from Javascript in Python 【发布时间】:2021-12-17 08:36:25 【问题描述】:我在 PyQt5 QWebEngine 中有一个复杂的图表,我希望能够在 python 上导入点击点。
这不是完整的代码,而是重要的部分。我已经可以通过 javascript 代码截取点的坐标并在点击时插入警报,但我希望能够在 Python 中使用它们。
self.browser = QtWebEngineWidgets.QWebEngineView(self)
vbox.addWidget(self.browser)
vbox.setSpacing(0)
vbox.setContentsMargins(0, 0, 0, 0)
self.show_graph(input_dict)
def show_graph(self, input_dict):
# Initialize figure with 3 3D subplots
...
#details of graph
...
fig = go.FigureWidget(fig.to_dict())
self.browser.sethtml(fig.to_html(include_plotlyjs='cdn', post_script="document.getElementsByClassName('plotly-graph-div')[0].on('plotly_click', function(data)alert(data.points[0].x + '-' + data.points[0].y));"))
所以代码的 javascript 部分可以工作,但我希望在 python 中可用数据而不是警报。我该怎么办?
【问题讨论】:
这能回答你的问题吗? Call Python function from JavaScript code 你需要构建一个 API 来执行 python 【参考方案1】:一种可能的解决方案是使用 QWebChannel。逻辑是导出一个 QObject 作为桥梁。
import json
import plotly.graph_objects as go
from PyQt5.QtCore import pyqtSlot, QFile, QIODevice, QObject
from PyQt5.QtWidgets import QApplication, QVBoxLayout, QWidget
from PyQt5.QtWebEngineWidgets import QWebEngineScript, QWebEngineView
from PyQt5.QtWebChannel import QWebChannel
def get_webchannel_source():
file = QFile(":/qtwebchannel/qwebchannel.js")
if not file.open(QIODevice.ReadOnly):
return ""
content = file.readAll()
file.close()
return content.data().decode()
class Backend(QObject):
@pyqtSlot(str, name="handleClicked")
def handle_clicked(self, o):
py_obj = json.loads(o)
print(py_obj)
class Widget(QWidget):
def __init__(self, parent=None):
super().__init__(parent)
self.backend = Backend()
self.browser = QWebEngineView()
script = QWebEngineScript()
script.setName("create_connection")
script.setSourceCode(get_webchannel_source())
script.setInjectionPoint(QWebEngineScript.DocumentReady)
script.setWorldId(QWebEngineScript.MainWorld)
script.setRunsOnSubFrames(False)
self.browser.page().profile().scripts().insert(script)
channel = QWebChannel(self)
channel.registerObject("backend", self.backend)
self.browser.page().setWebChannel(channel)
vbox = QVBoxLayout(self)
vbox.addWidget(self.browser)
vbox.setSpacing(0)
vbox.setContentsMargins(0, 0, 0, 0)
self.browser.loadFinished.connect(print)
self.build_plot()
def build_plot(self):
trace = go.Heatmap(
z=[[1, 20, 30, 50, 1], [20, 1, 60, 80, 30], [30, 60, 1, -10, 20]],
x=["Monday", "Tuesday", "Wednesday", "Thursday", "Friday"],
y=["Morning", "Afternoon", "Evening"],
)
data = [trace]
layout = go.Layout(title="Activity Heatmap")
fig = go.Figure(data=data, layout=layout)
fig = go.FigureWidget(fig.to_dict())
script = """
window.backend = null;
window.onload = function()
new QWebChannel(qt.webChannelTransport, function(channel)
window.backend = channel.objects.backend;
);
var elements = document.getElementsByClassName('plotly-graph-div');
if(elements.length > 0)
var element = elements[0];
element.on("plotly_click", function(data)
var point = data.points[0];
if(window.backend != null)
var json_str = JSON.stringify(x: point.x, y: point.y)
window.backend.handleClicked(json_str);
)
"""
html = fig.to_html(include_plotlyjs="cdn", post_script=script)
self.browser.setHtml(html)
def main():
app = QApplication([])
w = Widget()
w.resize(640, 480)
w.show()
app.exec_()
if __name__ == "__main__":
main()
【讨论】:
我会尝试这个解决方案,还有哪些其他可能的解决方案?是否可以通过javascript将数据保存在json文件中并在python中读取? @DavideSerafini 您提出的解决方案有几个缺点,例如: - 跟踪文件何时写入以及不太优雅。 QWebChannel 通过 websockets 实现通信(websockets 代码没有显示,但它们在那里)使得信息的发送变得简单。我不明白您为什么需要另一种解决方案。 您的解决方案对我来说似乎很棒,我正在尝试在我的代码中实现它以使其工作,不幸的是上面的代码不会产生任何结果。既然您写道这是可能的解决方案之一,我很想了解其他可能性是什么 @DavideSerafini 1. 我总是说这是可能的解决方案之一,因为我没有能力认为它是唯一可能的解决方案,也许其他人有更多的解决方案。 2.首先尝试我的解决方案(不要尝试直接在您的代码中应用它),如果它有效,则尝试将其应用到您的项目中,但我不对后者负责。以上是关于如何在 Python 中从 Javascript 中读取值的主要内容,如果未能解决你的问题,请参考以下文章
json post后在javascript中从python访问值
如何在 JavaScript 中从 html 引用 iframe
如何在 AngularJs 中从 HTML 转换 JavaScript 代码