python请求文件上传

sci*_*ris 93 python file-upload file python-requests

我正在执行一个使用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)
Run Code Online (Sandbox Code Playgroud)

我正在用我的文件名填充'upload_file'关键字的值,因为如果我把它留空,它会说

Error - You must select a file to upload!
Run Code Online (Sandbox Code Playgroud)

现在我明白了

File  file.txt  of size    bytes is  uploaded successfully!
Query service results:  There were 0 lines.
Run Code Online (Sandbox Code Playgroud)

仅当文件为空时才会出现.所以我不知道如何成功发送我的文件.我知道该文件有效,因为如果我去这个网站并手动填写表格,它会返回一个很好的匹配对象列表,这就是我所追求的.我非常感谢所有提示.

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

Mar*_*ers 177

如果upload_file是文件,请使用:

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

r = requests.post(url, files=files, data=values)
Run Code Online (Sandbox Code Playgroud)

并且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--
Run Code Online (Sandbox Code Playgroud)

注意filename="file.txt"参数.

files如果需要更多控制,可以使用元组作为映射值,使用2到4个元素.第一个元素是文件名,后跟内容,可选的content-type头值和附加头的可选映射:

files = {'upload_file': ('foobar.txt', open('file.txt','rb'), 'text/x-spam')}
Run Code Online (Sandbox Code Playgroud)

这将设置备用文件名和内容类型,省略可选标头.

如果你的意思是要从文件中取出整个POST主体(没有指定其他字段),那么不要使用该files参数,只需将文件直接发布为data.然后您可能也想要设置Content-Type标题,否则将不设置任何标题.

  • @William:你也可以使用一系列2值元组,它可以让你重复使用字段名:`files = [('attachment',open('attachment1.txt','rb')),('attachment) ',打开('attachment2.txt','rb'))]`.每个元组都是一对键和值. (4认同)
  • @MartijnPieters 这不会有泄露文件的风险吗?`requests` 会关闭它吗? (3认同)
  • @MattMessersmith:不,它没有关闭。如果要关闭文件,则将`with open(...)用作fobj:`并在`files`映射中使用`fobj`。 (3认同)
  • 您也可以使用`files = {'file':('nameoffile',open('namoffile','rb'),'Content-Type':'text / html','other header'),'file2' :('nameoffile2',open('nameoffile2','rb'),'Content-Type':'application / xml','other header')}`但是如果使用files = {},则headers = {'Content -Type':'blah blah'}不能使用!-&gt; @ martijn-pieters:因为multipart / form-data Content-Type必须包含用于在帖子主体中定义零件的边界值。不设置Content-Type标头可确保请求将其设置为正确的值。 (2认同)

lay*_*cat 24

(2018)新的python请求库简化了这个过程,我们可以使用'files'变量来表示我们要上传一个多部分编码的文件

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

r = requests.post(url, files=files)
r.text
Run Code Online (Sandbox Code Playgroud)

  • requests库会自动关闭文件吗? (7认同)
  • 使用“lsof”,文件似乎保持打开状态,或者至少,这就是我解释以下结果的方式。在运行“open”之前,“lsof”表中没有关于“filename”的记录。然后执行“open”后,会出现多条具有“read”访问权限的记录。执行“requests.post”后,记录仍然存在,表明文件没有关闭。 (2认同)
  • (2021) 如果上传文件时还需要参数,可以添加 `params`,如下所示: `r = requests.post(url,files=files,params={"key":value})` (2认同)

gih*_*uka 15

客户好评

如果要使用Python requests库上传单个文件,则请求lib 支持流上传,这使您无需读取内存即可发送大文件或流。

with open('massive-body', 'rb') as f:
    requests.post('http://some.url/streamed', data=f)
Run Code Online (Sandbox Code Playgroud)

服务器端

然后将文件存储在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
Run Code Online (Sandbox Code Playgroud)

或使用修复程序中提到的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
Run Code Online (Sandbox Code Playgroud)


Har*_*ore 8

您可以在调用 API 时通过 post 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())
Run Code Online (Sandbox Code Playgroud)