利用Eel使JavaScript调用Python程序
Eel简介
Eel是一个轻量的python桌面GUI开发第三方库, 它使用HTML/JS作为界面开发语言, 但是能够访问所有的python功能, 类似于electron, 但是比它轻量。
Eel实际上是启动了一个本地的web服务器, 它允许你将python的函数暴露给javascript, 所以网页端也能调用python函数。
有很多类似于electron的python实现, 比如cefpython, 但是Eel是轻量级的, 它只是启动了一个chrome app, 所以需要你提前安装好chrome浏览器才可以, 而electron和cefpython都是封装了网页渲染引擎的。
安装很简单:
使用pip就行:
pip install eel
用法
目录结构
Ele工程需要将前端页面和js代码都放在一个特定的文件夹, 其他python模块可以放到任意可以使用的地方。类似这样的目录结构:
my_python_script.py <-- Python scripts
other_python_module.py
web/ <-- Web folder
main.html
css/
style.css
img/
logo.png
HelloWrold
你需要写一个简单的main.html
页面, 然后放到存放网页的文件夹web
, 这个文件夹内的文件都被前端访访问。然后写一个简单的app.py
文件, 代码如下:
import eel
eel.init('web')
eel.start('main.html')
最后只要在命令行运行:python app.py
即可看到你的页面。
可选参数
在调用eel.start
的时候, 可以传入一些参数, 比如设置窗口尺寸的size参数:eel.start('main.html', size=(50, 50))
, 主要可以设置mode/port和启动chrome的时候一些命令行参数, 这些命令行参数可以从这里查看 :
eel.start('main.html', port=8888)
暴露函数
为了实现高级的功能, 你必须要在前端页面中引入下面的js模块:
<script type="text/javascript" src="/eel.js"></script>
然后你可以在写python模块的时候, 使用装饰器eel.expose
来暴露你的python函数给JavaScript:
@eel.expose
def my_python_function(a, b):
print(a, b, a + b)
然后你在前端, 可以使用下面的js代码来调用你的python函数:
console.log('Calling Python...');
eel.my_python_function(1, 2); // This calls the Python function that was decorated
当然你也可可以将JavaScript代码暴露给python用:
eel.expose(my_javascript_function);
function my_javascript_function(a, b, c, d) {
if(a < b){
console.log(c * d);
}
}
然后你就可以在python中掉用JavaScript:
print('Calling Javascript...')
eel.my_javascript_function(1, 2, 3, 4) # This calls the Javascript function
完整案例
下面是我们的’main.html’文件的主要内容:
<!DOCTYPE html>
<html>
<head>
<title>Hello, World!</title>
<!-- Include eel.js - note this file doesn't exist in the 'web' directory -->
<script type="text/javascript" src="/eel.js"></script>
<script type="text/javascript">
eel.expose(say_hello_js); // Expose this function to Python
function say_hello_js(x) {
console.log("Hello from " + x);
}
say_hello_js("Javascript World!");
eel.say_hello_py("Javascript World!"); // Call a Python function
</script>
</head>
<body>
Hello, World!
</body>
</html>
然后python模块是:
import eel
eel.init('web') # Give folder containing web files
@eel.expose # Expose this function to Javascript
def say_hello_py(x):
print('Hello from %s' % x)
say_hello_py('Python World!')
eel.say_hello_js('Python World!') # Call a Javascript function
eel.start('hello.html') # Start (this blocks and enters loop)
回调函数
当你调用一个被暴露的函数的时候, 我们可以传入一个函数, 这样就能在函数执行完毕之后立即调用这个函数。例如:
在js里定义一个函数:
eel.expose(js_random);
function js_random() {
return Math.random();
}
然后, 在python里调用的时候:
# 这是一个回调函数
def print_num(n):
print('Got this from Javascript:', n)
# 在python里调用js的函数, 然后, 再传入一个回调函数
# 回调函数将会在js函数执行完毕之后再执行
eel.js_random()(print_num)
同步返回
在python端, 我们只要不使用回调函数就能同步返回:
n = eel.js_random()() # 这里有两个括号
print('Got this from Javascript:', n)
假如python里已经暴露了一个函数py_random
, 在JavaScript端, 程序不允许阻塞, 所以只能使用await来避免使用回调函数:
async function run() {
// 只要函数前面带有async, 才能在函数内部使用await
let n = await eel.py_random()(); // Must prefix call with 'await', otherwise it's the same syntax
console.log('Got this from Python: ' + n);
}
run();
打包二进制文件
如果你想让用户下载你的软件使用, 而用户没有安装python, 你最好将你的程序打包成二进制可执行文件, 那么最好使用pyinstaller。
在你的app根目录下执行下面的命令:
python -m eel [your_main_script] [your_web_folder]
这将创建一文件夹dist
, 如果你想要创建单文件程序, 你需要使用--onefile
参数, 如果不想程序运行的时候有一个黑色命令窗口, 你可以使用--noconsole
参数。