Instaloader
Overview
Sección titulada «Overview»Instaloader is a Python tool for downloading Instagram profiles, posts, stories, and reels while preserving metadata. It’s designed for OSINT research, academic purposes, and understanding Instagram’s data structures. The tool operates through public Instagram APIs and respects terms of service when used appropriately.
Installation
Sección titulada «Installation»Linux (Debian/Ubuntu)
Sección titulada «Linux (Debian/Ubuntu)»sudo apt-get update
sudo apt-get install python3 python3-pip
pip3 install instaloader
brew install python3
pip3 install instaloader
Windows
Sección titulada «Windows»# Python 3.6+ required
python -m pip install instaloader
FROM python:3.11-slim
RUN pip install instaloader
ENTRYPOINT ["instaloader"]
Build from Source
Sección titulada «Build from Source»git clone https://github.com/instaloader/instaloader.git
cd instaloader
python3 -m pip install -e .
Verify Installation
Sección titulada «Verify Installation»instaloader --version
instaloader -h
Basic Usage
Sección titulada «Basic Usage»| Command | Description |
|---|---|
instaloader profile_name | Download profile |
instaloader --login username | Login with username |
instaloader --stories profile_name | Download stories |
instaloader --igtv profile_name | Download IGTV/reels |
instaloader "#hashtag" | Download hashtag posts |
instaloader @username | Download profile by handle |
Command-Line Options
Sección titulada «Command-Line Options»Profile Options
Sección titulada «Profile Options»--profile-pic Download profile picture
--stories Download stories
--highlights Download story highlights
--tagged Download tagged photos
--igtv Download IGTV/reels
--no-videos Skip video files
--no-captions Skip captions
--no-metadata-json Don't save JSON metadata
Authentication
Sección titulada «Authentication»--login USERNAME Login with username
--password PASSWORD Provide password (not recommended)
--session FILE Use saved session file
--load-cookies FILE Load cookies from file
--save-cookies FILE Save cookies for reuse
Download Filtering
Sección titulada «Download Filtering»-C, --count Maximum posts to download
--latest-stamps FILE Only posts newer than timestamp
--post-filter Python expression for filtering
--skip-posts Skip posts
--geotags Download geotag data
Output Options
Sección titulada «Output Options»-d, --dirname Custom output directory
-f, --filename Custom filename format
--flat-out Flat directory structure
--no-profile-pic Skip profile picture
--metadata-local Store metadata locally
--quiet Minimal output
--verbose Verbose output
Authentication
Sección titulada «Authentication»Session Management
Sección titulada «Session Management»First-Time Login
Sección titulada «First-Time Login»# Interactive login with browser
instaloader --login username
# Follow prompts:
# 1. Enter password
# 2. Complete 2FA if prompted
# 3. Session automatically saved
Reuse Saved Session
Sección titulada «Reuse Saved Session»# Session stored in config directory
# ~/.local/share/instaloader/
# or ~/.config/instaloader/
# Login returns session file
instaloader --login username
# Subsequent runs use cached session
instaloader username
Save Session Explicitly
Sección titulada «Save Session Explicitly»# Save session for later use
instaloader --login username --save-session session.json
# Load specific session
instaloader --session session.json profile_name
Cookie-Based Authentication
Sección titulada «Cookie-Based Authentication»# Export cookies from browser
# Use browser extension (e.g., EditThisCookie)
# Save as cookies.txt
# Use exported cookies
instaloader --load-cookies cookies.txt profile_name
Profile Analysis
Sección titulada «Profile Analysis»Download Complete Profile
Sección titulada «Download Complete Profile»Basic Profile Download
Sección titulada «Basic Profile Download»# Download all public posts
instaloader profile_name
# Output structure:
# profile_name/
# ├── 2024-01-15_ABC123_0.jpg
# ├── 2024-01-15_ABC123_0.txt (caption)
# ├── 2024-01-15_ABC123_0.json (metadata)
# └── profile.json (profile info)
Profile with Metadata
Sección titulada «Profile with Metadata»# Download including all metadata
instaloader --profile-pic --stories \
--no-captions profile_name
# profile.json contains:
# - username
# - full_name
# - biography
# - follower_count
# - following_count
# - is_private
# - business_category_name
# - external_url
# - contact_email
Extract Profile Information
Sección titulada «Extract Profile Information»Profile Metadata Analysis
Sección titulada «Profile Metadata Analysis»#!/usr/bin/env python3
import json
# Load profile metadata
with open('profile_name/profile.json', 'r') as f:
profile = json.load(f)
# Extract key information
print(f"Username: {profile['username']}")
print(f"Full Name: {profile['full_name']}")
print(f"Biography: {profile['biography']}")
print(f"Followers: {profile['follower_count']}")
print(f"Following: {profile['following_count']}")
print(f"Posts: {profile['edge_owner_to_timeline_by_timeline']['edges'].__len__()}")
print(f"Website: {profile['external_url']}")
print(f"Contact: {profile['contact_email']}")
print(f"Business Category: {profile['business_category_name']}")
Download Stories
Sección titulada «Download Stories»Story Collection
Sección titulada «Story Collection»# Download all stories
instaloader --stories profile_name
# With metadata
instaloader --stories --metadata-local profile_name
# Only latest stories
instaloader --stories --count 10 profile_name
# Stories saved with timestamps
# profile_name/stories/
# ├── 2024-01-15_120000_story.jpg
# ├── 2024-01-15_120000_story.json
Story Timestamp Analysis
Sección titulada «Story Timestamp Analysis»#!/usr/bin/env python3
import os
import json
from datetime import datetime
story_dir = "profile_name/stories"
for filename in sorted(os.listdir(story_dir)):
if filename.endswith('.json'):
with open(os.path.join(story_dir, filename)) as f:
data = json.load(f)
# Extract timestamp
taken_at = data.get('taken_at_timestamp', 0)
timestamp = datetime.fromtimestamp(taken_at)
print(f"{filename}: {timestamp}")
Download Highlights
Sección titulada «Download Highlights»Story Highlights Preservation
Sección titulada «Story Highlights Preservation»# Download story highlights
instaloader --highlights profile_name
# Output: profile_name/stories/highlight_name/
# Contains:
# - Highlight cover image
# - All stories in highlight
# - Metadata files
# Access saved highlights
ls -la profile_name/stories/highlight_*
Hashtag and Location Analysis
Sección titulada «Hashtag and Location Analysis»Hashtag Research
Sección titulada «Hashtag Research»Download Hashtag Posts
Sección titulada «Download Hashtag Posts»# Download posts with hashtag
instaloader "#hashtag"
# Limit results
instaloader "#hashtag" --count 100
# Filter by date
instaloader "#hashtag" \
--post-filter "date > datetime(2024,1,1)"
Hashtag Analysis Script
Sección titulada «Hashtag Analysis Script»#!/usr/bin/env python3
import json
import os
from collections import defaultdict
hashtag = "hashtag"
hashtag_dir = hashtag.replace("#", "")
# Analyze posts
engagement = defaultdict(int)
authors = set()
for filename in os.listdir(hashtag_dir):
if filename.endswith('.json'):
with open(os.path.join(hashtag_dir, filename)) as f:
post = json.load(f)
authors.add(post['owner']['username'])
engagement[post['owner']['username']] += (
post['edge_liked_by']['edge_likedby_count'] +
post['edge_media_to_caption']['edges'].__len__()
)
# Print top contributors
print(f"Total unique authors: {len(authors)}")
print("\nTop 10 contributors:")
for author, score in sorted(engagement.items(),
key=lambda x: x[1],
reverse=True)[:10]:
print(f"{author}: {score} engagements")
Location Research
Sección titulada «Location Research»Download Location Posts
Sección titulada «Download Location Posts»# Note: Instaloader has limited location support
# Alternative: Manual location lookup
# Find posts from location
# Typically requires manual browsing or API
# Workaround: Download posts mentioning location
instaloader -C 100 \
--post-filter "location == 'Location Name'"
Advanced Workflows
Sección titulada «Advanced Workflows»OSINT Intelligence Gathering
Sección titulada «OSINT Intelligence Gathering»Complete Profile Intelligence
Sección titulada «Complete Profile Intelligence»#!/bin/bash
TARGET="target_username"
OUTPUT_DIR="osint_results"
mkdir -p "$OUTPUT_DIR"
echo "[*] Gathering OSINT on $TARGET"
# 1. Download profile
echo "[*] Downloading profile..."
instaloader --login your_username --profile-pic \
--stories "$TARGET" -d "$OUTPUT_DIR"
# 2. Extract metadata
echo "[*] Extracting metadata..."
python3 << 'EOF'
import json
import os
profile_file = f"$OUTPUT_DIR/$TARGET/profile.json"
if os.path.exists(profile_file):
with open(profile_file) as f:
profile = json.load(f)
intel = {
'username': profile['username'],
'full_name': profile['full_name'],
'bio': profile['biography'],
'followers': profile['follower_count'],
'following': profile['following_count'],
'website': profile['external_url'],
'email': profile['contact_email'],
'business': profile['business_category_name']
}
with open(f"$OUTPUT_DIR/intelligence.json", 'w') as out:
json.dump(intel, out, indent=2)
print("[+] Intelligence extracted")
EOF
echo "[*] OSINT complete. Results in $OUTPUT_DIR/"
Social Network Analysis
Sección titulada «Social Network Analysis»#!/usr/bin/env python3
import json
import os
from collections import Counter
def analyze_social_network(profile_dir):
"""Analyze follower/following relationships"""
profile_file = os.path.join(profile_dir, 'profile.json')
with open(profile_file) as f:
profile = json.load(f)
# Extract relationships
followers = profile['follower_count']
following = profile['following_count']
print(f"Profile: {profile['username']}")
print(f"Followers: {followers}")
print(f"Following: {following}")
print(f"Engagement Ratio: {followers / max(following, 1):.2f}")
# Analyze posts
posts = profile['edge_owner_to_timeline_by_timeline']['edges']
engagement_scores = []
for post in posts[:20]: # Last 20 posts
node = post['node']
likes = node['edge_liked_by']['count']
comments = node['edge_media_to_caption']['edges'].__len__()
engagement = likes + (comments * 2) # Weight comments higher
engagement_scores.append(engagement)
avg_engagement = sum(engagement_scores) / len(engagement_scores)
print(f"\nAverage engagement (last 20): {avg_engagement:.0f}")
print(f"Engagement rate: {(avg_engagement / followers * 100):.2f}%")
# Usage
analyze_social_network('target_username')
Content Analysis
Sección titulada «Content Analysis»Post Metadata Extraction
Sección titulada «Post Metadata Extraction»#!/usr/bin/env python3
import json
import os
from datetime import datetime
from collections import defaultdict
def analyze_posts(profile_dir):
"""Analyze post patterns and content"""
posts_dir = os.path.join(profile_dir)
post_types = defaultdict(int)
posting_hours = defaultdict(int)
engagement_by_type = defaultdict(list)
for filename in os.listdir(posts_dir):
if not filename.endswith('.json'):
continue
filepath = os.path.join(posts_dir, filename)
with open(filepath) as f:
try:
post = json.load(f)
except:
continue
# Determine post type
is_video = post.get('is_video', False)
post_type = 'video' if is_video else 'image'
post_types[post_type] += 1
# Extract timestamp
timestamp = datetime.fromtimestamp(post['taken_at_timestamp'])
posting_hours[timestamp.hour] += 1
# Engagement metrics
likes = post.get('edge_liked_by', {}).get('count', 0)
comments = post.get('edge_media_to_comment', {}).get('count', 0)
engagement_by_type[post_type].append(likes + comments)
# Print analysis
print(f"Content breakdown:")
for post_type, count in post_types.items():
print(f" {post_type}: {count}")
print(f"\nPosting frequency by hour (UTC):")
for hour, count in sorted(posting_hours.items()):
print(f" {hour:02d}:00 - {hour:02d}:59: {count}")
print(f"\nAverage engagement by type:")
for post_type, scores in engagement_by_type.items():
avg = sum(scores) / len(scores) if scores else 0
print(f" {post_type}: {avg:.0f}")
# Usage
analyze_posts('target_username')
Video and Media Download
Sección titulada «Video and Media Download»Download Video Content
Sección titulada «Download Video Content»# Download IGTV/Reels
instaloader --igtv target_username
# Download all media including videos
instaloader --no-captions target_username
# Video files saved as MP4
# With metadata in JSON files
Media Organization
Sección titulada «Media Organization»#!/bin/bash
# Organize downloads by type
SOURCE="target_username"
OUTPUT="organized_media"
mkdir -p "$OUTPUT"/{photos,videos,stories,metadata}
# Separate by file type
for file in "$SOURCE"/*.jpg; do
[ -f "$file" ] && cp "$file" "$OUTPUT/photos/"
done
for file in "$SOURCE"/*.mp4; do
[ -f "$file" ] && cp "$file" "$OUTPUT/videos/"
done
for file in "$SOURCE"/*.json; do
[ -f "$file" ] && cp "$file" "$OUTPUT/metadata/"
done
# Stories
if [ -d "$SOURCE/stories" ]; then
cp -r "$SOURCE/stories" "$OUTPUT/stories"
fi
echo "[+] Media organized in $OUTPUT/"
Rate Limiting and Ethics
Sección titulada «Rate Limiting and Ethics»Responsible Usage
Sección titulada «Responsible Usage»Request Rate Limiting
Sección titulada «Request Rate Limiting»# Add delay between requests
instaloader --sleep-after-login 30 username
# Throttle requests
instaloader --max-request-retries 3 username
# Reasonable delays prevent detection
# 5-10 second delays between bulk operations
Session Best Practices
Sección titulada «Session Best Practices»# Use persistent session
# Rotate user agents
# Don't run in parallel
# Respect Instagram's robots.txt
# Follow API rate limits
# Archive sessions for reuse
Legal Considerations
Sección titulada «Legal Considerations»Terms of Service Compliance
Sección titulada «Terms of Service Compliance»Instagram Terms Restrictions:
- Don't download content without authorization
- Don't bypass security measures
- Don't use for spam/harassment
- Respect privacy settings
Legal Usage:
- Personal research
- Academic purposes
- Authorized security assessments
- Public content only
- Attribution of content
Troubleshooting
Sección titulada «Troubleshooting»Authentication Issues
Sección titulada «Authentication Issues»Login Failures
Sección titulada «Login Failures»# Clear old session
rm -rf ~/.local/share/instaloader/
# Re-authenticate
instaloader --login username --password password
# If 2FA enabled
# Respond to browser prompt
instaloader --login username
Session Expired
Sección titulada «Session Expired»# Save fresh session
instaloader --login username --save-session fresh.json
# Use explicit session
instaloader --session fresh.json profile_name
Download Issues
Sección titulada «Download Issues»No Results
Sección titulada «No Results»# Verify profile exists
instaloader --login user target_username --count 1
# Check profile visibility
# Private accounts require following
# Test with public profile first
# Verify credentials
instaloader --login user --test-login
Partial Downloads
Sección titulada «Partial Downloads»# Resume interrupted download
instaloader --login user profile_name
# Force re-download
rm profile_name/*.json
instaloader --login user profile_name
Rate Limiting
Sección titulada «Rate Limiting»”Too Many Requests”
Sección titulada «”Too Many Requests”»# Reduce request frequency
# Add delays between operations
sleep 30
# Try again later
instaloader --sleep-after-login 60 profile_name
# Use different session
instaloader --session backup.json profile_name
Advanced Python Usage
Sección titulada «Advanced Python Usage»Custom Instaloader Scripts
Sección titulada «Custom Instaloader Scripts»#!/usr/bin/env python3
import instaloader
from pathlib import Path
# Initialize loader
L = instaloader.Instaloader()
# Login
L.login("username", "password")
# Download profile
profile = instaloader.Profile.from_username(L.context, "target")
# Access profile attributes
print(f"Username: {profile.username}")
print(f"Followers: {profile.followers}")
print(f"Followed by: {profile.followed_by}")
# Iterate posts
for post in profile.get_posts():
print(f"Post: {post.caption[:50]}")
print(f"Likes: {post.likes}")
print(f"Comments: {post.comments}")
# Download specific post
L.download_post(post, target='./downloads')
# Logout
L.close()
Data Export
Sección titulada «Data Export»Format and Structure
Sección titulada «Format and Structure»JSON Metadata Format
Sección titulada «JSON Metadata Format»{
"node": {
"id": "post_id",
"taken_at_timestamp": 1234567890,
"caption": "Post caption text",
"edge_liked_by": {"count": 1000},
"edge_media_to_comment": {"count": 50},
"owner": {
"username": "author"
}
}
}
Export to CSV
Sección titulada «Export to CSV»#!/usr/bin/env python3
import json
import csv
import os
def export_to_csv(profile_dir, output_file):
"""Export posts to CSV"""
rows = []
for filename in os.listdir(profile_dir):
if not filename.endswith('.json'):
continue
with open(os.path.join(profile_dir, filename)) as f:
post = json.load(f)
rows.append({
'timestamp': post['taken_at_timestamp'],
'caption': post['caption'][:100],
'likes': post['edge_liked_by']['count'],
'comments': post['edge_media_to_comment']['count'],
'author': post['owner']['username']
})
# Write CSV
with open(output_file, 'w', newline='') as f:
writer = csv.DictWriter(f, fieldnames=rows[0].keys())
writer.writeheader()
writer.writerows(rows)
# Usage
export_to_csv('target_username', 'posts.csv')
Resources
Sección titulada «Resources»- Official Documentation: https://instaloader.github.io/
- GitHub Repository: https://github.com/instaloader/instaloader
- Community Discussions: GitHub Issues & Discussions
- Similar Tools: IG-Story-Downloader, Bulk Instagram Image Downloader
- Academic References: Social Media OSINT Papers
Version Information
Sección titulada «Version Information»Current stable: Instaloader 4.13+ Language: Python 3.6+ Cross-platform: Linux, macOS, Windows Dependencies: requests License: MIT Active Development: Community-maintained