如何在 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 中从 servlet 传递值

如何在 JavaScript 中从 html 引用 iframe

如何在 AngularJs 中从 HTML 转换 JavaScript 代码

如何在swift中从.js文件中调用javascript函数

如何在javascript中从json文件中读取数据