Advanced Instaloader Examples

Here we present code examples that use the Python Module instaloader for more advanced Instagram downloading or metadata mining than what is possible with the Instaloader command line interface.

The scripts presented here can be downloaded from our source tree: instaloader/docs/codesnippets/

Download Posts in a Specific Period

To only download Instagram pictures (and metadata) that are within a specific period, you can play around with dropwhile() and takewhile() from itertools like in this snippet.

from datetime import datetime
from itertools import dropwhile, takewhile

import instaloader

L = instaloader.Instaloader()

posts = L.get_hashtag_posts('urbanphotography')
# or
# posts = instaloader.Profile.from_username(L.context, PROFILE).get_posts()

SINCE = datetime(2015, 5, 1)
UNTIL = datetime(2015, 3, 1)

for post in takewhile(lambda p: p.date > UNTIL, dropwhile(lambda p: p.date > SINCE, posts)):
    print(post.date)
    L.download_post(post, '#urbanphotography')

See also Post, Instaloader.download_post().

Discussed in issue #121.

Likes of a Profile / Ghost Followers

To obtain a list of your inactive followers, i.e. followers that did not like any of your pictures, into a file you can use this approach.

import instaloader

L = instaloader.Instaloader()

USER = 'your_account'
PROFILE = USER

# Your preferred way of logging in:
L.load_session_from_file(USER)

profile = instaloader.Profile.from_username(L.context, PROFILE)

likes = set()
print('Fetching likes of all posts of profile {}.'.format(profile.username))
for post in profile.get_posts():
    print(post)
    likes = likes | set(post.get_likes())

print('Fetching followers of profile {}.'.format(profile.username))
followers = set(profile.get_followers())

ghosts = followers - likes

print('Storing ghosts into file.')
with open('/YOUR PATH/inactive-users.txt', 'w') as f:
    for ghost in ghosts:
        print(ghost.username, file=f)

See also Profile.get_posts(), Post.get_likes(), Profile.get_followers(), Instaloader.load_session_from_file(), Profile.from_username().

Discussed in issue #120.

Track Deleted Posts

This script uses Instaloader to obtain a list of currently-online Instagram and compares it with the set of posts that you already have downloaded. It outputs a list of posts which are online but not offline (i.e. not yet downloaded) and a list of posts which are offline but not online (i.e. deleted in the profile).

from glob import glob
from sys import argv
from os import chdir

from instaloader import Instaloader, Post, Profile, load_structure_from_file

# Instaloader instantiation - you may pass additional arguments to the constructor here
L = Instaloader()

# If desired, load session previously saved with `instaloader -l USERNAME`:
#L.load_session_from_file(USERNAME)

try:
    TARGET = argv[1]
except IndexError:
    raise SystemExit("Pass profile name as argument!")

# Obtain set of posts that are on hard disk
chdir(TARGET)
offline_posts = set(filter(lambda s: isinstance(s, Post),
                           (load_structure_from_file(L.context, file)
                            for file in (glob('*.json.xz') + glob('*.json')))))

# Obtain set of posts that are currently online
post_iterator = Profile.from_username(L.context, TARGET).get_posts()
online_posts = set(post_iterator)

if online_posts - offline_posts:
    print("Not yet downloaded posts:")
    print(" ".join(str(p) for p in (online_posts - offline_posts)))

if offline_posts - online_posts:
    print("Deleted posts:")
    print(" ".join(str(p) for p in (offline_posts - online_posts)))

See also load_structure_from_file(), Profile.from_username(), Profile.get_posts(), Post.

Discussed in issue #56.

Only one Post per User

To download only the one most recent post from each user, this snippet creates a set that contains the users of which a post has already been downloaded. While iterating the posts, it checks whether the post’s owner already is in the set. If not, the post is downloaded from Instagram and the user is added to that set.

import instaloader

L = instaloader.Instaloader()

posts = L.get_hashtag_posts('urbanphotography')

users = set()

for post in posts:
    if not post.owner_profile in users:
        L.download_post(post, '#urbanphotography')
        users.add(post.owner_profile)
    else:
        print("{} from {} skipped.".format(post, post.owner_profile))

See also Post, Instaloader.download_post(), Post.owner_profile, Profile.

Discussed in issue #113.

Top X Posts of User

With Instaloader, it is easy to download the few most-liked pictres of a user.

from itertools import islice
from math import ceil

from instaloader import Instaloader, Profile

PROFILE = ...        # profile to download from
X_percentage = 10    # percentage of posts that should be downloaded

L = Instaloader()

profile = Profile.from_username(L.context, PROFILE)
posts_sorted_by_likes = sorted(profile.get_posts(),
                               key=lambda p: p.likes + p.comments,
                               reverse=True)

for post in islice(posts_sorted_by_likes, ceil(profile.mediacount * X_percentage / 100)):
    L.download_post(post, PROFILE)

Discussed in issue #194.

Upgrade Images by Local Copies

The following script finds local versions of images fetched by Instaloader, in order to upgrade the downloaded images by locally-found versions with better quality. It uses image hashing to identify similar images.

updgrade-instaloader-images.py (external link to GitHub Gist)

Discussed in issue #46.

Add Captions to Images

Instaloader does not modify the downloaded JPEG file. However, one could combine it with an imaging library such as Pillow or PIL to render the caption on Instagram pictures. The following shows an approach.

from io import BytesIO

from requests import get
from PIL import Image, ImageDraw
from instaloader import *

L = Instaloader()

# Load Post instance
post = load_structure_from_file(L.context, '2017-10-01_18-53-03_UTC.json.xz')
# or post = Post.from_shortcode(L.context, SHORTCODE)

# Render caption
image = Image.open(BytesIO(get(post.url).content))
draw = ImageDraw.Draw(image)
color = 'rgb(0, 0, 0)'  # black color
draw.text((300,100), post.caption.encode('latin1', errors='ignore'), fill=color)

# Save image
image.save('test.jpg')

See also Post.caption, Post.url, Post.from_shortcode(), load_structure_from_file().

Discussed in issue #110.

Metadata JSON Files

The JSON files Instaloader saves along with each Post contain all the metadata that has been retrieved from Instagram while downloading the picture and associated required information.

With jq, a command-line JSON processor, the metadata can be easily post-processed. For example, Instaloader’s JSON files can be pretty-formatted with:

xzcat 2018-05-13_11-18-45_UTC.json.xz | jq .node

However, Instaloader tries to do as few metadata requests as possible, so, depending on how Instaloader has been invoked, it may occur that these files do not contain the complete available metadata structure. Nevertheless, the file can be loaded into Instaloader with load_structure_from_file() and the required metadata then be accessed via the Post or Profile attributes, which trigger an Instagram request if that particular information is not present in the JSON file.

Next Section

Troubleshooting

Table of Contents