Guest User

Untitled

a guest
Mar 14th, 2025
166
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 10.02 KB | None | 0 0
  1. import tkinter as tk
  2. from tkinter import filedialog, ttk, messagebox
  3. import csv
  4. import requests
  5. import os
  6. import json
  7. import threading
  8.  
  9. class PhoneLookupApp:
  10. def __init__(self, root):
  11. self.root = root
  12. self.root.title("Bulk Phone Number Lookup Tool: r/OSINT")
  13. self.root.geometry("600x400")
  14. self.root.resizable(True, True)
  15.  
  16. # Variables
  17. self.api_key = tk.StringVar()
  18. self.file_path = tk.StringVar()
  19. self.status_text = tk.StringVar()
  20. self.status_text.set("Ready")
  21. self.progress_var = tk.DoubleVar()
  22. self.progress_var.set(0)
  23.  
  24. # Create UI elements
  25. self.create_widgets()
  26.  
  27. # Processing flag
  28. self.processing = False
  29.  
  30. def create_widgets(self):
  31. # Main frame
  32. main_frame = ttk.Frame(self.root, padding="10")
  33. main_frame.pack(fill=tk.BOTH, expand=True)
  34.  
  35. # API Key section
  36. api_frame = ttk.LabelFrame(main_frame, text="API Configuration", padding="10")
  37. api_frame.pack(fill=tk.X, pady=5)
  38.  
  39. ttk.Label(api_frame, text="Trestle API Key:").grid(row=0, column=0, sticky=tk.W, padx=5, pady=5)
  40. ttk.Entry(api_frame, textvariable=self.api_key, width=50, show="*").grid(row=0, column=1, sticky=tk.W, padx=5, pady=5)
  41.  
  42. # File selection section
  43. file_frame = ttk.LabelFrame(main_frame, text="File Selection", padding="10")
  44. file_frame.pack(fill=tk.X, pady=5)
  45.  
  46. ttk.Label(file_frame, text="CSV File:").grid(row=0, column=0, sticky=tk.W, padx=5, pady=5)
  47. ttk.Entry(file_frame, textvariable=self.file_path, width=40).grid(row=0, column=1, sticky=tk.W, padx=5, pady=5)
  48. ttk.Button(file_frame, text="Browse...", command=self.browse_file).grid(row=0, column=2, sticky=tk.W, padx=5, pady=5)
  49.  
  50. # Process button
  51. process_frame = ttk.Frame(main_frame)
  52. process_frame.pack(fill=tk.X, pady=10)
  53. ttk.Button(process_frame, text="Process Phone Numbers", command=self.start_processing).pack(anchor=tk.CENTER)
  54.  
  55. # Progress bar
  56. progress_frame = ttk.LabelFrame(main_frame, text="Progress", padding="10")
  57. progress_frame.pack(fill=tk.X, pady=5)
  58.  
  59. self.progress_bar = ttk.Progressbar(progress_frame, variable=self.progress_var, maximum=100)
  60. self.progress_bar.pack(fill=tk.X, padx=5, pady=5)
  61.  
  62. # Status label
  63. status_frame = ttk.Frame(main_frame)
  64. status_frame.pack(fill=tk.X, pady=5)
  65. ttk.Label(status_frame, textvariable=self.status_text).pack(anchor=tk.W)
  66.  
  67. def browse_file(self):
  68. file_path = filedialog.askopenfilename(
  69. title="Select CSV File",
  70. filetypes=[("CSV Files", "*.csv"), ("All Files", "*.*")]
  71. )
  72. if file_path:
  73. self.file_path.set(file_path)
  74.  
  75. def start_processing(self):
  76. # Validate inputs
  77. if not self.api_key.get().strip():
  78. messagebox.showerror("Error", "Please enter your Trestle API Key")
  79. return
  80.  
  81. if not self.file_path.get().strip():
  82. messagebox.showerror("Error", "Please select a CSV file")
  83. return
  84.  
  85. if not os.path.exists(self.file_path.get()):
  86. messagebox.showerror("Error", "Selected file does not exist")
  87. return
  88.  
  89. # Prevent multiple processing
  90. if self.processing:
  91. messagebox.showinfo("Info", "Processing is already in progress")
  92. return
  93.  
  94. # Start processing in a separate thread
  95. self.processing = True
  96. self.progress_var.set(0)
  97. self.status_text.set("Starting processing...")
  98.  
  99. processing_thread = threading.Thread(target=self.process_file)
  100. processing_thread.daemon = True
  101. processing_thread.start()
  102.  
  103. def process_file(self):
  104. try:
  105. # Read phone numbers from CSV
  106. phone_numbers = self.read_phone_numbers()
  107.  
  108. if not phone_numbers:
  109. self.status_text.set("No phone numbers found in the CSV file")
  110. self.processing = False
  111. return
  112.  
  113. # Create output file path
  114. input_file = self.file_path.get()
  115. file_name, file_ext = os.path.splitext(input_file)
  116. output_file = f"{file_name}complete.csv"
  117.  
  118. # Process each phone number
  119. total_numbers = len(phone_numbers)
  120. processed_numbers = 0
  121.  
  122. # Prepare output CSV
  123. with open(output_file, 'w', newline='', encoding='utf-8') as csvfile:
  124. # We'll determine headers after the first API call
  125. csv_writer = None
  126.  
  127. for phone_number in phone_numbers:
  128. # Update status
  129. self.status_text.set(f"Processing {phone_number} ({processed_numbers + 1}/{total_numbers})")
  130.  
  131. # Call API
  132. result = self.lookup_phone_number(phone_number)
  133.  
  134. # Initialize CSV writer with headers if this is the first result
  135. if csv_writer is None and result:
  136. # Flatten the result for CSV headers
  137. headers = self.flatten_dict_keys(result)
  138. csv_writer = csv.DictWriter(csvfile, fieldnames=headers)
  139. csv_writer.writeheader()
  140.  
  141. # Write result to CSV
  142. if result and csv_writer:
  143. # Flatten the nested dictionaries for CSV
  144. flat_result = self.flatten_dict(result)
  145. csv_writer.writerow(flat_result)
  146.  
  147. # Update progress
  148. processed_numbers += 1
  149. progress_percentage = (processed_numbers / total_numbers) * 100
  150. self.progress_var.set(progress_percentage)
  151.  
  152. # Complete
  153. self.status_text.set(f"Processing complete. Results saved to {output_file}")
  154. messagebox.showinfo("Success", f"Processing complete. Results saved to {output_file}")
  155.  
  156. except Exception as e:
  157. self.status_text.set(f"Error: {str(e)}")
  158. messagebox.showerror("Error", f"An error occurred: {str(e)}")
  159.  
  160. finally:
  161. self.processing = False
  162.  
  163. def read_phone_numbers(self):
  164. phone_numbers = []
  165. try:
  166. with open(self.file_path.get(), 'r', newline='', encoding='utf-8') as csvfile:
  167. csv_reader = csv.reader(csvfile)
  168. for row in csv_reader:
  169. if row and row[0].strip():
  170. # Assuming phone number is in the first column
  171. phone_number = row[0].strip()
  172. phone_numbers.append(phone_number)
  173.  
  174. return phone_numbers
  175.  
  176. except Exception as e:
  177. self.status_text.set(f"Error reading CSV: {str(e)}")
  178. messagebox.showerror("Error", f"Error reading CSV: {str(e)}")
  179. return []
  180.  
  181. def lookup_phone_number(self, phone_number):
  182. try:
  183. # Prepare API request
  184. api_url = f"https://api.trestleiq.com/3.2/phone?phone={phone_number}"
  185. headers = {
  186. "x-api-key": self.api_key.get()
  187. }
  188.  
  189. # Make API request
  190. response = requests.get(api_url, headers=headers)
  191.  
  192. # Check for errors
  193. if response.status_code != 200:
  194. error_message = f"API Error: {response.status_code} - {response.text}"
  195. self.status_text.set(error_message)
  196. return None
  197.  
  198. # Parse response
  199. result = response.json()
  200.  
  201. # Add the original phone number to the result
  202. result['original_phone_number'] = phone_number
  203.  
  204. return result
  205.  
  206. except requests.exceptions.RequestException as e:
  207. self.status_text.set(f"API Request Error: {str(e)}")
  208. return None
  209.  
  210. except json.JSONDecodeError:
  211. self.status_text.set("Error parsing API response")
  212. return None
  213.  
  214. def flatten_dict_keys(self, d, parent_key='', sep='_'):
  215. """Get all keys from a nested dictionary for CSV headers"""
  216. items = []
  217. for k, v in d.items():
  218. new_key = f"{parent_key}{sep}{k}" if parent_key else k
  219. if isinstance(v, dict):
  220. items.extend(self.flatten_dict_keys(v, new_key, sep=sep))
  221. elif isinstance(v, list) and v and isinstance(v[0], dict):
  222. # For the first item in a list of dictionaries
  223. items.extend(self.flatten_dict_keys(v[0], f"{new_key}_0", sep=sep))
  224. else:
  225. items.append(new_key)
  226. return items
  227.  
  228. def flatten_dict(self, d, parent_key='', sep='_'):
  229. """Flatten a nested dictionary for CSV output"""
  230. items = {}
  231. for k, v in d.items():
  232. new_key = f"{parent_key}{sep}{k}" if parent_key else k
  233. if isinstance(v, dict):
  234. items.update(self.flatten_dict(v, new_key, sep=sep))
  235. elif isinstance(v, list):
  236. if v and isinstance(v[0], dict):
  237. # Handle list of dictionaries (just take the first one for simplicity)
  238. items.update(self.flatten_dict(v[0], f"{new_key}_0", sep=sep))
  239. else:
  240. # Handle list of primitives
  241. items[new_key] = str(v)
  242. else:
  243. items[new_key] = v
  244. return items
  245.  
  246. def main():
  247. root = tk.Tk()
  248. app = PhoneLookupApp(root)
  249. root.mainloop()
  250.  
  251. if __name__ == "__main__":
  252. main()
Advertisement
Add Comment
Please, Sign In to add comment