From wechat api doc:

curl -F [email protected] "http://file.api.wechat.com/cgi-bin/media/upload?access_token=ACCESS_TOKEN&type=TYPE"

Translate the command above to python:

import requests
url = 'http://file.api.wechat.com/cgi-bin/media/upload?access_token=ACCESS_TOKEN&type=TYPE'
files = {'media': open('test.jpg', 'rb')}
requests.post(url, files=files)

Doc: https://docs.python-requests.org/en/master/user/quickstart/#post-a-multipart-encoded-file

Answer from kev on Stack Overflow
🌐
Betatim
betatim.github.io › posts › python-create-multipart-formdata
TIL: Howto create multipart form data in Python - Tim Head's blog
December 12, 2021 - Once you find the answer it is surprisingly simple: encode_multipart_formdata() in urllib3. fields = { "foo": "bar", "somefile": ("somefile.txt", "contents of somefile"), "imagegfile": ("cats.png", open("cats.png").read(), "image/png"), } body, header = encode_multipart_formdata(fields)
Top answer
1 of 8
77

From wechat api doc:

curl -F [email protected] "http://file.api.wechat.com/cgi-bin/media/upload?access_token=ACCESS_TOKEN&type=TYPE"

Translate the command above to python:

import requests
url = 'http://file.api.wechat.com/cgi-bin/media/upload?access_token=ACCESS_TOKEN&type=TYPE'
files = {'media': open('test.jpg', 'rb')}
requests.post(url, files=files)

Doc: https://docs.python-requests.org/en/master/user/quickstart/#post-a-multipart-encoded-file

2 of 8
38

In case if you were to pass the image as part of JSON along with other attributes, you can use the below snippet.
client.py

import base64
import json                    

import requests

api = 'http://localhost:8080/test'
image_file = 'sample_image.png'

with open(image_file, "rb") as f:
    im_bytes = f.read()        
im_b64 = base64.b64encode(im_bytes).decode("utf8")

headers = {'Content-type': 'application/json', 'Accept': 'text/plain'}
  
payload = json.dumps({"image": im_b64, "other_key": "value"})
response = requests.post(api, data=payload, headers=headers)
try:
    data = response.json()     
    print(data)                
except requests.exceptions.RequestException:
    print(response.text)

server.py

import io
import json                    
import base64                  
import logging             
import numpy as np
from PIL import Image

from flask import Flask, request, jsonify, abort

app = Flask(__name__)          
app.logger.setLevel(logging.DEBUG)
  
  
@app.route("/test", methods=['POST'])
def test_method():         
    # print(request.json)      
    if not request.json or 'image' not in request.json: 
        abort(400)
             
    # get the base64 encoded string
    im_b64 = request.json['image']

    # convert it into bytes  
    img_bytes = base64.b64decode(im_b64.encode('utf-8'))

    # convert bytes data to PIL Image object
    img = Image.open(io.BytesIO(img_bytes))

    # PIL image object to numpy array
    img_arr = np.asarray(img)      
    print('img shape', img_arr.shape)

    # process your img_arr here    
    
    # access other keys of json
    # print(request.json['other_key'])

    result_dict = {'output': 'output_key'}
    return result_dict
  
  
def run_server_api():
    app.run(host='0.0.0.0', port=8080)
  
  
if __name__ == "__main__":     
    run_server_api()
Discussions

