kesma

make_network_db.py

Dec 17th, 2024
27
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 7.48 KB | None | 0 0
  1. import json
  2. import requests
  3. import os
  4. import traceback # Added for detailed exception logging
  5. from urllib.parse import quote
  6.  
  7. # Replace these with your Bluesky username and app password
  8. USERNAME = os.getenv('BLUESKY_USERNAME')
  9. APP_PASSWORD = os.getenv('BLUESKY_PASSWORD')
  10.  
  11. # Paths to the JSON files
  12. INITIAL_USERS_FILE = 'members_output.json' # The file you provided
  13. DATABASE_FILE = 'user_database.json'
  14. PROCESSED_INITIAL_USERS_FILE = 'processed_initial_users.json'
  15. SKIPPED_USERS_FILE = 'skipped_users.json'
  16.  
  17. # Base URL for the Bluesky API
  18. API_BASE_URL = 'https://bsky.social'
  19. def login(username, password):
  20. url = f'{API_BASE_URL}/xrpc/com.atproto.server.createSession'
  21. payload = {
  22. 'identifier': username,
  23. 'password': password
  24. }
  25. response = requests.post(url, json=payload)
  26. response.raise_for_status()
  27. data = response.json()
  28. return data['accessJwt']
  29.  
  30. def get_profile(access_token, actor):
  31. actor_encoded = quote(actor, safe=':')
  32. url = f'{API_BASE_URL}/xrpc/app.bsky.actor.getProfile?actor={actor_encoded}'
  33. headers = {
  34. 'Authorization': f'Bearer {access_token}'
  35. }
  36. response = requests.get(url, headers=headers)
  37. if response.status_code == 400:
  38. print(f'Could not get profile for actor {actor}: {response.text}')
  39. return None
  40. response.raise_for_status()
  41. return response.json()
  42.  
  43. def get_following(access_token, actor_did):
  44. url = f'{API_BASE_URL}/xrpc/app.bsky.graph.getFollows' # Gets the list of users the actor is following
  45. headers = {
  46. 'Authorization': f'Bearer {access_token}'
  47. }
  48. params = {
  49. 'actor': actor_did,
  50. 'limit': 100 # Max limit per API
  51. }
  52. following = []
  53. cursor = None
  54. while True:
  55. if cursor:
  56. params['cursor'] = cursor
  57. response = requests.get(url, headers=headers, params=params)
  58. if response.status_code == 400:
  59. print(f'Could not get following for actor {actor_did}: {response.text}')
  60. break
  61. response.raise_for_status()
  62. data = response.json()
  63. following.extend(data.get('follows', [])) # The key is 'follows' in the API response
  64. cursor = data.get('cursor')
  65. if not cursor:
  66. break
  67. return following
  68.  
  69. def save_json_file(filename, data):
  70. with open(filename, 'w') as f:
  71. json.dump(data, f, indent=4)
  72. print(f'Saved data to {filename}')
  73.  
  74. def main():
  75. try:
  76. # Authenticate and get access token
  77. print('Logging in...')
  78. access_token = login(USERNAME, APP_PASSWORD)
  79. print('Logged in successfully.')
  80.  
  81. # Load or initialize the database
  82. if os.path.exists(DATABASE_FILE):
  83. with open(DATABASE_FILE, 'r') as f:
  84. user_database = json.load(f)
  85. else:
  86. user_database = []
  87. save_json_file(DATABASE_FILE, user_database)
  88.  
  89. # Load or initialize the list of processed initial users
  90. if os.path.exists(PROCESSED_INITIAL_USERS_FILE):
  91. with open(PROCESSED_INITIAL_USERS_FILE, 'r') as f:
  92. processed_initial_users = json.load(f)
  93. else:
  94. processed_initial_users = []
  95. save_json_file(PROCESSED_INITIAL_USERS_FILE, processed_initial_users)
  96.  
  97. # Load or initialize the list of skipped users
  98. if os.path.exists(SKIPPED_USERS_FILE):
  99. with open(SKIPPED_USERS_FILE, 'r') as f:
  100. skipped_users = json.load(f)
  101. else:
  102. skipped_users = []
  103. save_json_file(SKIPPED_USERS_FILE, skipped_users)
  104.  
  105. # Create sets for quick lookup
  106. existing_users = set(user['handle'] for user in user_database)
  107. processed_initial_users_set = set(processed_initial_users)
  108. skipped_users_set = set(skipped_users)
  109.  
  110. # Load initial users from members_output.json
  111. with open(INITIAL_USERS_FILE, 'r') as f:
  112. initial_users_data = json.load(f)
  113.  
  114. initial_users = []
  115. initial_users_set = set()
  116.  
  117. # Extract handles from the initial users data
  118. for item in initial_users_data:
  119. subject = item.get('subject', {})
  120. handle = subject.get('handle')
  121. if handle:
  122. initial_users.append(handle)
  123. initial_users_set.add(handle)
  124. else:
  125. print('No handle found for one of the initial users.')
  126.  
  127. print(f'Found {len(initial_users)} initial users from {INITIAL_USERS_FILE}.')
  128.  
  129. # Process each user's follows using limit and cursor
  130. for username in initial_users:
  131. if username in processed_initial_users_set:
  132. print(f'Skipping initial user {username}: Already processed.')
  133. continue
  134.  
  135. print(f'Processing user: {username}')
  136. try:
  137. # Get the user's profile to obtain their DID
  138. profile = get_profile(access_token, username)
  139. if profile is None:
  140. print(f'Skipping user {username}: Unable to get profile.')
  141. if username not in skipped_users_set:
  142. skipped_users.append(username)
  143. skipped_users_set.add(username)
  144. save_json_file(SKIPPED_USERS_FILE, skipped_users)
  145. continue
  146. user_did = profile['did']
  147.  
  148. # Fetch the list of users this user is following using limit and cursor
  149. following = get_following(access_token, user_did)
  150.  
  151. # Use the data from 'following' directly without additional API calls
  152. for follow in following:
  153. followed_username = follow.get('handle')
  154. if (followed_username not in existing_users and
  155. followed_username not in initial_users_set):
  156. # Add the 'follow' data directly to user_database
  157. user_database.append(follow)
  158. existing_users.add(followed_username)
  159.  
  160. # Mark the initial user as processed
  161. processed_initial_users.append(username)
  162. processed_initial_users_set.add(username)
  163.  
  164. # Save data after each user is processed
  165. save_json_file(DATABASE_FILE, user_database)
  166. save_json_file(PROCESSED_INITIAL_USERS_FILE, processed_initial_users)
  167. save_json_file(SKIPPED_USERS_FILE, skipped_users)
  168.  
  169. print(f'Finished processing user: {username}')
  170.  
  171. except requests.HTTPError as e:
  172. print(f'HTTP error processing {username}: {e}')
  173. traceback.print_exc()
  174. if username not in skipped_users_set:
  175. skipped_users.append(username)
  176. skipped_users_set.add(username)
  177. save_json_file(SKIPPED_USERS_FILE, skipped_users)
  178. except Exception as e:
  179. print(f'Error processing {username}: {e}')
  180. traceback.print_exc()
  181. if username not in skipped_users_set:
  182. skipped_users.append(username)
  183. skipped_users_set.add(username)
  184. save_json_file(SKIPPED_USERS_FILE, skipped_users)
  185.  
  186. print('Processing completed.')
  187.  
  188. except Exception as e:
  189. print(f'An unexpected error occurred: {e}')
  190. traceback.print_exc()
  191.  
  192. if __name__ == '__main__':
  193. main()
Advertisement
Add Comment
Please, Sign In to add comment