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 OverflowFrom 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
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()
POST multipart-form image with python through rest API call - Stack Overflow
How to send a "multipart/form-data" with requests in python? - Stack Overflow
Python Request: Post Images on Facebook using Multipart/form-data - Stack Overflow
Want to send a multipart/form-data including images with python requests - Stack Overflow
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.
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
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
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.
try with this
import requests
headers = {
'Content-Type': 'multipart/form-data',
'x-api-key': 'xxxxxx-xxxxx-xxxx-xxxx-xxxxxxxx',
}
files = {
'file': ('<image>.jpg', open('<image>.jpg', 'rb')),
}
response = requests.post('http://localhost:8000/api/v1/recognition/recognize', headers=headers, files=files)
I made it work with this code:
import requests
url = "http://10.0.38.119:8000/api/v1/recognition/recognize"
payload = {}
files = [('file', ('<image>.jpg', open('<image>.jpg', 'rb'), 'image/jpeg'))]
headers = {
'x-api-key': 'xxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxx'
}
response = requests.request("POST", url, headers=headers, data=payload, files=files)
print(response.text)
Adding this reply if anyone needs it for future.
Please find the below code for sending image file in Python requests. Here logo is the keyword for an image file, which one of our servers accepts as an input. Hence 'logo' is given. Also, make sure you remove 'Content-type' from the headers.
response = requests.post(url,data=data,headers=headers, files={'logo':open("your_image_file.jpeg",'rb')})
I have found the solution, it is quite easy:
data = {'upload': ''}
I needed to pass the upload string in that way and voilà!