我正在执行使用Python请求库上传文件的简单任务。我搜索了Stack Overflow,似乎没有人有同样的问题,即文件没有被服务器接收到:
import requests
url='http://nesssi.cacr.caltech.edu/cgi-bin/getmulticonedb_release2.cgi/post'
files={'files': open('file.txt','rb')}
values={'upload_file' : 'file.txt' , 'DB':'photcat' , 'OUT':'csv' , 'SHORT':'short'}
r=requests.post(url,files=files,data=values)
我用我的文件名填充'upload_file'关键字的值,因为如果我让它为空,它说
Error - You must select a file to upload!
现在我得到
File file.txt of size bytes is uploaded successfully!
Query service results: There were 0 lines.
只有当文件为空时才会出现。所以我不知道如何成功地发送我的文件。我知道这个文件是有效的,因为如果我去这个网站,手动填写表单,它会返回一个匹配对象的列表,这就是我想要的。我很感激所有的提示。
其他一些相关的话题(但没有回答我的问题):
从Python脚本中使用POST发送文件
http://docs.python-requests.org/en/latest/user/quickstart/#response-content
使用请求上传文件并发送额外数据
http://docs.python-requests.org/en/latest/user/advanced/#body-content-workflow
有些可能需要通过put请求上传,这与发布数据略有不同。为了形成有效的请求,了解服务器如何期望数据是很重要的。一个常见的混淆来源是当数据不被接受时发送多部分形式的数据。本例使用基本身份验证,并通过put请求更新图像。
url = 'foobar.com/api/image-1'
basic = requests.auth.HTTPBasicAuth('someuser', 'password123')
# Setting the appropriate header is important and will vary based
# on what you upload
headers = {'Content-Type': 'image/png'}
with open('image-1.png', 'rb') as img_1:
r = requests.put(url, auth=basic, data=img_1, headers=headers)
虽然请求库使处理http请求变得容易得多,但它的一些魔力和便利性掩盖了如何创建更微妙的请求。
@martijn-pieters的答案是正确的,但是我想给data=和另一边添加一点上下文,在Flask服务器中,在你试图上传文件和JSON的情况下。
从请求端来看,这就像Martijn描述的那样:
files = {'upload_file': open('file.txt','rb')}
values = {'DB': 'photcat', 'OUT': 'csv', 'SHORT': 'short'}
r = requests.post(url, files=files, data=values)
然而,在Flask端(在这篇文章的另一边的接收web服务器),我必须使用表单
@app.route("/sftp-upload", methods=["POST"])
def upload_file():
if request.method == "POST":
# the mimetype here isnt application/json
# see here: https://stackoverflow.com/questions/20001229/how-to-get-posted-json-in-flask
body = request.form
print(body) # <- immutable dict
Body = request.get_json()不会返回任何内容。Body = request.get_data()将返回一个包含许多内容的blob,如文件名等。
下面是不好的部分:在客户端,将data={}更改为json={}将导致服务器无法读取KV对!例如,这将导致上面的{}体:
r = requests.post(url, files=files, json=values). # No!
这很糟糕,因为服务器无法控制用户如何格式化请求;json=是请求用户的习惯。
客户端上传
如果你想用Python请求库上传一个文件,那么请求库支持流上传,这允许你发送大文件或流,而不读入内存。
with open('massive-body', 'rb') as f:
requests.post('http://some.url/streamed', data=f)
服务器端
然后将文件存储在server.py端,这样就可以将流保存到文件中而不加载到内存中。下面是一个使用Flask文件上传的例子。
@app.route("/upload", methods=['POST'])
def upload_file():
from werkzeug.datastructures import FileStorage
FileStorage(request.stream).save(os.path.join(app.config['UPLOAD_FOLDER'], filename))
return 'OK', 200
或者使用werkzeug表单数据解析,就像在修复“大文件上传消耗内存”的问题中提到的那样,以避免在大文件上传(s.t 22 GiB文件大约60秒)时低效地使用内存。内存使用率稳定在13 MiB左右)。
@app.route("/upload", methods=['POST'])
def upload_file():
def custom_stream_factory(total_content_length, filename, content_type, content_length=None):
import tempfile
tmpfile = tempfile.NamedTemporaryFile('wb+', prefix='flaskapp', suffix='.nc')
app.logger.info("start receiving file ... filename => " + str(tmpfile.name))
return tmpfile
import werkzeug, flask
stream, form, files = werkzeug.formparser.parse_form_data(flask.request.environ, stream_factory=custom_stream_factory)
for fil in files.values():
app.logger.info(" ".join(["saved form name", fil.name, "submitted as", fil.filename, "to temporary file", fil.stream.name]))
# Do whatever with stored file at `fil.stream.name`
return 'OK', 200