Instaloader
Overview
Sezione intitolata “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
Sezione intitolata “Installation”Linux (Debian/Ubuntu)
Sezione intitolata “Linux (Debian/Ubuntu)”sudo apt-get update
sudo apt-get install python3 python3-pip
pip3 install instaloader
brew install python3
pip3 install instaloader
Windows
Sezione intitolata “Windows”# Python 3.6+ required
python -m pip install instaloader
FROM python:3.11-slim
RUN pip install instaloader
ENTRYPOINT ["instaloader"]
Build from Source
Sezione intitolata “Build from Source”git clone https://github.com/instaloader/instaloader.git
cd instaloader
python3 -m pip install -e .
Verify Installation
Sezione intitolata “Verify Installation”instaloader --version
instaloader -h
Basic Usage
Sezione intitolata “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
Sezione intitolata “Command-Line Options”Profile Options
Sezione intitolata “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
Sezione intitolata “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
Sezione intitolata “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
Sezione intitolata “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
Sezione intitolata “Authentication”Session Management
Sezione intitolata “Session Management”First-Time Login
Sezione intitolata “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
Sezione intitolata “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
Sezione intitolata “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
Sezione intitolata “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
Sezione intitolata “Profile Analysis”Download Complete Profile
Sezione intitolata “Download Complete Profile”Basic Profile Download
Sezione intitolata “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
Sezione intitolata “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
Sezione intitolata “Extract Profile Information”Profile Metadata Analysis
Sezione intitolata “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
Sezione intitolata “Download Stories”Story Collection
Sezione intitolata “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
Sezione intitolata “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
Sezione intitolata “Download Highlights”Story Highlights Preservation
Sezione intitolata “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
Sezione intitolata “Hashtag and Location Analysis”Hashtag Research
Sezione intitolata “Hashtag Research”Download Hashtag Posts
Sezione intitolata “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
Sezione intitolata “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
Sezione intitolata “Location Research”Download Location Posts
Sezione intitolata “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
Sezione intitolata “Advanced Workflows”OSINT Intelligence Gathering
Sezione intitolata “OSINT Intelligence Gathering”Complete Profile Intelligence
Sezione intitolata “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
Sezione intitolata “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
Sezione intitolata “Content Analysis”Post Metadata Extraction
Sezione intitolata “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
Sezione intitolata “Video and Media Download”Download Video Content
Sezione intitolata “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
Sezione intitolata “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
Sezione intitolata “Rate Limiting and Ethics”Responsible Usage
Sezione intitolata “Responsible Usage”Request Rate Limiting
Sezione intitolata “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
Sezione intitolata “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
Sezione intitolata “Legal Considerations”Terms of Service Compliance
Sezione intitolata “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
Sezione intitolata “Troubleshooting”Authentication Issues
Sezione intitolata “Authentication Issues”Login Failures
Sezione intitolata “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
Sezione intitolata “Session Expired”# Save fresh session
instaloader --login username --save-session fresh.json
# Use explicit session
instaloader --session fresh.json profile_name
Download Issues
Sezione intitolata “Download Issues”No Results
Sezione intitolata “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
Sezione intitolata “Partial Downloads”# Resume interrupted download
instaloader --login user profile_name
# Force re-download
rm profile_name/*.json
instaloader --login user profile_name
Rate Limiting
Sezione intitolata “Rate Limiting””Too Many Requests”
Sezione intitolata “”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
Sezione intitolata “Advanced Python Usage”Custom Instaloader Scripts
Sezione intitolata “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
Sezione intitolata “Data Export”Format and Structure
Sezione intitolata “Format and Structure”JSON Metadata Format
Sezione intitolata “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
Sezione intitolata “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
Sezione intitolata “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
Sezione intitolata “Version Information”Current stable: Instaloader 4.13+ Language: Python 3.6+ Cross-platform: Linux, macOS, Windows Dependencies: requests License: MIT Active Development: Community-maintained