コンテンツにスキップ

Instaloader

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.

sudo apt-get update
sudo apt-get install python3 python3-pip
pip3 install instaloader
brew install python3
pip3 install instaloader
# Python 3.6+ required
python -m pip install instaloader
FROM python:3.11-slim
RUN pip install instaloader
ENTRYPOINT ["instaloader"]
git clone https://github.com/instaloader/instaloader.git
cd instaloader
python3 -m pip install -e .
instaloader --version
instaloader -h
CommandDescription
instaloader profile_nameDownload profile
instaloader --login usernameLogin with username
instaloader --stories profile_nameDownload stories
instaloader --igtv profile_nameDownload IGTV/reels
instaloader "#hashtag"Download hashtag posts
instaloader @usernameDownload profile by handle
--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
--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
-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
-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
# Interactive login with browser
instaloader --login username

# Follow prompts:
# 1. Enter password
# 2. Complete 2FA if prompted
# 3. Session automatically saved
# 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 for later use
instaloader --login username --save-session session.json

# Load specific session
instaloader --session session.json profile_name
# Export cookies from browser
# Use browser extension (e.g., EditThisCookie)
# Save as cookies.txt

# Use exported cookies
instaloader --load-cookies cookies.txt profile_name
# 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)
# 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
#!/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 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
#!/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 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_*
# Download posts with hashtag
instaloader "#hashtag"

# Limit results
instaloader "#hashtag" --count 100

# Filter by date
instaloader "#hashtag" \
    --post-filter "date > datetime(2024,1,1)"
#!/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")
# 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'"
#!/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/"
#!/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')
#!/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')
# 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
#!/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/"
# 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
# Use persistent session
# Rotate user agents
# Don't run in parallel
# Respect Instagram's robots.txt
# Follow API rate limits
# Archive sessions for reuse
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
# 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
# Save fresh session
instaloader --login username --save-session fresh.json

# Use explicit session
instaloader --session fresh.json profile_name
# 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
# Resume interrupted download
instaloader --login user profile_name

# Force re-download
rm profile_name/*.json
instaloader --login user profile_name
# 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
#!/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()
{
  "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"
    }
  }
}
#!/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')

Current stable: Instaloader 4.13+ Language: Python 3.6+ Cross-platform: Linux, macOS, Windows Dependencies: requests License: MIT Active Development: Community-maintained