How to Send Multipart/Form-Data Requests in Python with requests
Sending data using multipart/form-data
encoding is essential for file uploads and submitting complex forms via HTTP POST requests.
This guide explores how to send multipart/form-data
requests using the popular requests
library in Python, covering scenarios with and without file uploads, and introducing the requests-toolbelt
for more advanced control.
Sending Multipart/Form-Data with the files
Parameter
The requests
library automatically uses multipart/form-data
encoding when you provide the files
argument to requests.post()
.
Sending Data Without Actual Files
You can use the files
parameter even if you're not uploading files. This forces the Content-Type
header to multipart/form-data
.
import requests
from pprint import pprint
url = 'https://httpbin.org/post'
response = requests.post(
url,
files={'id': '1', 'site': 'tutorialreference.com'}, # Use files param for multipart
timeout=30
)
print(f"Status Code: {response.status_code}")
if response.ok:
# Print headers to verify Content-Type
pprint(response.json().get('headers'))
Output:
Status Code: 200
{'Accept': '*/*',
'Accept-Encoding': 'gzip, deflate',
'Content-Length': '...',
'Content-Type': 'multipart/form-data; boundary=...', # Correct header
'Host': 'httpbin.org', ... }
- The
files
parameter can be used to send any data using multipart/form-data encoding.
Do not manually set the Content-Type
header when using the files
parameter. requests
handles setting the correct Content-Type
including the necessary boundary
parameter.
Sending Files
To upload a file, provide a file object opened in binary read mode ('rb'
) within the files
dictionary:
import requests
url = 'https://httpbin.org/post'
try:
# Assume 'data.json' exists in the same directory
with open('data.json', 'rb') as f:
files_to_upload = {'file': f}
response = requests.post(url, files=files_to_upload, timeout=30)
print(response.text)
print(f"Status Code: {response.status_code}")
except FileNotFoundError:
print("Error: data.json not found.")
except requests.exceptions.RequestException as e:
print(f"Request failed: {e}")
Explicitly Setting Filename, Content-Type, and Headers
For more control over file uploads, you can provide a tuple as the value in the files
dictionary. The tuple format allows specifying (filename, file_object, content_type, custom_headers)
.
import requests
url = 'https://httpbin.org/post'
try:
# Assume 'example.xlsx' exists
with open('example.xlsx', 'rb') as f:
files_spec = {
'file': (
'custom_filename.xlsx', # Custom filename
f, # File object
'application/vnd.ms-excel', # Specific Content-Type
{'Expires': '0'} # Custom headers
)
}
response = requests.post(url, files=files_spec, timeout=30)
print(response.text)
print(f"Status Code: {response.status_code}")
except FileNotFoundError:
print("Error: example.xlsx not found.")
except requests.exceptions.RequestException as e:
print(f"Request failed: {e}")
- Plain Text Fields: To send regular form fields alongside files using the
files
parameter structure, set the filename part of the tuple toNone
:files_with_text = {
'session_id': (None, 'some_session_value'), # Plain text field
'upload': ('report.txt', open('report.txt', 'rb')) # File field
}
# response = requests.post(url, files=files_with_text) - String as File Content: You can also provide a string directly as the file content:
files_string_content = {
'file': (
'example.csv',
'some,data,to,send\nanother,row,to,send\n' # String content
)
}
# response = requests.post(url, files=files_string_content)
Sending Multipart/Form-Data with requests-toolbelt
The requests-toolbelt
library offers the MultipartEncoder
for more complex scenarios and streaming uploads.
Installing requests-toolbelt
pip install requests-toolbelt
# or with pip3
pip3 install requests-toolbelt
Using MultipartEncoder
import requests
from requests_toolbelt.multipart.encoder import MultipartEncoder
url = 'https://httpbin.org/post'
try:
# Assume 'example.xlsx' exists
with open('example.xlsx', 'rb') as f:
multipart_data = MultipartEncoder(
fields={
# Plain text fields
'field1': 'value1',
'field2': 'value2',
# File upload field (filename, file_object, content_type)
'file': ('custom_name.xlsx', f, 'application/vnd.ms-excel')
}
)
response = requests.post(
url,
data=multipart_data, # Pass encoder to 'data'
headers={'Content-Type': multipart_data.content_type}, # Set header from encoder
timeout=30
)
print(response.text)
print(f"Status Code: {response.status_code}")
except FileNotFoundError:
print("Error: example.xlsx not found.")
except requests.exceptions.RequestException as e:
print(f"Request failed: {e}")
- Create a
MultipartEncoder
instance, defining fields with their names, values, and optional content types. - Pass the
MultipartEncoder
object to thedata
parameter ofrequests.post()
. - Crucially, set the
Content-Type
header usingmultipart_data.content_type
.
Conclusion
This guide demonstrated how to send multipart/form-data
requests using Python's requests
library.
You learned the primary method using the files
parameter for both simple data and file uploads, how to customize file details using tuples, and how to use the requests-toolbelt
library for more advanced multipart encoding. Choosing the right method depends on the complexity of the data and files you need to send.