65.9K
CodeProject 正在变化。 阅读更多。
Home

Python 3 与 Electron/Node.JS 的连接:构建现代桌面应用

starIconstarIconstarIconstarIconstarIcon

5.00/5 (1投票)

2020年4月28日

CPOL

5分钟阅读

viewsIcon

9874

你可以用来连接或集成 Python 与 Node.js 和 Electron 的可能方法,附带简单示例

必备组件

本教程面向想要使用现代 Web 技术(HTML、CSS、JS 及相关框架)构建桌面应用程序和 GUI 的 Python 开发者。

为了能够舒适地学习本教程,你需要具备一些先决条件:

  • 必须掌握 Python 知识。
  • 你应该熟悉 JavaScript、HTML 和 CSS 等 Web 技术。
  • 你也应该熟悉通过 npm 安装和使用 Node.js 包。

步骤 1 - 设置开发环境

在本节中,我们将设置一个开发环境来运行我们的示例。我们需要在我们的机器上同时安装 Node.js、NPM 和 Python 3。

安装 Node.js 和 NPM

你可以通过多种方式在你的开发机器上安装 Node.js 和 NPM,例如使用:

  • 适用于你目标操作系统的官方二进制文件
  • 适用于你系统的官方包管理器
  • NVM (Node 版本管理器),用于在同一台机器上安装和管理多个 Node.js 版本

我们保持简单,只需访问 官方网站,下载适用于你目标操作系统的二进制文件,然后按照说明在你的系统上安装 Node.js 和 NPM。

设置 Python 虚拟环境

你的开发机器很可能已经安装了 Python 3。如果尚未安装,最简单的方法是访问 官方网站,下载适用于你目标系统的二进制文件。

你可以通过打开命令行界面并运行以下命令来确保你的系统已安装 Python 3:

$ python --version
Python 3.7.0

现在,让我们设置一个虚拟环境。

创建虚拟环境

在本节中,你将使用 venv 创建一个隔离的虚拟环境来运行你的示例并安装所需的包。

虚拟环境允许你创建一个环境来隔离当前项目的依赖项。这将使你能够避免同一包不同版本之间的冲突。

在 Python 3 中,你可以利用 venv 模块来创建虚拟环境。

现在,转到你的终端并运行以下命令来创建一个虚拟环境:

$ python -m venv env

接下来,你需要使用以下命令激活该环境:

$ source env/bin/activate

在 Windows 上,你可以使用 Scripts\activate.bat 文件激活虚拟环境,如下所示:

$ env\Scripts\activate.bat

好了。你现在已经激活了虚拟环境,可以为你示例安装所需的包了。

步骤 4 - 创建 Node.js 应用程序

既然我们已经通过安装 Node.js 和 npm 以及创建 Python 虚拟环境来设置了 Python 和 Electron 开发环境,现在让我们继续创建我们的 Electron 应用程序。

让我们先创建一个项目文件夹,并在其中创建一个 package.json 文件,使用以下命令:

$ mkdir python-nodejs-example
$ cd python-nodejs-example
$ npm init -y

npm 的 init 命令将生成一个具有以下默认值的 package.json 文件:

{
  "name": "python-nodejs-example",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC"
}

你可以根据项目需要自定义此文件中的值,也可以为这个简单的示例直接使用默认值。

接下来,我们需要在项目文件夹中创建两个文件:index.htmlindex.js

$ touch index.js 
$ touch index.html

如何实现 Electron 和 Python 之间的通信

在本节中,我们将了解你可以用来实现 Electron 和 Python 进程之间通信的各种可用方法。

什么是 IPC?

根据 维基百科

在计算机科学中,进程间通信或 IPC 特指操作系统提供的允许进程管理共享数据的机制。通常,应用程序可以使用 IPC,按客户端和服务器分类,其中客户端请求数据,服务器响应客户端的请求。

IPC 指的是操作系统支持的一套机制,用于使不同、本地或远程的进程能够相互通信。例如,在我们的例子中,我们希望允许 Electron 进程和 Python 进程之间的通信。

让我们来看一些实现 IPC 的方法。

使用 child_process 启动 Python 进程