POST multipart-form image with python through rest API call - Stack Overflow
I am relatively new to python and enjoying every day I program in it. I have been looking around for a possible solution to figure out how to post an image in a multipart-form, binary format, with a form tag. The API I am trying to call is expecting a binary image in a form. The request payload sample I have is: ----WebkitFormBoundaryM817iTBsSwXz0iv8 Content-Disposition: form-data... More on stackoverflow.com
🌐 stackoverflow.com
How to send a "multipart/form-data" with requests in python? - Stack Overflow
Show activity on this post. How to send a multipart/form-data with requests in python? More on stackoverflow.com
🌐 stackoverflow.com
Python Request: Post Images on Facebook using Multipart/form-data - Stack Overflow
I'm using the facebook API to post images on a page, I can post image from web using this : import requests data = 'url=' + url + '&caption=' + caption + '&access_token=' + token status = More on stackoverflow.com
🌐 stackoverflow.com
May 24, 2017
Want to send a multipart/form-data including images with python requests - Stack Overflow
I want to send a multipart/form-data which contains a image with python requests. I already tried something this but it was not working properly can any suggest me something ? import requests f... More on stackoverflow.com
🌐 stackoverflow.com
March 15, 2019
🌐
JetBridge
blog.jetbridge.com › home › multipart-encoded and python requests
Multipart-Encoded and Python Requests - JetBridge Software
September 28, 2021 - The recommended header for multipart-encoded files/images is multipart/form-data and requests already set it for us automatically, using the parameter “files”. Here’s an example taken from requests documentation: >>> url = ...
🌐
Stack Overflow
stackoverflow.com › questions › 20064524 › post-multipart-form-image-with-python-through-rest-api-call
POST multipart-form image with python through rest API call - Stack Overflow
def Post_Image(urlPath, filePath, fileName): url = urlPath headers = {'content-type': 'multipart/form-data'} files = {'file':(fileName, open(filePath,'rb'))} payload = {"Content-Disposition": "form-data", "name":fileName} payload = urllib.urlencode(payload) resp = requests.post(url, data=payload, headers=headers, files= files)
Top answer
1 of 16
398

Basically, if you specify a files parameter (a dictionary), then requests will send a multipart/form-data POST instead of a application/x-www-form-urlencoded POST. You are not limited to using actual files in that dictionary, however:

>>> import requests
>>> response = requests.post('http://httpbin.org/post', files=dict(foo='bar'))
>>> response.status_code
200

and httpbin.org lets you know what headers you posted with; in response.json() we have:

>>> from pprint import pprint
>>> pprint(response.json()['headers'])
{'Accept': '*/*',
 'Accept-Encoding': 'gzip, deflate',
 'Connection': 'close',
 'Content-Length': '141',
 'Content-Type': 'multipart/form-data; '
                 'boundary=c7cbfdd911b4e720f1dd8f479c50bc7f',
 'Host': 'httpbin.org',
 'User-Agent': 'python-requests/2.21.0'}

And just to be explicit: you should not set the Content-Type header when you use the files parameter, leave this to requests because it needs to specify a (unique) boundary value in the header that matches the value used in the request body.

Better still, you can further control the filename, content type and additional headers for each part by using a tuple instead of a single string or bytes object. The tuple is expected to contain between 2 and 4 elements; the filename, the content, optionally a content type, and an optional dictionary of further headers.

I'd use the tuple form with None as the filename, so that the filename="..." parameter is dropped from the request for those parts:

>>> files = {'foo': 'bar'}
>>> print(requests.Request('POST', 'http://httpbin.org/post', files=files).prepare().body.decode('utf8'))
--bb3f05a247b43eede27a124ef8b968c5
Content-Disposition: form-data; name="foo"; filename="foo"

bar
--bb3f05a247b43eede27a124ef8b968c5--
>>> files = {'foo': (None, 'bar')}
>>> print(requests.Request('POST', 'http://httpbin.org/post', files=files).prepare().body.decode('utf8'))
--d5ca8c90a869c5ae31f70fa3ddb23c76
Content-Disposition: form-data; name="foo"

bar
--d5ca8c90a869c5ae31f70fa3ddb23c76--

files can also be a list of two-value tuples, if you need ordering and/or multiple fields with the same name:

requests.post(
    'http://requestb.in/xucj9exu',
    files=(
        ('foo', (None, 'bar')),
        ('foo', (None, 'baz')),
        ('spam', (None, 'eggs')),
    )
)

If you specify both files and data, then it depends on the value of data what will be used to create the POST body. If data is a string, only it willl be used; otherwise both data and files are used, with the elements in data listed first.

There is also the excellent requests-toolbelt project, which includes advanced Multipart support. It takes field definitions in the same format as the files parameter, but unlike requests, it defaults to not setting a filename parameter. In addition, it can stream the request from open file objects, where requests will first construct the request body in memory:

from requests_toolbelt.multipart.encoder import MultipartEncoder

mp_encoder = MultipartEncoder(
    fields={
        'foo': 'bar',
        # plain file object, no filename or mime type produces a
        # Content-Disposition header with just the part name
        'spam': ('spam.txt', open('spam.txt', 'rb'), 'text/plain'),
    }
)
r = requests.post(
    'http://httpbin.org/post',
    data=mp_encoder,  # The MultipartEncoder is posted as data, don't use files=...!
    # The MultipartEncoder provides the content-type header with the boundary:
    headers={'Content-Type': mp_encoder.content_type}
)

