首页 > 解决方案 > Python/Flask - 通过从 Jupyter Notebook 传递路径来上传文件

问题描述

语境

我创建了一个 Flask 应用程序,它允许我:

(1)上传一个GeoTIFF文件到指定文件夹(UPLOAD_FOLDER)

(2) 使用GDAL将上传的GeoTIFF作为Pandas数据框打开,并返回一个包含所有单元格值的JSON。应用程序代码如下:

import os
import gdal
import numpy as np
import pandas as pd
import json
from flask import Flask, flash, request, redirect, url_for
from werkzeug.utils import secure_filename

UPLOAD_FOLDER = 'PATH_GOES_HERE'  #specify path
ALLOWED_EXTENSIONS = set(['tif'])

app = Flask(__name__)
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER

def allowed_file(filename):
    return '.' in filename and \
           filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS

@app.route('/upload', methods=['GET', 'POST'])
def upload_file():
    if request.method == 'POST':
        if 'file' not in request.files:
            flash('No file part')
            return redirect(request.url)
        file = request.files['file']
        if file.filename == '':
            flash('No selected file')
            return redirect(request.url)
        if file and allowed_file(file.filename):
            filename = secure_filename(file.filename)
            file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))
            return redirect(url_for('get_raster_data',
                                    filename=filename))
    return '''
    <!doctype html>
    <title>Upload raster file</title>
    <h1>Upload raster file</h1>
    <form method=post enctype=multipart/form-data>
      <input type=file name=file>
      <input type=submit value=Upload>
    </form>
    '''

@app.route('/rasterdata', methods=['GET'])
def get_raster_data():
    filename = secure_filename(request.args.get('filename'))
    try:
        if filename and allowed_file(filename):
            f = os.path.join(app.config['UPLOAD_FOLDER'], filename)
            rast_data = gdal.Open(f)
            rast_array = np.array(rast_data.GetRasterBand(1).ReadAsArray())
        return pd.DataFrame(rast_array).to_json()
    except IOError:
        pass
    return "Unable to read file"

该应用程序工作正常(即我已经使用本地主机进行了测试并在调试模式下运行)。该应用程序允许我使用“选择文件”和“上传”按钮打开网页。上传文件后,我将被重定向到具有预期输出的“/rasterdata”页面。

我的任务是创建一个 Jupyter Notebook,基本上只需要用户指定他们想要上传的 GeoTIFF 的路径。指定路径后,Flask 应用程序需要运行并返回所有 GeoTIFF 单元格值的数据框。从那里,笔记本经历了一些需要数据框作为输入的处理步骤,但这些与我的问题无关。

问题

如何通过简单地在 Jupyter Notebook 中指定 GeoTIFF 的路径将文件上传到 UPLOAD_FOLDER?下面是我的 Jupyter Notebook 中的代码。我添加了评论,说明我卡在哪里了。我怀疑我需要修改 Flask 应用程序以获取路径名。不过,我找不到任何教程。我能找到的所有教程都给了我与我目前拥有的相似的代码。

url = f'http://localhost:5000/upload'
my_path = r'C:\Users\admievan\Desktop\FlaskGDAL\my_raster.tif'

#Opening the upload page
with urllib.request.urlopen(path) as url:
    #THIS IS WHERE I AM STUCK
    #I want to pass my_path to the Flask application rather than having to
    #manually navigate to the file in the GUI interface that comes up when clicking
    #the "Choose file" button

#Reading the data web page as a panadas data frame
#This part works fine if 'my_raster.tif' is already in the UPLOAD_FOLDER
url = f'http://localhost:5000/rasterdata?filename=my_raster.tif'
df = pd.read_json(url, orient='rows')
df

标签: pythonflaskjupyter-notebookgdalgeotiff

解决方案


在处理上传/提取和 API 调用时,请求包是您最好的朋友。无论您的主机是什么网址,您都需要通过它。上传并不太难,可能看起来像这样:

import os
import base64
import urllib
import json
import requests
def jupyter_upload(token, filePath, resourceDstPath, jupyterUrl='http://localhost:8888'):
    dstPath = urllib.quote(resourceDstPath)
    dstUrl = '%s/api/contents/%s' % (jupyterUrl, dstPath)
    fileName = filePath[1 + filePath.rfind(os.sep):]
    headers = {}
    headers['Authorization'] = 'token '+token
    with open(filePath, 'r') as myfile:
        data=myfile.read()
        b64data=base64.encodestring(data)
        body = json.dumps({
            'content':b64data,
            'name': fileName,
            'path': resourceDstPath,
            'format': 'base64',
            'type':'file'
        })
        return requests.put(dstUrl, data=body, headers=headers, verify=True)`

推荐阅读