En este momento estás viendo Extraer favicons de sitios web con Python

Extraer favicons de sitios web con Python

  • Autor de la entrada:
  • Categoría de la entrada:Python
  • Comentarios de la entrada:Sin comentarios
Tiempo de lectura estimado: 4 minutos

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()

 

SernaStd

Desarrollador web y software. Amante del diseño gráfico, diseño 3D y la locura!. Café y manos, son cosas que han de ir unidas. ¡No pongas fronteras en tus proyectos!.

Deja una respuesta