Fields follow the same conventions; use a tuple with between 2 and 4 elements to add a filename, part mime-type or extra headers. Unlike the files parameter, no attempt is made to find a default filename value if you don't use a tuple.

2 of 16
147

Requests has changed since some of the previous answers were written. Have a look at this Issue on Github for more details and this comment for an example.

In short, the files parameter takes a dictionary with the key being the name of the form field and the value being either a string or a 2, 3 or 4-length tuple, as described in the section POST a Multipart-Encoded File in the Requests quickstart:

>>> url = 'http://httpbin.org/post'
>>> files = {'file': ('report.xls', open('report.xls', 'rb'), 'application/vnd.ms-excel', {'Expires': '0'})}

In the above, the tuple is composed as follows:

(filename, data, content_type, headers)

If the value is just a string, the filename will be the same as the key, as in the following:

>>> files = {'obvius_session_id': '72c2b6f406cdabd578c5fd7598557c52'}

Content-Disposition: form-data; name="obvius_session_id"; filename="obvius_session_id"
Content-Type: application/octet-stream

72c2b6f406cdabd578c5fd7598557c52

If the value is a tuple and the first entry is None the filename property will not be included:

>>> files = {'obvius_session_id': (None, '72c2b6f406cdabd578c5fd7598557c52')}

Content-Disposition: form-data; name="obvius_session_id"
Content-Type: application/octet-stream

72c2b6f406cdabd578c5fd7598557c52
🌐
Franklingu
franklingu.github.io › programming › 2017 › 10 › 30 › post-multipart-form-data-using-requests
Post multipart form data using Python requests | Junchao's blog
October 30, 2017 - In [1]: data_req = Request('POST', 'https://franklingu.github.io/', data={'name ...: ': 'normal'}).prepare() In [2]: print(data_req.body) name=normal In [3]: normal_multipart_req = Request('POST', 'https://franklingu.github.io/', ...: files={'name': open('test.txt', 'r'), 'name2': 'content'}).pre ...: pare() In [4]: print(normal_multipart_req.body.decode('utf-8')) --cdf39af4e1bf449384b62fef701eda7b Content-Disposition: form-data; name="name"; filename="name" test --cdf39af4e1bf449384b62fef701eda7b Content-Disposition: form-data; name="name2"; filename="name2" content --cdf39af4e1bf449384b62fef
🌐
Gree2
gree2.github.io › python › 2016 › 03 › 30 › python-multipart-form-post-data
python multipart form post data
March 30, 2016 - # test_client.py from poster.encode import multipart_encode from poster.streaminghttp import register_openers import urllib2 # Register the streaming http handlers with urllib2 register_openers() # Start the multipart/form-data encoding of the file "DSC0001.jpg" # "image1" is the name of the parameter, which is normally set # via the "name" parameter of the HTML <input> tag.
Find elsewhere
🌐
Morioh
morioh.com › p › eaa930cc4550
Post Multipart Form Data in Python with Requests: Flask File Upload Example
In this tutorial we'll demonstrate how to upload a file from a Python server to another server by sending a POST request with multipart/form-data using the Python requests library.
Top answer
1 of 2
4

Files are supported in python3 requests module, here. This should work out for you.

import requests

url = "http://xxx"

# just set files to a list of tuples of (form_field_name, file_info)
multiple_files = [
        ('images', ('xxx.jpeg', open('xxx.jpeg', 'rb'), 'image/png')),
        ('images', ('bar.png', open('bar.png', 'rb'), 'image/png'))
]

text_data = {"key":"value"}
headers = {
    "Authorization" : "xxx",
    "Content-Type": "application/json"
}
r = requests.post(url, files=multiple_files, data=text_data, headers=headers)
r.text
2 of 2
1

I use the Python3 library urllib.request and it works perfectly for me. I also use a private key and certificate to upload files with SSL authentication. I show you how to do it in Python3 and its equivalent with the cURL command.

Bash version:

#!/bin/bash

KEY="my_key.pem"
CERT="my_cert.pem"
PASSWORD="XXXXXXX"
URL="https://put_here_your_host.com"
FILE="my_file.txt" # or .pdf, .tar.gz, etc.

