如何通过点击HTML网页按钮在后端运行Jupyter Notebook?
通过前端按钮触发后端运行Jupyter Notebook的实现方案
方案1:基于Python Web框架(Flask/FastAPI)封装执行逻辑
这是最灵活的方案,适合需要自定义业务逻辑、处理执行结果的场景。
操作步骤:
安装依赖
先安装所需的Python库:pip install flask nbclient nbformat flask-corsflask:搭建Web后端接口nbclient:以编程方式执行Jupyter Notebooknbformat:解析和处理Notebook文件格式flask-cors:解决前后端跨域问题(若前后端分离部署)
编写Flask后端代码
创建app.py文件,实现接收前端请求、执行Notebook的接口:from flask import Flask, jsonify from flask_cors import CORS from nbformat import read, NO_CONVERT from nbclient import NotebookClient app = Flask(__name__) CORS(app) # 允许跨域请求 @app.route('/run-notebook', methods=['POST']) def run_notebook(): try: # 读取目标Notebook文件 with open('your_notebook.ipynb', 'r', encoding='utf-8') as f: nb = read(f, NO_CONVERT) # 配置并执行Notebook client = NotebookClient(nb, timeout=600, kernel_name='python3') client.execute() # 收集执行结果(可选,按需处理) outputs = [] for cell in nb.cells: if hasattr(cell, 'outputs') and cell.outputs: for output in cell.outputs: if output.output_type == 'stream': outputs.append(output.text) elif output.output_type == 'execute_result': outputs.append(str(output.data.get('text/plain', ''))) return jsonify({'status': 'success', 'outputs': outputs}), 200 except Exception as e: return jsonify({'status': 'error', 'message': str(e)}), 500 if __name__ == '__main__': app.run(host='0.0.0.0', port=5000, debug=True)编写前端页面
创建index.html,添加按钮并绑定点击事件:<!DOCTYPE html> <html> <head> <title>运行Jupyter Notebook</title> <style> #runNotebookBtn { padding: 10px 20px; font-size: 16px; cursor: pointer; background-color: #4CAF50; color: white; border: none; border-radius: 4px; } #runNotebookBtn:hover { background-color: #45a049; } #result { margin-top: 20px; padding: 10px; border: 1px solid #ccc; border-radius: 4px; min-height: 50px; } </style> </head> <body> <button id="runNotebookBtn">运行Jupyter笔记本</button> <div id="result"></div> <script> const btn = document.getElementById('runNotebookBtn'); const resultDiv = document.getElementById('result'); btn.addEventListener('click', async () => { btn.disabled = true; btn.textContent = '运行中...'; resultDiv.textContent = ''; try { const response = await fetch('http://localhost:5000/run-notebook', { method: 'POST', headers: { 'Content-Type': 'application/json' } }); const data = await response.json(); if (data.status === 'success') { resultDiv.textContent = '执行成功!输出结果:\n' + data.outputs.join('\n'); } else { resultDiv.textContent = '执行失败:' + data.message; } } catch (error) { resultDiv.textContent = '请求出错:' + error.message; } finally { btn.disabled = false; btn.textContent = '运行Jupyter笔记本'; } }); </script> </body> </html>运行测试
- 启动Flask后端:
python app.py - 打开
index.html页面,点击按钮即可触发Notebook执行。
- 启动Flask后端:
方案2:直接调用Jupyter Server的REST API
利用Jupyter自带的官方API,无需额外封装执行逻辑,适合快速搭建场景。
操作步骤:
启动带API访问的Jupyter Server
测试环境启动命令(生产环境必须设置token/密码):jupyter notebook --port=8888 --NotebookApp.token='' --NotebookApp.password='' --allow-origin='*'--allow-origin='*':允许跨域请求(生产环境建议指定具体域名)
前端调用API执行Notebook
修改前端JS代码,通过Jupyter API完成执行流程:<script> const btn = document.getElementById('runNotebookBtn'); const resultDiv = document.getElementById('result'); const baseUrl = 'http://localhost:8888/api'; btn.addEventListener('click', async () => { btn.disabled = true; btn.textContent = '运行中...'; resultDiv.textContent = ''; try { // 1. 创建Python内核 const kernelResp = await fetch(`${baseUrl}/kernels`, { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify({name: 'python3'}) }); const kernel = await kernelResp.json(); const kernelId = kernel.id; // 2. 获取Notebook内容 const nbResp = await fetch(`${baseUrl}/contents/your_notebook.ipynb`); const nbData = await nbResp.json(); const cells = nbData.content.cells; // 3. 逐个执行单元格 const outputs = []; for (const cell of cells) { if (cell.cell_type === 'code') { const execResp = await fetch(`${baseUrl}/kernels/${kernelId}/execute`, { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify({code: cell.source}) }); const execResult = await execResp.json(); outputs.push(`单元格输出:${JSON.stringify(execResult.content)}`); } } // 4. 关闭内核(可选) await fetch(`${baseUrl}/kernels/${kernelId}`, {method: 'DELETE'}); resultDiv.textContent = '执行成功!输出结果:\n' + outputs.join('\n'); } catch (error) { resultDiv.textContent = '请求出错:' + error.message; } finally { btn.disabled = false; btn.textContent = '运行Jupyter笔记本'; } }); </script>注意事项
- 生产环境必须配置Jupyter的认证机制(token或密码),避免未授权访问
- Jupyter API的详细文档可通过启动后的
http://localhost:8888/docs查看
方案3:通过nbconvert命令行工具批量执行
适合仅需运行Notebook并生成输出文件(如HTML、PDF),无需实时获取执行结果的场景。
操作步骤:
安装nbconvert
pip install nbconvert编写后端接口(以Flask为例)
修改app.py中的接口,用subprocess调用nbconvert命令:from flask import Flask, jsonify from flask_cors import CORS import subprocess import os app = Flask(__name__) CORS(app) @app.route('/run-notebook', methods=['POST']) def run_notebook(): try: notebook_path = 'your_notebook.ipynb' output_path = 'output.html' # 执行nbconvert命令,运行Notebook并生成HTML输出 subprocess.run( ['jupyter', 'nbconvert', '--execute', '--to', 'html', notebook_path, '--output', output_path], check=True, capture_output=True, text=True ) # 检查输出文件是否生成 if os.path.exists(output_path): return jsonify({'status': 'success', 'output_file': output_path}), 200 else: return jsonify({'status': 'error', 'message': '输出文件未生成'}), 500 except subprocess.CalledProcessError as e: return jsonify({'status': 'error', 'message': f'命令执行失败:{e.stderr}'}), 500 except Exception as e: return jsonify({'status': 'error', 'message': str(e)}), 500 if __name__ == '__main__': app.run(host='0.0.0.0', port=5000, debug=True)前端处理结果
前端可以在请求成功后,通过链接下载生成的输出文件:// 在fetch成功的分支添加 if (data.status === 'success') { const downloadLink = document.createElement('a'); downloadLink.href = data.output_file; downloadLink.download = 'notebook_output.html'; downloadLink.textContent = '点击下载执行结果'; resultDiv.innerHTML = '执行成功!'; resultDiv.appendChild(downloadLink); }
内容的提问来源于stack exchange,提问作者Coding Geeek
相关产品推荐
相关产品推荐

