Skip to content

Instantly share code, notes, and snippets.

Last active May 29, 2021 19:02
Show Gist options
  • Save mayo/90a02222fe6a2826044572d7e8192551 to your computer and use it in GitHub Desktop.
Save mayo/90a02222fe6a2826044572d7e8192551 to your computer and use it in GitHub Desktop.
Import instagram data into a static site (Jekyll, Hugo, Hana, Metalsmith, etc)
import codecs
from datetime import datetime
import json
import os
import posixpath
import re
import shutil
import sys
# This script will import your instagram photos to your static site. It should work for most, assuming you customize the POST_TEMPLATE to match what your site uses.
# Things to note:
# * multi-photo posts will be imported as standalone photos with no caption (that's how Instagram exports them)
# * hashtags get removed from posts, unless you set REMOVE_HASH_TAGS to False.
# * multiline instagram posts are not handled gracefully if you're using the default POST_TEMPLATE (instagram image caption doesn't work with new lines)
# Configuration parameters START
# All of these paths will be strftime formatted with capture time
#BLOG_PATH = "content/blog/%Y/%m"
BLOG_PATH = "_posts"
#MEDIA_PATH = "content/media/images/photos/%Y/%m"
MEDIA_PATH = "assets/img/photos"
#MEDIA_URL = "/media/images/photos/%Y/%m"
MEDIA_URL = "/assets/img/photos"
# BLOG_POST_FILE_TEMPLATE will be formatted with parameters: capture_time, stub
BLOG_POST_FILE_TEMPLATE = "{capture_time:%Y}-{capture_time:%m}-{capture_time:%d}-{slug:s}.md"
# POST_TEMPLATE will be formatted with post_time, caption, and photo_file parameters. Photo file is full path derived from MEDIA_URL
#type: photo
#imported: "instagram"
#created: !!timestamp '{post_time:%Y-%m-%d %H:%M:%S}'
# - microblog
layout: post
title: "{caption:s}"
date: {post_time:%Y-%m-%d %H:%M}
imported: instagram
# Configuration parameters END
if len(sys.argv) < 2:
print 'First parameter has to be path to directory with Instagram data'
instagram_data = sys.argv[1]
media_file = os.path.join(instagram_data, 'media.json')
data = {}
if not os.path.exists(instagram_data) or not os.path.exists(media_file):
print """Directory "{:s}" doesn't exist or is missing media.json file"""
with open(media_file) as fd:
data = json.load(fd)
photos = data.get('photos', [])
for photo in photos:
caption = re.sub(r'#[^\n\s]+', '', photo['caption']).strip()
# Encode everything as UTF-8
caption = codecs.encode(caption, 'utf-8')
capture_time = datetime.strptime(photo['taken_at'], "%Y-%m-%dT%H:%M:%S")
instagram_photo_path = os.path.join(instagram_data, photo['path'])
# If the image file is not there, move on. If you don't want to import certain images, just delete them first.
if not os.path.exists(instagram_photo_path):
blog_path = datetime.strftime(capture_time, BLOG_PATH)
media_path = datetime.strftime(capture_time, MEDIA_PATH)
media_url = datetime.strftime(capture_time, MEDIA_URL)
photo_file = os.path.basename(instagram_photo_path)
post = POST_TEMPLATE.format(
photo_path=posixpath.join(media_url, photo_file)
post_file = None
if caption:
slug = re.sub(r"[^a-z0-9 ]", '', caption.lower()).strip()
slug = re.sub(r" (the|a|an) ", ' ', slug).strip()
slug = re.sub(r"\s+", ' ', slug).strip()
slug = "-".join(slug.split()[0:3])
post_file = BLOG_POST_FILE_TEMPLATE.format(
# If the filename derived from caption exists, don't use it
if os.path.exists(os.path.join(blog_path, post_file)):
post_file = None
if not post_file:
post_file = BLOG_POST_FILE_TEMPLATE.format(
post_path = os.path.join(blog_path, post_file)
except OSError as err:
# Ignore "directory exists" errors
if err.errno != 17:
with open(post_path, 'w') as fd:
shutil.copy(instagram_photo_path, media_path)
Copy link

This has been really helpful. Not sure if you are still using this but wondered if you could extend it slightly.

It would be great if the location of the photo could be added to the post template as well as any of the #tags that you strip out as a tag array?

I’m completely new to python and did attempt to make some changes but couldn’t get it to work.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment