Как загрузить файл с multipart / form POST, имеющий только URL-адрес файла, который нужно загрузить (куски) [дубликат]
На этот вопрос уже есть ответ здесь:
Есть ли шанс загрузить файл через конечную точку API, которая принимает multipart / form-data в качестве типа контента, имеющего только URL этого файла?
Правило: Загрузить весь файл в память, а затем загрузить с помощью этой конечной точки невозможно (Нет никакой гарантии, что коробка когда-либо будет достаточно большой, чтобы вместить временный файл).
Вопрос: Я хочу передавать файл кусками с одного сервера (GET) на другой (multipart/form-data POST). Возможно ли это? Как этого добиться?
Поток: file_server сервер загрузки
Вот простой пример загрузки в память (ОЗУ) опции (но это противоречит правилу):
from io import BytesIO
import requests
from requests_toolbelt.multipart.encoder import MultipartEncoder
file_url = 'https://www.sysaid.com/wp-content/uploads/features/itam/image-banner-asset.png'
requested_file_response = requests.get(file_url, stream=True)
TOKEN_PAYLOAD = {
'grant_type': 'password',
'client_id': '#########',
'client_secret': '#########',
'username': '#########',
'password': '#########'
}
def get_token():
response = requests.post(
'https://upload_server/oauth/token',
params=TOKEN_PAYLOAD)
response_data = response.json()
token = response_data.get('access_token')
if not token:
print("token error!")
return token
token = get_token()
file_object = BytesIO()
file_object.write(requested_file_response.content)
# Form conctent
multipart_data = MultipartEncoder(
fields={
'--': (
'test.png',
file_object # AttributeError: 'generator' object has no attribute 'encode' when I try to pass generator here.
),
'id': '2217',
'fileFieldDefId': '4258',
}
)
# Create headers
headers = {
"Authorization": "Bearer {}".format(token),
'Content-Type': multipart_data.content_type
}
session = requests.Session()
response = session.post(
'https://upload_server/multipartUpdate',
headers=headers,
data=multipart_data,
)
Ответ находится в файле, похожем на создание объекта для потока цели
Большое Спасибо за любую помощь. Ура!
1 ответ:
Если я читаю requests_toolbelt исходный код справа, то это требует не только способности
.read()
файла (который мы могли бы получить просто передавrequests.get(..., stream=True).raw
), но и того, что есть некоторый способ определить, сколько данных осталось в потоке.Предполагая, что вы уверены, что у вас всегда есть допустимый Заголовок
content-length
, я бы предложил следующее решение:import requests from requests_toolbelt.multipart.encoder import MultipartEncoder file_url = 'https://www.sysaid.com/wp-content/uploads/features/itam/image-banner-asset.png' target = 'http://localhost:5000/test' class PinocchioFile: """I wish I was a real file""" def __init__(self, url): self.req = requests.get(url, stream=True) length = self.req.headers.get('content-length') self.len = None if length is None else int(length) self._raw = self.req.raw def read(self, chunk_size): chunk = self._raw.read(chunk_size) or b'' self.len -= len(chunk) if not chunk: self.len = 0 return chunk multipart_data = MultipartEncoder( fields={ '--': ( 'test.png', PinocchioFile(file_url), ), 'id': '2217', 'fileFieldDefId': '4258', } ) # Create headers headers = { 'Content-Type': multipart_data.content_type } response = requests.post( target, data=multipart_data, headers=headers, )