reddit-universal-scraper/analytics/subreddit_stats.py
2025-12-13 22:35:09 +05:30

243 lines
7.4 KiB
Python

"""
Subreddit Statistics - Subscribers, rules, mods, and metadata
"""
import requests
from datetime import datetime
import json
USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"
def get_subreddit_about(subreddit):
"""
Fetch subreddit metadata (subscribers, description, rules, etc.)
Args:
subreddit: Subreddit name (without r/)
Returns:
Dictionary with subreddit info
"""
url = f"https://old.reddit.com/r/{subreddit}/about.json"
try:
response = requests.get(url, headers={"User-Agent": USER_AGENT}, timeout=15)
if response.status_code != 200:
print(f"❌ Failed to fetch r/{subreddit} info: {response.status_code}")
return None
data = response.json()['data']
return {
"name": data.get('display_name'),
"title": data.get('title'),
"description": data.get('public_description'),
"subscribers": data.get('subscribers', 0),
"active_users": data.get('accounts_active', 0),
"created_utc": datetime.fromtimestamp(data.get('created_utc', 0)).isoformat(),
"over_18": data.get('over18', False),
"subreddit_type": data.get('subreddit_type'), # public, private, restricted
"lang": data.get('lang'),
"icon_url": data.get('icon_img', '').split('?')[0] if data.get('icon_img') else None,
"banner_url": data.get('banner_img', '').split('?')[0] if data.get('banner_img') else None,
"header_url": data.get('header_img'),
"community_icon": data.get('community_icon', '').split('?')[0] if data.get('community_icon') else None,
"wiki_enabled": data.get('wiki_enabled', False),
"spoilers_enabled": data.get('spoilers_enabled', False),
"allow_videos": data.get('allow_videos', False),
"allow_images": data.get('allow_images', False),
"allow_polls": data.get('allow_polls', False),
}
except Exception as e:
print(f"❌ Error fetching subreddit info: {e}")
return None
def get_subreddit_rules(subreddit):
"""
Fetch subreddit rules.
Args:
subreddit: Subreddit name
Returns:
List of rule dictionaries
"""
url = f"https://old.reddit.com/r/{subreddit}/about/rules.json"
try:
response = requests.get(url, headers={"User-Agent": USER_AGENT}, timeout=15)
if response.status_code != 200:
return []
data = response.json()
rules = []
for rule in data.get('rules', []):
rules.append({
"short_name": rule.get('short_name'),
"description": rule.get('description'),
"priority": rule.get('priority'),
"kind": rule.get('kind'), # link, comment, all
"created_utc": datetime.fromtimestamp(rule.get('created_utc', 0)).isoformat()
})
return rules
except Exception as e:
print(f"❌ Error fetching rules: {e}")
return []
def get_subreddit_mods(subreddit):
"""
Fetch subreddit moderators.
Args:
subreddit: Subreddit name
Returns:
List of moderator usernames
"""
url = f"https://old.reddit.com/r/{subreddit}/about/moderators.json"
try:
response = requests.get(url, headers={"User-Agent": USER_AGENT}, timeout=15)
if response.status_code != 200:
return []
data = response.json()
mods = []
for mod in data.get('data', {}).get('children', []):
mods.append({
"name": mod.get('name'),
"permissions": mod.get('mod_permissions', []),
"added_utc": datetime.fromtimestamp(mod.get('date', 0)).isoformat() if mod.get('date') else None
})
return mods
except Exception as e:
print(f"❌ Error fetching mods: {e}")
return []
def get_subreddit_flairs(subreddit):
"""
Fetch available post flairs.
Args:
subreddit: Subreddit name
Returns:
List of flair options
"""
url = f"https://old.reddit.com/r/{subreddit}/api/link_flair_v2.json"
try:
response = requests.get(url, headers={"User-Agent": USER_AGENT}, timeout=15)
if response.status_code != 200:
return []
flairs = []
for flair in response.json():
flairs.append({
"text": flair.get('text'),
"id": flair.get('id'),
"background_color": flair.get('background_color'),
"text_color": flair.get('text_color'),
"type": flair.get('type')
})
return flairs
except Exception as e:
return []
def get_full_subreddit_stats(subreddit):
"""
Get comprehensive subreddit statistics.
Args:
subreddit: Subreddit name
Returns:
Dictionary with all stats
"""
print(f"📊 Fetching stats for r/{subreddit}...")
about = get_subreddit_about(subreddit)
if not about:
return None
rules = get_subreddit_rules(subreddit)
mods = get_subreddit_mods(subreddit)
flairs = get_subreddit_flairs(subreddit)
stats = {
**about,
"rules": rules,
"rules_count": len(rules),
"moderators": mods,
"moderator_count": len(mods),
"flairs": flairs,
"flair_count": len(flairs),
"fetched_at": datetime.now().isoformat()
}
# Print summary
print(f"\n📊 r/{subreddit} Statistics:")
print(f" 👥 Subscribers: {stats['subscribers']:,}")
print(f" 🟢 Active Users: {stats['active_users']:,}")
print(f" 📜 Rules: {stats['rules_count']}")
print(f" 👮 Moderators: {stats['moderator_count']}")
print(f" 🏷️ Flairs: {stats['flair_count']}")
print(f" 📅 Created: {stats['created_utc'][:10]}")
print(f" 🔞 NSFW: {stats['over_18']}")
return stats
def save_subreddit_stats(subreddit, output_dir="data"):
"""
Fetch and save subreddit stats to JSON.
Args:
subreddit: Subreddit name
output_dir: Output directory
Returns:
Path to saved file
"""
import os
stats = get_full_subreddit_stats(subreddit)
if not stats:
return None
save_dir = f"{output_dir}/r_{subreddit}"
os.makedirs(save_dir, exist_ok=True)
filepath = f"{save_dir}/subreddit_stats.json"
with open(filepath, 'w', encoding='utf-8') as f:
json.dump(stats, f, indent=2, ensure_ascii=False)
print(f"\n💾 Saved to {filepath}")
return filepath
# CLI for testing
if __name__ == "__main__":
import argparse
parser = argparse.ArgumentParser(description="Subreddit Statistics")
parser.add_argument("subreddit", help="Subreddit name")
parser.add_argument("--save", action="store_true", help="Save to JSON")
args = parser.parse_args()
if args.save:
save_subreddit_stats(args.subreddit)
else:
stats = get_full_subreddit_stats(args.subreddit)
if stats:
print(f"\n📝 Description: {stats['description'][:200]}..." if stats['description'] else "")