curl -k --cert $CERT:$PASSWORD --key $KEY $URL -X POST -H "xxx : xxx, yyy: yyy" -T $FILE

Python3 version:

import ssl
import urllib.request

# Set global
key = 'my_key.pem'
cert = 'my_cert.pem'
password = 'XXXXXXX'
url = 'https://put_here_your_host.com'
file = 'my_file.txt' # or .pdf, .tar.gz, etc.

# Security block. You can skip this block if you do not need it.
context = ssl.create_default_context()
context.load_cert_chain(cert, keyfile=key, password=password)
opener = urllib.request.build_opener(urllib.request.HTTPSHandler(context=context))
urllib.request.install_opener(opener)

# Set request with headers.
headers = {
    'xxx' : 'xxx',
    'yyy': 'yyy'
}
request = urllib.request.Request(url, headers=headers)

# Post your file.
urllib.request.urlopen(request, open(file, 'rb').read())

I hope it helps you.

🌐
Postman
community.postman.com › help hub
Help with multipart-formdata - Python Requests code - Help Hub - Postman Community
September 24, 2020 - Hi, When I create a form-data POST request with two images, the Postman Request works. However when I select the code for Python - Requests the generated code does not work at all. It’s looking for the boundary marker…
🌐
Agiliq
agiliq.com › home › blog
Handling multipart form upload with vanilla Python - Agiliq
November 3, 2025 - We added two callbacks named on_field and on_file. python-multipart calls these callbacks while parsing multipart data. Added if/else condition to handle our two routes. Call multipart.parse_form with needed arguments. python-multipart calls on_field once it’s done parsing a non binary field. python-multipart calls on_file once it’s done parsing a file field. Instead of printing we could have used boto and uploaded the file to S3. Or we could have analysed the image.
🌐
w3resource
w3resource.com › python-exercises › urllib3 › python-urllib3-exercise-19.php
Python File Upload: Simulate POST request with multipart/Form-Data
import urllib3 # Create a PoolManager http = urllib3.PoolManager() # Specify the file and URL file_path = 'test.txt' upload_url = 'https://example.com/upload' # Prepare the multipart/form-data payload fields = { 'field1': 'value1', # Additional form fields if needed 'field2': 'value2', 'file': ('filename.txt', open(file_path, 'rb').read(), 'text/plain') } # Set the Content-Type header to multipart/form-data headers = {'Content-Type': 'multipart/form-data'} # Make the POST request response = http.request('POST', upload_url, fields=fields, headers=headers) # Receive and print the response print(response.data.decode('utf-8'))
🌐
py4u
py4u.org › blog › python-standard-library-to-post-multipart-form-data-encoded-data
How to POST Multipart/Form-Data in Python Using the Standard Library (No External Dependencies)
By following this guide, you can now send multipart/form-data requests using only Python’s standard library. While external libraries like requests simplify this process, understanding the underlying mechanics empowers you to work in environments where dependencies are restricted.
🌐
10xdev
10xdev.blog › python-requests-upload-file-post-multipart-form-data
Post Multipart Form Data in Python with Requests: Flask File Upload Example |
<!DOCTYPE html> <html> <head> <title>Upload New File</title> </head> <body> <h1>Upload Files</h1> <form action="handle_form" method="post" enctype="multipart/form-data"> <input type="file" name="file"> <input type="submit" value="Upload"> </form> </body> </html>
🌐
Stack Overflow
stackoverflow.com › questions › 71201139 › upload-files-with-python-request-with-multipart-form-data
Upload files with python request with multipart-form data - Stack Overflow
February 21, 2022 - # python with requests.session() as session: cookie = login(session, h) abs_path = (os.path.join(path, file) for file in os.listdir(path)) files = (("", open(file, 'rb'), Image.open(file).get_format_mimetype()) for file in abs_path) images = [('art_img[]', file) for file in files] response = session.post( "https://localhost/titanium/articoli/dettaglio_img.php?id_art=4129", files=images, data={'salva_img': "Salva immagine"} ) print(response.status_code) print(response.text) python · request · multipartform-data ·
🌐
YouTube
youtube.com › watch
python requests post file multipart form data - YouTube
Instantly Download or Run the code at https://codegive.com title: uploading files with python requests using multipart form dataintroduction:in this tutoria...
Published   February 23, 2024