Guest User

Untitled

a guest
Dec 23rd, 2025
133
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 9.30 KB | Source Code | 0 0
  1. import praw
  2. import json
  3. import time
  4. from datetime import datetime
  5.  
  6.  
  7. subreddit_list = [
  8. 'medicine', 'nursing', 'Residency', 'medicalschool', 'pharmacy', 'Dentistry',
  9. 'Veterinary', 'ems', 'NewToEMS', 'medlabprofessionals', 'physicaltherapy',
  10. 'radiology', 'slp', 'optometry', 'Chiropractic', 'therapists', 'socialwork',
  11. 'psychotherapy', 'doctorsUK', 'cscareerquestions', 'sysadmin', 'devops',
  12. 'ITCareerQuestions', 'webdev', 'softwareengineering', 'networking',
  13. 'cybersecurity', 'datascience', 'gamedev', 'ProgrammerHumor',
  14. 'qualityassurance', 'UI_Design', 'userexperience', 'skilledtrades',
  15. 'Construction', 'Electricians', 'Plumbing', 'HVAC', 'Welding', 'Truckers',
  16. 'Carpentry', 'Machinists', 'Lineman', 'Locksmith', 'millwrights',
  17. 'oilandgasworkers', 'railroading', 'landscaping', 'Justrolledintotheshop',
  18. 'engineering', 'civilengineering', 'mechanicalengineering',
  19. 'electricalengineering', 'ChemicalEngineering', 'aerospace', 'biotech', 'PLC',
  20. 'Accounting', 'FinancialCareers', 'consulting', 'marketing', 'sales',
  21. 'humanresources', 'supplychain', 'actuary', 'InsurancePros', 'realtors',
  22. 'CommercialRealEstate', 'Lawyers', 'LawSchool', 'paralegal', 'PublicDefenders',
  23. 'KitchenConfidential', 'Chefit', 'TalesFromRetail', 'Serverlife', 'bartenders',
  24. 'flightattendants', 'TalesFromTheFrontDesk', 'starbucks', 'Custodians',
  25. 'Teachers', 'Professors', 'highereducation', 'librarians', 'ece', 'teaching',
  26. 'graphic_design', 'filmmakers', 'editors', 'journalism', 'copywriting',
  27. 'advertising', 'architecture', 'photography', 'videography', 'museumpros',
  28. 'Firefighting', 'police', 'ProtectAndServe', 'securityguards', '911dispatchers',
  29. 'jobs', 'careerguidance', 'resumes', 'recruitinghell', 'remotejobs',
  30. 'civilservice', 'usajobs', 'nonprofit', 'csMajors', 'leetcode'
  31. ]
  32.  
  33. # Authenticate to Reddit
  34. reddit = praw.Reddit(client_id='',
  35. client_secret='',
  36. user_agent='MacOS:RedditDataAnalyzer:v1.0 (by /u/Sebastian764)'),
  37. username='',
  38. password='')
  39.  
  40.  
  41. def comment_to_dict(comment):
  42. """Convert a Reddit comment to a dictionary."""
  43. body = comment.body.strip() if comment.body else ''
  44.  
  45. # Skip deleted comments
  46. if body == '[deleted]' or body == '[removed]':
  47. return None
  48.  
  49. return {
  50. 'id': comment.id,
  51. 'author': str(comment.author) if comment.author else '[deleted]',
  52. 'score': comment.score,
  53. 'created_utc': comment.created_utc,
  54. 'created_date': datetime.fromtimestamp(comment.created_utc).isoformat(),
  55. 'body': body,
  56. 'body_word_count': len(body.split()) if body else 0,
  57. }
  58.  
  59.  
  60. def fetch_top_comments(post, top_percentage=0.5):
  61. """Fetch top comments for a post, returning top 50% by upvote count."""
  62. try:
  63. post.comments.replace_more(limit=0) # Load all top-level comments
  64.  
  65. # Get all top-level comments and convert to dict (excluding deleted)
  66. all_comments = []
  67. for comment in post.comments:
  68. comment_dict = comment_to_dict(comment)
  69. if comment_dict: # Only add if not deleted
  70. all_comments.append(comment_dict)
  71.  
  72. if not all_comments:
  73. return []
  74.  
  75. # Sort by score descending
  76. all_comments.sort(key=lambda x: x['score'], reverse=True)
  77.  
  78. # Get top 50%
  79. top_count = max(1, int(len(all_comments) * top_percentage))
  80. return all_comments[:top_count]
  81.  
  82. except Exception as e:
  83. print(f" Error fetching comments for post {post.id}: {e}")
  84. return []
  85.  
  86.  
  87. def post_to_dict(post, include_comments=True):
  88. """Convert a Reddit post to a dictionary."""
  89. body = post.selftext.strip() if post.selftext else ''
  90.  
  91. # Check if body is deleted
  92. if body == '[deleted]' or body == '[removed]':
  93. body = ''
  94.  
  95. post_dict = {
  96. 'id': post.id,
  97. 'title': post.title,
  98. 'score': post.score,
  99. 'url': post.url,
  100. 'permalink': f"https://reddit.com{post.permalink}",
  101. 'created_utc': post.created_utc,
  102. 'created_date': datetime.fromtimestamp(post.created_utc).isoformat(),
  103. 'author': str(post.author) if post.author else '[deleted]',
  104. 'num_comments': post.num_comments,
  105. 'body': body,
  106. 'body_word_count': len(body.split()) if body else 0,
  107. 'is_self': post.is_self,
  108. 'link_flair_text': post.link_flair_text,
  109. 'upvote_ratio': post.upvote_ratio,
  110. }
  111.  
  112. if include_comments:
  113. post_dict['top_comments'] = fetch_top_comments(post)
  114. post_dict['top_comments_count'] = len(post_dict['top_comments'])
  115.  
  116. return post_dict
  117.  
  118.  
  119. def fetch_top_posts(subreddit_name, time_filter, limit=1500):
  120. """Fetch top posts from a subreddit with the given time filter."""
  121. subreddit = reddit.subreddit(subreddit_name)
  122. posts = []
  123.  
  124. print(f" Fetching top {limit} posts ({time_filter}) from r/{subreddit_name}...")
  125.  
  126. try:
  127. for post in subreddit.top(time_filter=time_filter, limit=limit):
  128. posts.append(post_to_dict(post, include_comments=True))
  129.  
  130. # Progress indicator every 100 posts
  131. if len(posts) % 100 == 0:
  132. print(f" Fetched {len(posts)} posts...")
  133.  
  134. # Small delay to respect rate limits
  135. time.sleep(0.5)
  136. except Exception as e:
  137. print(f" Error fetching posts: {e}")
  138.  
  139. print(f" Completed: {len(posts)} posts fetched")
  140. return posts
  141.  
  142.  
  143. def extract_subreddit_data(subreddit_name):
  144. """Extract top posts of the year and all time for a subreddit."""
  145. print(f"\nProcessing r/{subreddit_name}...")
  146.  
  147. # Fetch top posts of the year
  148. year_posts = fetch_top_posts(subreddit_name, 'year', limit=1500)
  149. year_post_ids = {post['id'] for post in year_posts}
  150.  
  151. # Fetch top posts of all time
  152. all_time_posts_raw = fetch_top_posts(subreddit_name, 'all', limit=1500)
  153.  
  154. # Remove duplicates: keep posts only in "all time" if they're not in "year"
  155. all_time_posts = [post for post in all_time_posts_raw if post['id'] not in year_post_ids]
  156.  
  157. print(f" Deduplication: {len(all_time_posts_raw)} all-time posts -> {len(all_time_posts)} unique (removed {len(all_time_posts_raw) - len(all_time_posts)} duplicates)")
  158.  
  159. return {
  160. 'subreddit': subreddit_name,
  161. 'extraction_date': datetime.now().isoformat(),
  162. 'top_posts_year': {
  163. 'time_filter': 'year',
  164. 'count': len(year_posts),
  165. 'posts': year_posts
  166. },
  167. 'top_posts_all_time': {
  168. 'time_filter': 'all',
  169. 'count': len(all_time_posts),
  170. 'note': 'Excludes posts already in top_posts_year to avoid duplicates',
  171. 'posts': all_time_posts
  172. }
  173. }
  174.  
  175.  
  176. def extract_all_subreddits(subreddit_list, output_file='reddit_top_posts.json'):
  177. """Extract data from all subreddits and save to a single JSON file."""
  178. print(f"Starting extraction for {len(subreddit_list)} subreddits...")
  179.  
  180. user = reddit.user.me()
  181. print(f"Authenticated as: {user}")
  182.  
  183. data = {
  184. 'metadata': {
  185. 'extraction_date': datetime.now().isoformat(),
  186. 'subreddits_count': len(subreddit_list),
  187. 'posts_per_category': 1500,
  188. 'note': 'Posts in top_posts_year are excluded from top_posts_all_time to avoid duplicates'
  189. },
  190. 'subreddits': {}
  191. }
  192.  
  193. for subreddit_name in subreddit_list:
  194. try:
  195. subreddit_data = extract_subreddit_data(subreddit_name)
  196. data['subreddits'][subreddit_name] = subreddit_data
  197. except Exception as e:
  198. print(f"Error processing r/{subreddit_name}: {e}")
  199. data['subreddits'][subreddit_name] = {
  200. 'error': str(e),
  201. 'subreddit': subreddit_name
  202. }
  203.  
  204. # Save to JSON file
  205. print(f"\nSaving data to {output_file}...")
  206. with open(output_file, 'w', encoding='utf-8') as f:
  207. json.dump(data, f, indent=2, ensure_ascii=False)
  208.  
  209. print(f"Done! Data saved to {output_file}")
  210.  
  211. # Print summary
  212. print("\n=== Summary ===")
  213. for sub_name, sub_data in data['subreddits'].items():
  214. if 'error' not in sub_data:
  215. year_count = sub_data['top_posts_year']['count']
  216. all_time_count = sub_data['top_posts_all_time']['count']
  217. print(f"r/{sub_name}: {year_count} year posts, {all_time_count} all-time posts (unique)")
  218.  
  219. return data
  220.  
  221.  
  222. if __name__ == '__main__':
  223. # print(len(subreddit_list))
  224. test_list = subreddit_list#[:2]
  225. extract_all_subreddits(test_list, output_file='reddit_top_posts.json')
  226.  
  227.  
  228. # JSON output structure:
  229. # {
  230. # "metadata": { "extraction_date": "...", "subreddits_count": 2, ... },
  231. # "subreddits": {
  232. # "example": {
  233. # "top_posts_year": {
  234. # "count": 1500,
  235. # "posts": [
  236. # {
  237. # "id": "...",
  238. # "title": "...",
  239. # "score": 1234,
  240. # "body": "post content here",
  241. # "body_word_count": 50,
  242. # "top_comments": [
  243. # { "id": "...", "author": "...", "score": 500, "body": "comment text", ... }
  244. # ],
  245. # "top_comments_count": 10,
  246. # ...
  247. # }
  248. # ]
  249. # },
  250. # "top_posts_all_time": { "count": X, "posts": [...] }
  251. # },
  252. # "example2": { ... }
  253. # }
  254. # }
Advertisement
Add Comment
Please, Sign In to add comment