Skip to content

Instantly share code, notes, and snippets.

Last active May 30, 2018 13:45
What would you like to do?
Upload a Photoset to Tumblr using the Python Requests library (
# Adapted from:
import requests_oauthlib
import requests
import os.path
from mimetypes import guess_type
class SimpleTumblrClient(object):
def __init__(self, consumer_key, consumer_secret, token, token_secret):
self._oauth = requests_oauthlib.OAuth1(consumer_key, consumer_secret, token, token_secret)
def new_multipart_post(self, hostname, parameters={}, data_files=None):
hostname: the full domain name for the blog you wish to post on, e.g.
'', rather than 'example' or ''
parameters: a dictionary containing all desired post parameters, EXCEPT
data_files: the result of handing a list of image URIs (local or web) to
full_url = "{}/post".format(hostname)
# prepare the initial request without the binary data
req = requests.Request(method="POST", url=full_url, data=parameters, auth=self._oauth)
prep = req.prepare()
# grab the computed auth data
headers = {'Authorization': prep.headers['Authorization']}
# combine the parameters, the computed auth data, and the binary files into a new request
req = requests.Request(method="POST", url=full_url, data=parameters, headers=headers, files=data_files)
prep = req.prepare()
# send the combined request
s = requests.Session()
r = s.send(prep)
# check whether it succeeded
if r.status_code != 201:
print("Post request failed with status code {}".format(r.status_code))
print("Posted successfully.")
def encode_media(media_list):
encode_photos takes a list of photo URIs, either local or on the web,
and returns a dictionary of image data suitable for Requests
can also take a list containing one video or audio URI (adding more will
probably break the request)
media = {}
if media_list == None:
return None
if len(media_list) > 1:
pattern = 'data[{}]'
pattern = 'data'
for i in range(len(media_list)):
media_uri = media_list[i]
if os.path.isfile(media_uri):
_, filename = media_uri.rsplit(os.path.sep, 1)
media.update({pattern.format(i): (filename, open(media_uri, mode='rb'), detect_mimetype(filename))})
else: # assume this is a web url
_, filename = media_uri.rsplit('/', 1)
r = requests.get(media_uri)
media.update({pattern.format(i): (filename, r.content, detect_mimetype(filename))})
return media
def detect_mimetype(uri):
Tries to guess the mimetype based on filename extension. If the extension
is unknown, or does not exist, returns None
return guess_type(uri)[0]
if __name__ == '__main__':
# enter the host name of the blog you wish to post to here
base_hostname = ""
params = {"type": "photo", "tags": "your, tags", \
"more params": "see"}
# to upload a non-media posts, just set this to None, or delete it from the call below
# to upload a video or audio file, set its URI as the only list item
# local video uploads work, have yet to test audio or remote video
# obviously you need to set the correct params too
media_file_list = ["list photo uris here",\
files = encode_media(media_file_list)
client = SimpleTumblrClient(consumer_key="", consumer_secret="", token="", token_secret="")
client.new_multipart_post(base_hostname, params, files)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment