Загрузка нескольких файлов в одном запросе с использованием модуля запросов python

Модуль Python requests предоставляет хорошую документацию о том, как загрузить один файл в одном запросе. :

 files = {'file': open('report.xls', 'rb')}

Я попытался расширить этот пример, используя этот код, пытаясь загрузить несколько файлов:

 files = {'file': [open('report.xls', 'rb'), open('report2.xls, 'rb')]}

но это привело к этой ошибке:

 File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/urllib.py",      line 1052, in splittype
 match = _typeprog.match(url)
 TypeError: expected string or buffer

Можно ли с помощью этого модуля загрузить список файлов одним запросом и как?


person user462455    schedule 12.08.2013    source источник
comment
почему не было принятого ответа? Недостаточно ли ответа с высоким рейтингом ниже?   -  person Wade Anderson    schedule 29.10.2014
comment
Пинг/бампинг. Достаточно ли одного из этих ответов?   -  person Wayne Werner    schedule 13.05.2016


Ответы (8)


Чтобы загрузить список файлов с одинаковым значением ключа в одном запросе, вы можете создать список кортежей с первым элементом в каждом кортеже в качестве значения ключа и файловым объектом в качестве второго:

files = [('file', open('report.xls', 'rb')), ('file', open('report2.xls', 'rb'))]
person Ryan Fau    schedule 25.12.2013
comment
Допустим, у меня есть список имен файлов, есть ли способ сделать это с пониманием списка? - person Maciek Semik; 22.03.2019
comment
@MatthewSemik file_names = [abc.txt, pqr.txt] files = [('file', open(f, 'rb')) for f в file_names] - person Swapnil Suryawanshi; 10.12.2019
comment
Спасибо, отлично сработало для меня - person Mohit Duklan; 03.06.2021

Можно загрузить несколько файлов с разными значениями ключа, добавив несколько записей в словарь:

files = {'file1': open('report.xls', 'rb'), 'file2': open('otherthing.txt', 'rb')}
r = requests.post('http://httpbin.org/post', files=files)
person Lukasa    schedule 12.08.2013
comment
Интересно. Попробую ваш подход. Причина, по которой я попробовал список, заключалась в том, что Flask (веб-фреймворк Python) говорит, что файлы являются мультидиктом, и способ доступа ко всем загружаемым файлам: request.files.getall('file') - person user462455; 12.08.2013
comment
Нужно ли мне закрывать файловые дескрипторы самостоятельно? или они будут автоматически закрыты, как с open('file', 'r') as f..? - person kaki gadol; 30.10.2019
comment
@Lukasa, есть ли аналогичный подход к решению в R? - person user5249203; 25.03.2021

документация содержит четкий ответ .

Цитата:

Вы можете отправить несколько файлов в одном запросе. Например, предположим, что вы хотите загрузить файлы изображений в HTML-форму с несколькими полями файла «изображения»:

Для этого просто установите файлы в список кортежей (form_field_name, file_info):

url = 'http://httpbin.org/post'
multiple_files = [('images', ('foo.png', open('foo.png', 'rb'), 'image/png')),
                      ('images', ('bar.png', open('bar.png', 'rb'), 'image/png'))]
r = requests.post(url, files=multiple_files)
r.text

# {
#  ...
#  'files': {'images': 'data:image/png;base64,iVBORw ....'}
#  'Content-Type': 'multipart/form-data; boundary=3131623adb2043caaeb5538cc7aa0b3a',
#  ...
# }
person Wade Anderson    schedule 29.10.2014
comment
Какую форму может принимать file_info? Могу ли я опустить тип содержимого? Что еще может быть частью file_info? документация не вдается в подробности. - person A.R.; 29.01.2015
comment
@AmauryRodriguez Я рекомендую вам посмотреть все эти подробности в источнике. - person Wade Anderson; 28.10.2015

Вам нужно создать список файлов для загрузки нескольких изображений:

file_list = [  
       ('Key_here', ('file_name1.jpg', open('file_path1.jpg', 'rb'), 'image/png')),
       ('key_here', ('file_name2.jpg', open('file_path2.jpg', 'rb'), 'image/png'))
   ]

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

Если вы хотите отправлять файлы с одним и тем же ключом, вам нужно сохранить один и тот же ключ для каждого элемента, а для другого ключа просто измените ключи.

Источник: https://stackabuse.com/the-python-requests-module/

person Abdul Haseeb    schedule 23.04.2019

Я немного запутался, но напрямую открывать файл в запросе (впрочем, то же самое написано в официальном руководстве по запросам) не так уж и "безопасно".

Просто попробуй:

import os
import requests
file_path = "/home/user_folder/somefile.txt"
files = {'somefile': open(file_path, 'rb')}
r = requests.post('http://httpbin.org/post', files=files)

Да, все будет хорошо, но:

os.rename(file_path, file_path)

И вы получите:

PermissionError:The process cannot access the file because it is being used by another process

Пожалуйста, поправьте меня, если я не прав, но кажется, что файл все еще открыт, и я не знаю, как его закрыть.

Вместо этого я использую:

import os
import requests
#let it be folder with files to upload
folder = "/home/user_folder/"
#dict for files
upload_list = []
for files in os.listdir(folder):
    with open("{folder}{name}".format(folder=folder, name=files), "rb") as data:
        upload_list.append(files, data.read())
r = request.post("https://httpbin.org/post", files=upload_list)
#trying to rename uploaded files now
for files in os.listdir(folder):
    os.rename("{folder}{name}".format(folder=folder, name=files), "{folder}{name}".format(folder=folder, name=files))

Теперь мы не получаем ошибок, поэтому я рекомендую использовать этот способ для загрузки нескольких файлов, иначе вы можете получить некоторые ошибки. Надеюсь, этот ответ поможет кому-нибудь и сэкономит бесценное время.

person Mike Mint    schedule 29.06.2019
comment
Я не думаю, что то, что вы пытаетесь сделать, сработает, потому что указатели файлов уже будут закрыты, до того, как они будут использованы requests.post. Поэтому у нас остается возможность иметь открытые указатели. Мы можем, я думаю, поместить указатели в переменные, и после того, как они будут использованы, закрыть их ИЛИ иметь параллельные открытия, опубликовать внутри блока with. Указатели будут автоматически закрыты. - person Mooncrater; 06.07.2020

Если у вас есть несколько файлов в списке python, вы можете использовать eval() в понимании, чтобы перебрать файлы в параметре файлов запросов.

file_list = ['001.jpg', '002.jpg', '003.jpg']
files=[eval(f'("inline", open("{file}", "rb"))') for file in file_list ]

requests.post(
        url=url,
        files=files
)
person joshhu    schedule 05.09.2019

В моем случае загрузка всех изображений, находящихся внутри папки, просто добавление ключа с индексом

напр. ключ = 'изображения', например. 'images[0]' в цикле

 photosDir = 'allImages'
 def getFilesList(self):
        listOfDir = os.listdir(os.path.join(os.getcwd()+photosDir))
        setOfImg = []
        for key,row in enumerate(listOfDir):
            print(os.getcwd()+photosDir+str(row) , 'Image Path')
            setOfImg.append((
                'images['+str(key)+']',(row,open(os.path.join(os.getcwd()+photosDir+'/'+str(row)),'rb'),'image/jpg')
            ))
        print(setOfImg)
        return  setOfImg
person Shamim    schedule 15.12.2020

Если у вас есть файлы из формы и вы хотите переслать их на другой URL или в API. Вот пример с несколькими файлами и другими данными формы для пересылки на другой URL.

images = request.files.getlist('images')
files = []
for image in images:
    files.append(("images", (image.filename, image.read(), image.content_type)))
r = requests.post(url="http://example.com/post", data={"formdata1": "strvalue", "formdata2": "strvalue2"}, files=files)
person Gopal Singh Sirvi    schedule 06.05.2021