|
| 1 | +import tkinter as tk |
| 2 | +from tkinter import ttk, filedialog, simpledialog |
| 3 | +import requests |
| 4 | +import socket as _socket |
| 5 | +from urllib.request import urlopen |
| 6 | +import csv |
| 7 | +import threading |
| 8 | +from concurrent.futures import ThreadPoolExecutor |
| 9 | +import feedparser |
| 10 | +import re |
| 11 | +import socks |
| 12 | +from requests.adapters import HTTPAdapter |
| 13 | +from urllib3.util.retry import Retry |
| 14 | +from tkinter.ttk import Progressbar |
| 15 | +from queue import Queue |
| 16 | +from tkinter import StringVar |
| 17 | +from tkinter import IntVar |
| 18 | +import concurrent |
| 19 | + |
| 20 | + |
| 21 | +class ProxyAdapter(HTTPAdapter): |
| 22 | + def __init__(self, proxy, *args, **kwargs): |
| 23 | + self.proxy = proxy |
| 24 | + super(ProxyAdapter, self).__init__(*args, **kwargs) |
| 25 | + |
| 26 | + def send(self, request, stream=False, timeout=None, verify=True, cert=None): |
| 27 | + request.proxies = { |
| 28 | + 'http': self.proxy, |
| 29 | + 'https': self.proxy |
| 30 | + } |
| 31 | + return super(ProxyAdapter, self).send(request, stream=stream, timeout=timeout, verify=verify, cert=cert) |
| 32 | + |
| 33 | + |
| 34 | +class ProxyChecker: |
| 35 | + def __init__(self): |
| 36 | + self.window = tk.Tk() |
| 37 | + self.window.title("Proxy Checker") |
| 38 | + self.status_text = tk.StringVar() |
| 39 | + self.status_text.set("Ready") |
| 40 | + self.progress_queue = Queue() |
| 41 | + self.stop_check = threading.Event() |
| 42 | + self.proxies = [] |
| 43 | + self.find_valid_proxies_var = IntVar() |
| 44 | + self.find_valid_proxies_var.trace( |
| 45 | + "w", self.update_check_proxies_button) |
| 46 | + self.create_widgets() |
| 47 | + |
| 48 | + def update_check_proxies_button(self, *args): |
| 49 | + if self.find_valid_proxies_var.get() or self.proxies: |
| 50 | + # Make button visible |
| 51 | + self.check_button.grid( |
| 52 | + row=4, column=2, columnspan=2, padx=10, pady=10) |
| 53 | + self.check_button.config(state='normal') |
| 54 | + else: |
| 55 | + self.check_button.grid( |
| 56 | + row=4, column=2, columnspan=2, padx=10, pady=10) |
| 57 | + self.check_button.config(state='disabled') |
| 58 | + |
| 59 | + def update_status_label(self, *args): |
| 60 | + self.status_label.config(text=self.status_text.get()) |
| 61 | + |
| 62 | + def update_progress_bar(self, increment=1): |
| 63 | + self.progress_bar["value"] += increment |
| 64 | + self.progress_bar.update_idletasks() |
| 65 | + |
| 66 | + def create_widgets(self): |
| 67 | + style = ttk.Style() |
| 68 | + style.configure('TButton', font=('Helvetica', 10)) |
| 69 | + style.configure('TLabel', font=('Helvetica', 10)) |
| 70 | + style.configure('TEntry', font=('Helvetica', 10)) |
| 71 | + |
| 72 | + # Load Proxies button |
| 73 | + |
| 74 | + self.load_button = ttk.Button( |
| 75 | + self.window, text="Browse Proxy File", command=self.load_proxies) |
| 76 | + self.load_button.grid(row=0, column=0, padx=10, pady=10, sticky='w') |
| 77 | + |
| 78 | + # URL label and entry |
| 79 | + self.url_label = ttk.Label(self.window, text="URL:") |
| 80 | + self.url_label.grid(row=1, column=0, padx=10, sticky='w') |
| 81 | + |
| 82 | + self.url_entry = ttk.Entry(self.window) |
| 83 | + self.url_entry.grid(row=1, column=1, padx=10, pady=10, sticky='w') |
| 84 | + |
| 85 | + # Load Proxies from URL button |
| 86 | + self.load_url_button = ttk.Button( |
| 87 | + self.window, text="Load Proxies from URL", command=self.start_load_proxies_from_url) |
| 88 | + self.load_url_button.grid( |
| 89 | + row=1, column=2, padx=10, pady=10, sticky='w') |
| 90 | + |
| 91 | + # Stop button |
| 92 | + self.stop_button = ttk.Button( |
| 93 | + self.window, text="STOP", command=self.stop_check_proxies, state='disabled') |
| 94 | + self.stop_button.grid(row=2, column=1, padx=10, pady=10, sticky='w') |
| 95 | + |
| 96 | + # Status label |
| 97 | + self.status_label = ttk.Label( |
| 98 | + self.window, textvariable=self.status_text) |
| 99 | + self.status_label.grid(row=7, column=0, padx=10, pady=10, sticky='w') |
| 100 | + |
| 101 | + # Proxy Type label and combobox |
| 102 | + self.proxy_type_label = ttk.Label(self.window, text="Proxy Type:") |
| 103 | + self.proxy_type_label.grid( |
| 104 | + row=3, column=1, padx=10, pady=10, sticky='w') |
| 105 | + |
| 106 | + self.proxy_type_var = StringVar() |
| 107 | + self.proxy_type_combobox = ttk.Combobox( |
| 108 | + self.window, textvariable=self.proxy_type_var, state='readonly') |
| 109 | + self.proxy_type_combobox['values'] = ( |
| 110 | + 'All', 'HTTP', 'HTTPS', 'SOCKS4', 'SOCKS5') |
| 111 | + self.proxy_type_combobox.current(0) |
| 112 | + self.proxy_type_combobox.grid( |
| 113 | + row=3, column=2, padx=10, pady=10, sticky='w') |
| 114 | + |
| 115 | + # Check Proxies button |
| 116 | + self.check_button = ttk.Button( |
| 117 | + self.window, text="Check Proxies", command=self.start_check_proxies, state='disabled') |
| 118 | + self.check_button.grid(row=4, column=2, padx=10, pady=10, sticky='w') |
| 119 | + |
| 120 | + # Find Valid Proxies checkbox |
| 121 | + self.find_valid_proxies_checkbox = ttk.Checkbutton( |
| 122 | + self.window, text="Find Valid Proxies", variable=self.find_valid_proxies_var) |
| 123 | + self.find_valid_proxies_checkbox.grid( |
| 124 | + row=4, column=1, padx=10, pady=10, sticky='w') |
| 125 | + |
| 126 | + # Valid Proxies label and text box |
| 127 | + self.output_label = ttk.Label(self.window, text="Valid Proxies:") |
| 128 | + self.output_label.grid(row=4, column=0, padx=10, pady=10, sticky='w') |
| 129 | + |
| 130 | + self.output_text = tk.Text( |
| 131 | + self.window, wrap=tk.WORD, width=60, height=10) |
| 132 | + self.output_text.grid(row=5, column=0, padx=10, |
| 133 | + pady=10, columnspan=3, sticky='w') |
| 134 | + |
| 135 | + # Export buttons |
| 136 | + self.export_txt_button = ttk.Button( |
| 137 | + self.window, text="Export as TXT", command=self.export_txt, state='disabled') |
| 138 | + self.export_txt_button.grid( |
| 139 | + row=6, column=0, padx=10, pady=10, sticky='w') |
| 140 | + self.export_csv_button = ttk.Button( |
| 141 | + self.window, text="Export as CSV", command=self.export_csv, state='disabled') |
| 142 | + self.export_csv_button.grid( |
| 143 | + row=6, column=1, padx=10, pady=10, sticky='w') |
| 144 | + |
| 145 | + # Progress bar |
| 146 | + self.progress_bar = ttk.Progressbar(self.window, mode="determinate") |
| 147 | + self.progress_bar.grid(row=3, column=0, padx=10, |
| 148 | + pady=10, sticky='w', columnspan=3) |
| 149 | + |
| 150 | + def load_proxies_from_url(self): |
| 151 | + url = self.url_entry.get() |
| 152 | + self.check_button.config(state='disabled') |
| 153 | + if not url: |
| 154 | + self.status_text.set("URL is empty.") |
| 155 | + self.load_url_button.config(state='normal') |
| 156 | + return |
| 157 | + |
| 158 | + try: |
| 159 | + if url.endswith('.txt'): |
| 160 | + response = requests.get(url) |
| 161 | + response.raise_for_status() |
| 162 | + content = response.text |
| 163 | + else: |
| 164 | + feed = feedparser.parse(url) |
| 165 | + if all('content' in entry for entry in feed.entries): |
| 166 | + content = '\n'.join( |
| 167 | + entry.content[0].value for entry in feed.entries) |
| 168 | + else: |
| 169 | + content = '\n'.join( |
| 170 | + entry.summary for entry in feed.entries if 'summary' in entry) |
| 171 | + |
| 172 | + proxies = self.extract_proxies_from_text(content) |
| 173 | + |
| 174 | + if self.proxies: |
| 175 | + self.check_button.config(state='normal') |
| 176 | + self.status_text.set(f"Loaded {len(self.proxies)} proxies") |
| 177 | + else: |
| 178 | + self.status_text.set("No proxies found.") |
| 179 | + except Exception as e: |
| 180 | + self.status_text.set(f"Error: {str(e)}") |
| 181 | + |
| 182 | + finally: |
| 183 | + self.load_url_button.config(state='normal') |
| 184 | + |
| 185 | + def extract_proxies_from_text(self, text): |
| 186 | + proxies = [] |
| 187 | + lines = text.splitlines() |
| 188 | + for line in lines: |
| 189 | + matches = re.findall(r'\b(?:\d{1,3}\.){3}\d{1,3}\:\d{1,5}\b', line) |
| 190 | + proxies.extend(matches) |
| 191 | + return proxies |
| 192 | + |
| 193 | + def load_proxies(self): |
| 194 | + choice = filedialog.askopenfilename( |
| 195 | + title="Select a file or cancel to enter proxies manually", filetypes=[("Text files", "*.txt")]) |
| 196 | + |
| 197 | + self.check_button.config(state='disabled') |
| 198 | + if choice: |
| 199 | + with open(choice, "r") as file: |
| 200 | + self.proxies = file.read().splitlines() |
| 201 | + else: |
| 202 | + self.proxies = self.window.tk.splitlist(tk.simpledialog.askstring( |
| 203 | + "Enter proxies", "Enter proxies separated by commas:\nExample: 127.0.0.1:8080,127.0.0.1:8081")) |
| 204 | + |
| 205 | + if self.proxies: |
| 206 | + self.check_button.config(state='normal') |
| 207 | + self.status_text.set(f"Loaded {len(self.proxies)} proxies") |
| 208 | + |
| 209 | + def check_proxies(self): |
| 210 | + self.window.after_idle(self.status_text.set, "Checking proxies...") |
| 211 | + |
| 212 | + self.valid_proxies = self.test_proxies(self.proxies) |
| 213 | + |
| 214 | + self.output_text.delete(1.0, tk.END) |
| 215 | + self.output_text.insert(tk.END, "\n".join(self.valid_proxies)) |
| 216 | + |
| 217 | + if self.valid_proxies: |
| 218 | + self.export_txt_button.config(state='normal') |
| 219 | + self.export_csv_button.config(state='normal') |
| 220 | + else: |
| 221 | + self.export_txt_button.config(state='disabled') |
| 222 | + self.export_csv_button.config(state='disabled') |
| 223 | + |
| 224 | + self.window.after_idle(self.check_button.config, state='normal') |
| 225 | + self.window.after_idle(self.load_button.config, state='normal') |
| 226 | + self.window.after_idle(self.stop_button.config, state='disabled') |
| 227 | + self.status_text.set( |
| 228 | + f"Checked proxies. {len(self.valid_proxies)} valid proxies found.") |
| 229 | + self.update_status_label() |
| 230 | + |
| 231 | + def toggle_check_proxies_button(self): |
| 232 | + if self.find_valid_proxies_var.get(): |
| 233 | + self.check_button.config(state='disabled') |
| 234 | + else: |
| 235 | + if self.proxies: |
| 236 | + self.check_button.config(state='normal') |
| 237 | + else: |
| 238 | + self.check_button.config(state='disabled') |
| 239 | + |
| 240 | + def fetch_and_validate_proxies(self): |
| 241 | + self.window.after_idle(self.status_text.set, |
| 242 | + "Fetching proxies from the internet...") |
| 243 | + proxy_type = self.proxy_type_var.get() |
| 244 | + proxy_type = proxy_type.lower() if proxy_type != 'All' else 'http' |
| 245 | + |
| 246 | + try: |
| 247 | + url = f'https://api.proxyscrape.com/v2/?request=displayproxies&protocol=http&timeout=10000&country=all&ssl=all&anonymity=all' |
| 248 | + response = requests.get(url) |
| 249 | + response.raise_for_status() |
| 250 | + proxies = response.text.splitlines() |
| 251 | + self.proxies = proxies |
| 252 | + self.status_text.set( |
| 253 | + f"Found {len(proxies)} proxies from the internet. Checking...") |
| 254 | + self.check_proxies() |
| 255 | + except Exception as e: |
| 256 | + # self.status_text.set(f"Error fetching proxies: {str(e)}") |
| 257 | + self.check_button.config(state='normal') |
| 258 | + self.load_button.config(state='normal') |
| 259 | + self.stop_button.config(state='disabled') |
| 260 | + |
| 261 | + def start_check_proxies(self): |
| 262 | + self.stop_check.clear() |
| 263 | + self.check_button.config(state='disabled') |
| 264 | + self.load_button.config(state='disabled') |
| 265 | + self.stop_button.config(state='normal') |
| 266 | + self.stop_check.clear() |
| 267 | + |
| 268 | + if self.find_valid_proxies_var.get(): |
| 269 | + check_thread = threading.Thread( |
| 270 | + target=self.fetch_and_validate_proxies) |
| 271 | + else: |
| 272 | + check_thread = threading.Thread(target=self.check_proxies) |
| 273 | + |
| 274 | + check_thread.start() |
| 275 | + |
| 276 | + def stop_check_proxies(self): |
| 277 | + self.stop_check.set() |
| 278 | + |
| 279 | + def is_proxy_valid(self, proxy): |
| 280 | + if self.stop_check.is_set(): |
| 281 | + return False |
| 282 | + |
| 283 | + proxy_url = f"http://{proxy}" |
| 284 | + proxy_type = self.proxy_type_var.get() |
| 285 | + |
| 286 | + if proxy_type in ('All', 'HTTP', 'HTTPS'): |
| 287 | + session = requests.Session() |
| 288 | + session.mount('http://', ProxyAdapter(proxy_url)) |
| 289 | + session.mount('https://', ProxyAdapter(proxy_url)) |
| 290 | + retry_strategy = Retry( |
| 291 | + total=3, |
| 292 | + backoff_factor=1, |
| 293 | + status_forcelist=[429, 500, 502, 503, 504], |
| 294 | + allowed_methods=["HEAD", "GET", "OPTIONS"] |
| 295 | + ) |
| 296 | + session.mount("https://", HTTPAdapter(max_retries=retry_strategy)) |
| 297 | + |
| 298 | + try: |
| 299 | + response = session.get("https://httpbin.org/ip", timeout=5) |
| 300 | + if response.status_code == 200: |
| 301 | + # self.status_text.set( |
| 302 | + # f"Testing: {proxy} - Valid (HTTP/HTTPS)") |
| 303 | + return True |
| 304 | + except Exception: |
| 305 | + pass |
| 306 | + |
| 307 | + if proxy_type in ('All', 'SOCKS4', 'SOCKS5'): |
| 308 | + proxy_ip, proxy_port = proxy.split(":") |
| 309 | + socks_types = [socks.SOCKS4, socks.SOCKS5] if proxy_type == 'All' else [ |
| 310 | + getattr(socks, proxy_type)] |
| 311 | + |
| 312 | + for socks_type in socks_types: |
| 313 | + original_socket = _socket.socket |
| 314 | + socks.set_default_proxy(socks_type, proxy_ip, int(proxy_port)) |
| 315 | + _socket.socket = socks.socksocket |
| 316 | + try: |
| 317 | + response = urlopen("https://httpbin.org/ip", timeout=5) |
| 318 | + if response.status == 200: |
| 319 | + # self.status_text.set( |
| 320 | + # f"Testing: {proxy} - Valid (SOCKS{socks_type - socks.SOCKS4 + 4})") |
| 321 | + return True |
| 322 | + except Exception: |
| 323 | + pass |
| 324 | + finally: |
| 325 | + _socket.socket = original_socket |
| 326 | + |
| 327 | + self.progress_queue.put(1) |
| 328 | + # self.status_text.set(f"Testing: {proxy} - Invalid") |
| 329 | + return False |
| 330 | + |
| 331 | + def start_load_proxies_from_url(self): |
| 332 | + self.load_url_button.config(state='disabled') |
| 333 | + self.status_text.set("Loading proxies from URL...") |
| 334 | + load_thread = threading.Thread(target=self.load_proxies_from_url) |
| 335 | + load_thread.start() |
| 336 | + |
| 337 | + def export_txt(self): |
| 338 | + file = filedialog.asksaveasfile(defaultextension=".txt", filetypes=[ |
| 339 | + ("Text files", "*.txt")]) |
| 340 | + if file: |
| 341 | + file.write('\n'.join(self.valid_proxies)) |
| 342 | + file.close() |
| 343 | + |
| 344 | + def export_csv(self): |
| 345 | + file = filedialog.asksaveasfile( |
| 346 | + defaultextension=".csv", filetypes=[("CSV files", "*.csv")]) |
| 347 | + if file: |
| 348 | + writer = csv.writer(file) |
| 349 | + for proxy in self.valid_proxies: |
| 350 | + writer.writerow([proxy]) |
| 351 | + file.close() |
| 352 | + |
| 353 | + def get_anonymity_level(self, proxy): |
| 354 | + try: |
| 355 | + with requests.get(self.test_url, proxies={"http": proxy, "https": proxy}, timeout=self.timeout) as response: |
| 356 | + headers = response.headers |
| 357 | + via_header = headers.get("Via") |
| 358 | + x_forwarded_for_header = headers.get("X-Forwarded-For") |
| 359 | + |
| 360 | + if not via_header and not x_forwarded_for_header: |
| 361 | + return "elite" |
| 362 | + elif via_header and x_forwarded_for_header: |
| 363 | + return "anonymous" |
| 364 | + else: |
| 365 | + return "transparent" |
| 366 | + except Exception as e: |
| 367 | + return None |
| 368 | + |
| 369 | + def test_proxies(self, proxies): |
| 370 | + self.progress_bar["maximum"] = len(proxies) |
| 371 | + self.progress_bar["value"] = 0 |
| 372 | + valid_proxies = [] |
| 373 | + with ThreadPoolExecutor() as executor: |
| 374 | + for proxy, valid in zip(proxies, executor.map(self.is_proxy_valid, proxies)): |
| 375 | + if valid: |
| 376 | + valid_proxies.append(proxy) |
| 377 | + self.output_text.insert(tk.END, proxy + "\n") |
| 378 | + # Add this line to auto-scroll |
| 379 | + self.output_text.see(tk.END) |
| 380 | + self.update_progress_bar(1) |
| 381 | + self.progress_bar["value"] = len(valid_proxies) |
| 382 | + return valid_proxies |
| 383 | + |
| 384 | + def run(self): |
| 385 | + self.window.mainloop() |
| 386 | + |
| 387 | + |
| 388 | +if __name__ == "__main__": |
| 389 | + app = ProxyChecker() |
| 390 | + app.run() |
0 commit comments