如何使用 python 请求上传文件?

2024-12-11 08:47:00
admin
原创
161
摘要:问题描述:我正在使用 Python 请求库执行一个简单的文件上传任务。我搜索了 Stack Overflow,似乎没有人遇到同样的问题,即服务器未收到该文件:import requests url='http://nesssi.cacr.caltech.edu/cgi-bin/getmulticonedb_r...

问题描述:

我正在使用 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.

只有文件为空时才会出现。所以我不知道如何成功发送我的文件。我知道这个文件有效,因为如果我访问这个网站并手动填写表格,它会返回一个匹配对象的列表,这正是我想要的。我非常感谢所有的提示。

其他一些相关的线程(但没有回答我的问题):


解决方案 1:

如果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(不指定其他字段),则不要使用参数,只需将文件直接发布为data。然后您可能还想设置Content-Type标题,否则将不设置任何标题。请参阅Python 请求 - 从文件发布数据。

解决方案 2:

新的 Python 请求库简化了这个过程,我们可以使用“files”变量来表示我们想要上传一个多部分编码的文件:

url = 'http://httpbin.org/post'
files = {'file': open('report.xls', 'rb')}

r = requests.post(url, files=files)
r.text

解决方案 3:

客户端上传

如果您想使用 Pythonrequests库上传单个文件,那么请求库支持流式上传,这允许您发送大文件或流而无需读入内存

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 表单数据解析,如针对“大文件上传占用内存”问题的修复程序中所述,以避免在大文件上传时低效使用内存(st 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

解决方案 4:

您可以通过 post api 发送任何文件,调用 API 时只需提及 files={'any_key': fobj}

import requests
import json
    
url = "https://request-url.com"
 
headers = {"Content-Type": "application/json; charset=utf-8"}
    
with open(filepath, 'rb') as fobj:
    response = requests.post(url, headers=headers, files={'file': fobj})
 
print("Status Code", response.status_code)
print("JSON Response ", response.json())

解决方案 5:

@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 另一端的接收 Web 服务器),我必须使用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=会成为请求用户的习惯。

解决方案 6:

上传:

with open('file.txt', 'rb') as f:
    files = {'upload_file': f.read()}
    
values = {'DB': 'photcat', 'OUT': 'csv', 'SHORT': 'short'}

r = requests.post(url, files=files, data=values)

下载(Django):

with open('file.txt', 'wb') as f:
    f.write(request.FILES['upload_file'].file.read())

解决方案 7:

关于迄今为止给出的答案,总是缺少一些东西阻止它对我来说发挥作用(尽管答案中的所有提示都很有帮助)。 因此,让我从自己的实验中总结出最终对我有用的方法:

import json
import os
import requests

API_ENDPOINT = "http://localhost:80"
access_token = "sdfJHKsdfjJKHKJsdfJKHJKysdfJKHsdfJKHs"  # TODO: get fresh Token here


def upload_engagement_file(filepath):
 
    url = API_ENDPOINT + "/api/files"  # add any URL parameters if needed
    hdr = {"Authorization": "Bearer %s" % access_token}
    with open(filepath, "rb") as fobj:
        file_obj = fobj.read()
        file_basename = os.path.basename(filepath)
        file_to_upload = {"file": (str(file_basename), file_obj)}
        finfo = {"fullPath": filepath}
        upload_response = requests.post(url, headers=hdr, files=file_to_upload, data=finfo)
        fobj.close()
    # print("Status Code ", upload_response.status_code)
    # print("JSON Response ", upload_response.json())
    return upload_response

注意requests.post(...)需要

  • 一个url参数,包含你正在调用的 API 端点的完整 URL,使用API_ENDPOINT,假设我们有一个http://localhost:8000/api/files端点来发布文件

  • 一个headers参数,至少包含授权(承载令牌)

  • 一个files参数,包含文件的名称和整个文件内容

  • data仅采用路径和文件名的参数

所需安装(控制台):

pip 安装请求

函数调用返回的是一个响应对象,其中包含状态代码以及 JSON 格式的完整错误消息。末尾注释的打印语句upload_engagement_file向您展示了如何访问它们。

注意:有关请求库的一些有用的附加信息可在此处找到。如果您想了解有关 Python 的更多信息(更多一般信息),请查看此处。

解决方案 8:

有些可能需要通过 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 请求变得容易得多,但它的一些魔力和便利性掩盖了如何制作更细致的请求。

解决方案 9:

在 Ubuntu 中你可以这样应用,

将文件保存在某个位置(临时),然后打开并发送到 API

      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)
相关推荐
  政府信创国产化的10大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   1565  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1354  
  信创国产芯片作为信息技术创新的核心领域,对于推动国家自主可控生态建设具有至关重要的意义。在全球科技竞争日益激烈的背景下,实现信息技术的自主可控,摆脱对国外技术的依赖,已成为保障国家信息安全和产业可持续发展的关键。国产芯片作为信创产业的基石,其发展水平直接影响着整个信创生态的构建与完善。通过不断提升国产芯片的技术实力、产...
国产信创系统   21  
  信创生态建设旨在实现信息技术领域的自主创新和安全可控,涵盖了从硬件到软件的全产业链。随着数字化转型的加速,信创生态建设的重要性日益凸显,它不仅关乎国家的信息安全,更是推动产业升级和经济高质量发展的关键力量。然而,在推进信创生态建设的过程中,面临着诸多复杂且严峻的挑战,需要深入剖析并寻找切实可行的解决方案。技术创新难题技...
信创操作系统   27  
  信创产业作为国家信息技术创新发展的重要领域,对于保障国家信息安全、推动产业升级具有关键意义。而国产芯片作为信创产业的核心基石,其研发进展备受关注。在信创国产芯片的研发征程中,面临着诸多复杂且艰巨的难点,这些难点犹如一道道关卡,阻碍着国产芯片的快速发展。然而,科研人员和相关企业并未退缩,积极探索并提出了一系列切实可行的解...
国产化替代产品目录   28  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用