Hola!.
Hoy vamos a ver, como descargarnos los favicons de nuestras webs favoritas usando Python y algo más.
import requests import time import json from tkinter import Tk, Button, Label, Scrollbar, filedialog, Canvas, Frame from tkinter import ttk from PIL import Image, ImageTk from io import BytesIO import threading # TODO : ADD NEW URLS from input # Lista de URLs proporcionada websites = [ "https://www.google.com", "https://www.reddit.com", "https://www.yahoo.com", "https://www.amazon.com", "https://www.bbc.com", "https://www.cnn.com", "https://www.msn.com", "https://www.stackoverflow.com", "https://www.medium.com", "https://www.python.org", "https://www.github.com", "https://www.linkedin.com", "https://www.twitter.com", "https://www.facebook.com", "https://www.instagram.com", "https://www.quora.com", "https://www.tumblr.com", "https://www.reuters.com", "https://www.nytimes.com", "https://www.nasa.gov", "https://www.wikihow.com", "https://www.apple.com", "https://www.microsoft.com", "https://www.netflix.com", "https://www.spotify.com", "https://www.soundcloud.com", "https://www.pinterest.com", "https://www.twitch.tv", "https://www.snapchat.com", "https://www.tiktok.com", "https://www.wired.com", "https://www.forbes.com", "https://www.theguardian.com", "https://www.nike.com", "https://www.espn.com", "https://www.dailymotion.com", "https://www.flickr.com", "https://www.tripadvisor.com", "https://www.imdb.com", "https://www.rottentomatoes.com", "https://www.weather.com", "https://www.bing.com", "https://www.etsy.com", "https://www.cnbc.com", "https://www.huffpost.com", "https://www.slate.com", "https://www.politico.com", "https://www.npr.org", "https://www.cbsnews.com", "https://www.businessinsider.es", "https://www.microsoft.com", # Nuevas URLs añadidas "https://www.spotify.com", "https://www.nike.com", "https://www.github.com", "https://www.stackoverflow.com", "https://www.twitch.tv", "https://www.wikipedia.org", "https://www.reddit.com", "https://www.youtube.com", "https://www.bbc.com", "https://www.cnn.com", "https://www.apple.com", "https://www.spotify.com", "https://www.slack.com", "https://www.salesforce.com" ] # Favicon predeterminado en caso de que no se pueda obtener uno default_favicon = Image.new('RGB', (50, 50), color=(73, 109, 137)) # Lista para almacenar los tiempos de descarga download_times = [] # Eventos de control de hilo pause_event = threading.Event() stop_event = threading.Event() # Inicialmente el evento de pausa está configurado pause_event.set() # Función para obtener los favicons def fetch_thumbnail(url): try: response = requests.get(f"https://www.google.com/s2/favicons?domain={url}", timeout=5) response.raise_for_status() img = Image.open(BytesIO(response.content)) img.thumbnail((150, 150)) except requests.exceptions.RequestException: img = default_favicon return img # Función para actualizar la vista cuando se agreguen íconos def update_canvas_scroll_region(icon_canvas): icon_canvas.update_idletasks() # Actualizar el tamaño del contenido icon_canvas.config(scrollregion=icon_canvas.bbox("all")) # Ajustar el área de desplazamiento # Función para agregar íconos y mostrar información relevante def add_thumbnail(url, index, icon_inner_frame, time_table, progress, label_progress, images_to_add, icon_canvas): start_time = time.time() # Inicia el conteo de tiempo img = fetch_thumbnail(url) img = ImageTk.PhotoImage(img) # Convertir la imagen para Tkinter # Añadir el ícono a la interfaz de usuario row = index // 100 # Cambiado para 100íconos por fila column = index % 100 # Cambiado para 100 íconos por fila # Añadir el ícono al canvas con `grid` para alinearlos label = Label(icon_inner_frame, image=img, cursor="hand2", relief="solid", borderwidth=1) label.image = img # Mantener una referencia a la imagen # Añadir a la lista de imágenes que vamos a añadir después images_to_add.append(label) # Colocar los íconos en el layout de la cuadrícula label.grid(row=row, column=column, padx=10, pady=10, sticky="nsew") # Calcular el tiempo de descarga end_time = time.time() elapsed_time = end_time - start_time # Guardar el tiempo en la lista global download_times.append({"url": url, "time": elapsed_time}) # Mostrar el tiempo de descarga en la tabla time_table.insert("", "end", values=(url, f"{elapsed_time:.2f} segundos")) # Actualizar la barra de progreso global progress['value'] = (index + 1) * 100 / len(websites) label_progress.config(text=f"Progreso general: {index + 1}/{len(websites)}") # Actualizar la región de desplazamiento update_canvas_scroll_region(icon_canvas) # Función para manejar la carga asincrónica de los favicons def run_scraping(progress, label_progress, icon_inner_frame, time_table, icon_canvas): images_to_add = [] for index, website in enumerate(websites): if stop_event.is_set(): break # Pausar si el evento de pausa está desactivado pause_event.wait() add_thumbnail(website, index, icon_inner_frame, time_table, progress, label_progress, images_to_add, icon_canvas) # Después de agregar todos los íconos, los mostramos todos juntos icon_inner_frame.update_idletasks() # Cuando la barra de progreso llega al 100% if not stop_event.is_set(): progress['value'] = 100 label_progress.config(text="¡Íconos descargados con éxito! 🎉", fg="#4CAF50", font=("Arial", 12, "bold")) # Función para guardar los tiempos de descarga en un archivo JSON def save_to_json(): file_path = filedialog.asksaveasfilename(defaultextension=".json", filetypes=[("Archivos JSON", "*.json")]) if file_path: with open(file_path, "w") as file: json.dump(download_times, file, indent=4) # Función para pausar el scraping def pause_scraping(): pause_event.clear() label_progress.config(text="Scraping pausado") # Función para reanudar el scraping def resume_scraping(): pause_event.set() label_progress.config(text="Scraping reanudado") # Función para detener el scraping def stop_scraping(): stop_event.set() pause_event.set() # Asegurarse de que no esté bloqueado label_progress.config(text="Scraping detenido") # Función para convertir los íconos a B/N def convert_icons_to_bw(): for label in icon_inner_frame.winfo_children(): img = label.image img = ImageTk.getimage(img).convert("L") # Convertir a escala de grises img = ImageTk.PhotoImage(img) label.config(image=img) label.image = img # Función para guardar los íconos en archivos def download_icons(): for index, website in enumerate(websites): img = fetch_thumbnail(website) img = img.convert("RGB") # Guardar imagen con el nombre de dominio domain_name = website.split("//")[-1].split("/")[0] img.save(f"{domain_name}_favicon.png") # Configuración de la interfaz gráfica de usuario root = Tk() root.title("Scraper de Favicons y Tiempos") root.state('zoomed') # Pone la ventana en pantalla completa # Crear un contenedor centralizado para todo central_frame = ttk.Frame(root) central_frame.pack(padx=20, pady=20, fill="both", expand=True) # Hacer que el contenedor central ocupe todo el espacio disponible central_frame.grid_rowconfigure(0, weight=1) central_frame.grid_columnconfigure(0, weight=1) # Crear un marco para los botones y agregarlo al contenedor central button_frame = ttk.Frame(central_frame) button_frame.grid(row=0, column=0, pady=20, padx=10, sticky="nsew") # Usamos grid con 'sticky' # Configuramos el layout de la columna para que se distribuyan de manera justa pero sin estirarse button_frame.grid_columnconfigure(0, weight=1) button_frame.grid_columnconfigure(1, weight=1) button_frame.grid_columnconfigure(2, weight=1) button_frame.grid_columnconfigure(3, weight=1) button_frame.grid_columnconfigure(4, weight=1) button_frame.grid_columnconfigure(5, weight=1) # Crear botones con configuración adecuada start_button = Button(button_frame, text="Iniciar scraping", command=lambda: threading.Thread(target=run_scraping, args=(progress, label_progress, icon_inner_frame, time_table, icon_canvas)).start(), bg="#4CAF50", fg="white", font=("Arial", 12, "bold"), relief="flat", cursor="hand2") start_button.grid(row=0, column=0, padx=10, pady=5) pause_button = Button(button_frame, text="Pausar scraping", command=pause_scraping, bg="#FFC107", fg="black", font=("Arial", 12, "bold"), relief="flat", cursor="hand2") pause_button.grid(row=0, column=1, padx=10, pady=5) resume_button = Button(button_frame, text="Reanudar scraping", command=resume_scraping, bg="#8BC34A", fg="white", font=("Arial", 12, "bold"), relief="flat", cursor="hand2") resume_button.grid(row=0, column=2, padx=10, pady=5) stop_button = Button(button_frame, text="Detener scraping", command=stop_scraping, bg="#F44336", fg="white", font=("Arial", 12, "bold"), relief="flat", cursor="hand2") stop_button.grid(row=0, column=3, padx=10, pady=5) save_button = Button(button_frame, text="Guardar JSON", command=save_to_json, bg="#2196F3", fg="white", font=("Arial", 12, "bold"), relief="flat", cursor="hand2") save_button.grid(row=0, column=4, padx=10, pady=5) convert_button = Button(button_frame, text="Convertir íconos a B/N", command=convert_icons_to_bw, bg="#9E9E9E", fg="white", font=("Arial", 12, "bold"), relief="flat", cursor="hand2") convert_button.grid(row=0, column=5, padx=10, pady=5) download_button = Button(button_frame, text="Descargar íconos", command=download_icons, bg="#4CAF50", fg="white", font=("Arial", 12, "bold"), relief="flat", cursor="hand2") download_button.grid(row=0, column=6, padx=10, pady=5) # Barra de progreso progress = ttk.Progressbar(central_frame, orient="horizontal", length=500, mode="determinate") progress.grid(row=1, column=0, pady=10) # Etiqueta de progreso label_progress = Label(central_frame, text="Progreso general: 0/0", font=("Arial", 12)) label_progress.grid(row=2, column=0, pady=10) # Crear la tabla para mostrar los tiempos de descarga columns = ("URL", "Tiempo") time_table = ttk.Treeview(central_frame, columns=columns, show="headings", height=20) # Ampliado time_table.heading("URL", text="URL") time_table.heading("Tiempo", text="Tiempo de descarga") time_table.grid(row=3, column=0, padx=20, pady=20) # Crear un Canvas para los íconos y agregar la barra de desplazamiento icon_canvas = Canvas(central_frame) icon_canvas.grid(row=4, column=0, padx=20, pady=20, sticky="nsew") scrollbar = Scrollbar(central_frame, orient="vertical", command=icon_canvas.yview) scrollbar.grid(row=4, column=1, sticky="ns") icon_canvas.config(yscrollcommand=scrollbar.set) # Crear un marco dentro del Canvas para contener los íconos icon_frame = Frame(icon_canvas) icon_canvas.create_window((0, 0), window=icon_frame, anchor="nw") # Marco interior para íconos icon_inner_frame = Frame(icon_frame) icon_inner_frame.grid(row=0, column=0, sticky="nsew") # Configurar la distribución de las columnas dentro del icon_inner_frame for i in range(12): icon_inner_frame.grid_columnconfigure(i, weight=1, uniform="equal") # Igualar el peso de las columnas # Iniciar la ventana root.mainloop()