我正在执行使用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.
仅在文件为空时才会出现。所以我对如何成功发送文件感到困惑。我知道该文件有效,因为如果我去这个网站并手动填写表格,它会返回一个很好的匹配对象列表,这就是我所追求的。我非常感谢所有提示。
其他一些线程相关(但没有回答我的问题):
答案 0 :(得分:141)
如果要将upload_file
作为文件,请使用:
files = {'upload_file': open('file.txt','rb')}
values = {'DB': 'photcat', 'OUT': 'csv', 'SHORT': 'short'}
r = requests.post(url, files=files, data=values)
和requests
将发送多部分表单POST正文,并将upload_file
字段设置为file.txt
文件的内容。
文件名将包含在特定字段的mime标头中:
>>> import requests
>>> open('file.txt', 'wb') # create an empty demo file
<_io.BufferedWriter name='file.txt'>
>>> files = {'upload_file': open('file.txt', 'rb')}
>>> print(requests.Request('POST', 'http://example.com', files=files).prepare().body.decode('ascii'))
--c226ce13d09842658ffbd31e0563c6bd
Content-Disposition: form-data; name="upload_file"; filename="file.txt"
--c226ce13d09842658ffbd31e0563c6bd--
请注意filename="file.txt"
参数。
如果需要更多控制,可以使用元组作为files
映射值,使用2到4个元素。第一个元素是文件名,后跟内容,可选的内容类型标题值和附加标题的可选映射:
files = {'upload_file': ('foobar.txt', open('file.txt','rb'), 'text/x-spam')}
这会设置一个替代文件名和内容类型,省略可选标题。
如果您要从文件中获取整个POST正文(未指定其他字段),则不要使用files
参数,只需将文件直接发布为{{1} }。然后,您可能还想设置data
标题,否则将不会设置。
答案 1 :(得分:17)
(2018年)新的python请求库简化了此过程,我们可以使用'files'变量表示我们要上传由多部分编码的文件
func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
let delete = UIContextualAction(style: .normal, title: "") { (action, view, completion) in
print("Delete Pressed")
completion(true)
}
delete.backgroundColor = UIColor.clear
delete.image = #imageLiteral(resourceName: "trash")
let config = UISwipeActionsConfiguration(actions: [delete])
config.performsFirstActionWithFullSwipe = false
return config
}
func tableView(_ tableView: UITableView, willBeginEditingRowAt indexPath: IndexPath) {
tableView.subviews.forEach { subview in
if (String(describing: type(of: subview)) == "UISwipeActionPullView") {
if (String(describing: type(of: subview.subviews[0])) == "UISwipeActionStandardButton") {
if let actionButtonCGRect = actionButtonCGRect {
subview.subviews[0].bounds = actionButtonCGRect
} else {
actionButtonCGRect = subview.subviews[0].frame.insetBy(dx: 0, dy: 10)
subview.subviews[0].bounds = actionButtonCGRect!
}
subview.subviews[0].layer.cornerRadius = 10
subview.subviews[0].clipsToBounds = true
subview.subviews[0].backgroundColor = UIColor.red
}
}
}
}
答案 2 :(得分:8)
如果您想使用Python requests
库上传单个文件,则请求lib supports streaming uploads,该库允许您发送大型文件或流而无需阅读进入内存。
with open('massive-body', 'rb') as f:
requests.post('http://some.url/streamed', data=f)
然后将文件存储在server.py
侧,以便将流保存到文件中而不加载到内存中。以下是使用Flask file uploads的示例。
@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 Form Data Parsing”修复中提到的large file uploads eating up memory,以避免在上传大文件时低效使用内存(第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
答案 3 :(得分:0)
@martijn-pieters 答案是正确的,但是我想在 Flask 服务器中向 data=
以及另一端添加一些上下文,以防您尝试上传文件 和 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 端(此 POST 另一端的接收网络服务器),我不得不使用 form
@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=
将成为请求用户的习惯。
答案 4 :(得分:-2)
在Ubuntu中,您可以采用这种方式
path = default_storage.save('static/tmp/' + f1.name, ContentFile(f1.read()))
path12 = os.path.join(os.getcwd(), "static/tmp/" + f1.name)
data={} #can be anything u want to pass along with File
file1 = open(path12, 'rb')
header = {"Content-Disposition": "attachment; filename=" + f1.name, "Authorization": "JWT " + token}
res= requests.post(url,data,header)