Node.js 提供了 {child_process] (https://node.org.cn/api/child_process.html) 模块,它允许你启动子进程。

让我们使用它来启动一个 Python 进程并运行一个简单的 calc.py 脚本。

我们将使用 simplecalculator 在 Python 中执行简单的计算,所以我们首先运行以下命令来安装它:

$ sudo pip install simplecalculator

首先,在你的项目文件夹内,创建一个 py 文件夹,并在其中创建一个 calc.py 文件:

$ mkdir py & cd py
$ touch calc.py

打开 calc.py 文件并添加以下 Python 代码,该代码执行计算并将结果打印到标准输出:

from sys import argv
from calculator.simple import SimpleCalculator

def calc(text):
	"""based on the input text, return the operation result"""
	try:
		c = SimpleCalculator()
		c.run(text)
		return c.log[-1]
	except Exception as e:
		print(e)
		return 0.0

if __name__ == '__main__':
    print(calc(argv[1]))

接下来,创建一个 renderer.js 文件,并添加以下代码以启动 Python 进程并执行 py/calc.py 脚本:

function sendToPython() {
  var python = require('child_process').spawn('python', ['./py/calc.py', input.value]);
  python.stdout.on('data', function (data) {
    console.log("Python response: ", data.toString('utf8'));
    result.textContent = data.toString('utf8');
  });

  python.stderr.on('data', (data) => {
    console.error(`stderr: ${data}`);
  });

  python.on('close', (code) => {
    console.log(`child process exited with code ${code}`);
  });
}

btn.addEventListener('click', () => {
  sendToPython();
});

btn.dispatchEvent(new Event('click'));

接下来,打开 index.html 文件并按如下方式更新它:

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Calling Python from Electron!</title>
</head>

<body>
    <h1>Simple Python Calculator!</h1>
    <p>Input something like <code>1 + 1</code>.</p>
    <input id="input" value="1 + 1"></input>
    <input id="btn" type="button" value="Send to Python!"></input>
    </br>
    Got <span id="result"></span>
    
    <script src="./renderer.js"></script>

</body>
</html>

使用 python-shell

在了解了如何使用 child_process 实现 Electron 和 Python 之间的通信后,现在让我们看看如何使用 python-shell

python-shell 是一个 npm 包,它提供了一种简单的方法,可以从 Node.js 运行 Python 脚本,并具有基本而高效的进程间通信和错误处理。

你可以使用 python-shell 来:

  • 启动 Python 脚本
  • 在文本、JSON 和二进制模式之间切换
  • 通过 stdinstdout 流进行数据传输
  • 在发生错误时获取堆栈跟踪

转到你的终端,然后运行以下命令从 npm 安装 python-shell

$ npm install --save python-shell

在撰写本文时,我们的项目中已安装 python-shell v1.0.8

接下来,打开 renderer.js 文件并将 sendToPython() 函数更新如下:

function sendToPython() {
  var { PythonShell } = require('python-shell');

  let options = {
    mode: 'text',
    args: [input.value]
  };

  PythonShell.run('./py/calc.py', options, function (err, results) {
    if (err) throw err;
    // results is an array consisting of messages collected during execution
    console.log('results: ', results);
    result.textContent = results[0];
  });
}

使用客户端-服务器通信

现在让我们来看另一种使用 HTTP 服务器在 Python 和 Electron 之间实现通信的方法。

回到你的终端,运行以下命令来安装 Flask 和 Flask-Cors:

$ pip install flask
$ pip install Flask-Cors

接下来,在项目的 py 文件夹中,创建一个 server.py 文件,并添加以下代码来运行一个 Flask 服务器,该服务器执行一个计算并将结果作为 HTTP 响应返回:

import sys
from flask import Flask
from flask_cors import cross_origin
from calculator.simple import SimpleCalculator

def calcOp(text):
	"""based on the input text, return the operation result"""
	try:
		c = SimpleCalculator()
		c.run(text)
		return c.log[-1]
	except Exception as e:
		print(e)
		return 0.0

app = Flask(__name__)

@app.route("/<input>")
@cross_origin()
def calc(input):    
    return calcOp(input)

if __name__ == "__main__":
    app.run(host='127.0.0.1', port=5001)

接下来,打开 renderer.js 文件并添加以下代码来启动 Python 并运行 server.py 文件:

let input = document.querySelector('#input')
let result = document.querySelector('#result')
let btn = document.querySelector('#btn')

function sendToPython() {
  var { PythonShell } = require('python-shell');

  let options = {
    mode: 'text'
  };
  
  PythonShell.run('./py/server.py', options, function (err, results) {
    if (err) throw err;
    // results is an array consisting of messages collected during execution
    console.log('response: ', results);
  });
}

function onclick(){

  fetch(`http://127.0.0.1:5001/${input.value}`).then((data)=>{      
      return data.text();
      
  }).then((text)=>{
    console.log("data: ", text);
    result.textContent = text;
  }).catch(e=>{
    console.log(e);
  })
}
sendToPython();

btn.addEventListener('click', () => {
  onclick();
});

btn.dispatchEvent(new Event('click'))

回顾

在本教程中,我们为 Python 开发者介绍了 Electron,如果你想使用基于 HTML、CSS 和 JavaScript 的现代 Web 技术为你的 Python 应用构建 GUI,它将是一个非常有用的工具。我们还看到了连接 Python 和 Electron 的不同方法,例如 child_processpython-shell 和 HTTP (Flask) 服务器。

© . All rights reserved.