This commit is contained in:
Santi 2025-02-18 16:32:28 +01:00
parent 650b20dda5
commit 27d83cc9ad
5 changed files with 70 additions and 96 deletions

View File

@ -23,21 +23,22 @@ class EconomyBitcoinChart:
self.ax_bitcoin = self.figure.add_subplot(212) # Gráfico inferior self.ax_bitcoin = self.figure.add_subplot(212) # Gráfico inferior
# Inicializar datos simulados # Inicializar datos simulados
self.economy_data = [random.randint(50, 100) for _ in range(10)] # Economía en meses self.economy_data = [random.randint(50, 100) for _ in range(10)] # Índice económico en meses
self.bitcoin_data = [random.randint(20000, 60000) for _ in range(10)] # Bitcoin en días self.bitcoin_data = [random.randint(20000, 60000) for _ in range(10)] # Precio del Bitcoin en días
# Dibujar los gráficos iniciales
self.update_economy_chart() self.update_economy_chart()
self.update_bitcoin_chart() self.update_bitcoin_chart()
# Embebiendo los gráficos en Tkinter # Embebiendo los gráficos en la interfaz de Tkinter
self.canvas = FigureCanvasTkAgg(self.figure, master=self.parent) self.canvas = FigureCanvasTkAgg(self.figure, master=self.parent)
self.canvas.get_tk_widget().pack(fill="both", expand=True, padx=10, pady=10) self.canvas.get_tk_widget().pack(fill="both", expand=True, padx=10, pady=10)
# Iniciar hilos para actualizar los gráficos # Iniciar hilos para actualizar los gráficos periódicamente
threading.Thread(target=self.update_charts, daemon=True).start() threading.Thread(target=self.update_charts, daemon=True).start()
def update_economy_chart(self): def update_economy_chart(self):
"""Actualiza el gráfico de economía mundial.""" """Actualiza el gráfico de economía mundial con nuevos datos."""
self.ax_economy.clear() self.ax_economy.clear()
self.ax_economy.plot(self.economy_data, marker="o", color="blue") self.ax_economy.plot(self.economy_data, marker="o", color="blue")
self.ax_economy.set_title("Economía Mundial") self.ax_economy.set_title("Economía Mundial")
@ -45,22 +46,22 @@ class EconomyBitcoinChart:
self.ax_economy.grid(True) self.ax_economy.grid(True)
def update_bitcoin_chart(self): def update_bitcoin_chart(self):
"""Actualiza el gráfico de Bitcoin.""" """Actualiza el gráfico del precio de Bitcoin."""
self.ax_bitcoin.clear() self.ax_bitcoin.clear()
self.ax_bitcoin.plot(self.bitcoin_data, marker="o", color="green") self.ax_bitcoin.plot(self.bitcoin_data, marker="o", color="green")
self.ax_bitcoin.set_title("Precio de Bitcoin") self.ax_bitcoin.set_title("Precio de Bitcoin")
self.ax_bitcoin.set_ylabel("Precio en USD") self.ax_bitcoin.set_ylabel("Precio en USD")
self.ax_bitcoin.set_xlabel("Días") # Etiqueta para los días self.ax_bitcoin.set_xlabel("Días") # Etiqueta del eje X
self.ax_bitcoin.grid(True) self.ax_bitcoin.grid(True)
def update_charts(self): def update_charts(self):
"""Actualiza ambos gráficos periódicamente.""" """Actualiza ambos gráficos con nuevos datos periódicamente."""
while True: while True:
# Actualizar datos simulados # Generar nuevos datos simulados
self.economy_data = self.economy_data[1:] + [random.randint(50, 100)] # Economía en meses self.economy_data = self.economy_data[1:] + [random.randint(50, 100)]
self.bitcoin_data = self.bitcoin_data[1:] + [random.randint(20000, 60000)] # Bitcoin en días self.bitcoin_data = self.bitcoin_data[1:] + [random.randint(20000, 60000)]
# Actualizar gráficos # Redibujar gráficos con los nuevos datos
self.update_economy_chart() self.update_economy_chart()
self.update_bitcoin_chart() self.update_bitcoin_chart()
self.canvas.draw() self.canvas.draw()

View File

@ -10,7 +10,7 @@ DOWNLOAD_FOLDER = "musicplayer"
class MusicDownloader: class MusicDownloader:
def __init__(self, parent): def __init__(self, parent):
""" """
Inicializa la interfaz para descargar música de YouTube en MP3. Inicializa la interfaz gráfica para descargar música de YouTube en formato MP3.
""" """
self.parent = parent self.parent = parent
@ -22,7 +22,7 @@ class MusicDownloader:
title = tk.Label(self.parent, text="Descargar Música MP3", font=("Helvetica", 14, "bold")) title = tk.Label(self.parent, text="Descargar Música MP3", font=("Helvetica", 14, "bold"))
title.pack(pady=10) title.pack(pady=10)
# Entrada para la URL # Campo de entrada para la URL de YouTube
self.url_label = tk.Label(self.parent, text="URL de YouTube:") self.url_label = tk.Label(self.parent, text="URL de YouTube:")
self.url_label.pack(pady=5) self.url_label.pack(pady=5)
self.url_entry = tk.Entry(self.parent, width=50) self.url_entry = tk.Entry(self.parent, width=50)
@ -32,16 +32,16 @@ class MusicDownloader:
self.download_button = tk.Button(self.parent, text="Descargar MP3", command=self.start_download, bg="lightblue") self.download_button = tk.Button(self.parent, text="Descargar MP3", command=self.start_download, bg="lightblue")
self.download_button.pack(pady=10) self.download_button.pack(pady=10)
# Barra de progreso # Barra de progreso de la descarga
self.progress = ttk.Progressbar(self.parent, orient="horizontal", length=300, mode="determinate") self.progress = ttk.Progressbar(self.parent, orient="horizontal", length=300, mode="determinate")
self.progress.pack(pady=10) self.progress.pack(pady=10)
# Etiqueta de estado # Etiqueta de estado para mostrar mensajes
self.status_label = tk.Label(self.parent, text="", font=("Helvetica", 10)) self.status_label = tk.Label(self.parent, text="", font=("Helvetica", 10))
self.status_label.pack(pady=5) self.status_label.pack(pady=5)
def start_download(self): def start_download(self):
"""Inicia la descarga en un hilo separado.""" """Inicia la descarga en un hilo separado para no bloquear la interfaz."""
url = self.url_entry.get() url = self.url_entry.get()
if not url: if not url:
self.status_label.config(text="Por favor, ingrese una URL válida.", fg="red") self.status_label.config(text="Por favor, ingrese una URL válida.", fg="red")
@ -50,11 +50,12 @@ class MusicDownloader:
threading.Thread(target=self.download_music, args=(url,), daemon=True).start() threading.Thread(target=self.download_music, args=(url,), daemon=True).start()
def download_music(self, url): def download_music(self, url):
"""Descarga el audio de YouTube en MP3 usando yt-dlp.""" """Descarga el audio de YouTube en formato MP3 usando `yt-dlp`."""
try: try:
self.status_label.config(text="Descargando...", fg="blue") self.status_label.config(text="Descargando...", fg="blue")
output_template = os.path.join(DOWNLOAD_FOLDER, "%(title)s.%(ext)s") output_template = os.path.join(DOWNLOAD_FOLDER, "%(title)s.%(ext)s")
# Opciones para descargar solo el audio y convertirlo a MP3
ydl_opts = { ydl_opts = {
'format': 'bestaudio/best', 'format': 'bestaudio/best',
'outtmpl': output_template, 'outtmpl': output_template,
@ -71,6 +72,7 @@ class MusicDownloader:
self.status_label.config(text="¡Descarga completada!", fg="green") self.status_label.config(text="¡Descarga completada!", fg="green")
except Exception as e: except Exception as e:
self.status_label.config(text=f"Error: {str(e)}", fg="red") self.status_label.config(text=f"Error: {str(e)}", fg="red")
def update_progress(self, stream, chunk, bytes_remaining): def update_progress(self, stream, chunk, bytes_remaining):
"""Actualiza la barra de progreso durante la descarga.""" """Actualiza la barra de progreso durante la descarga."""
total_size = stream.filesize total_size = stream.filesize

View File

@ -4,33 +4,32 @@ import threading
import mysql.connector import mysql.connector
from mysql.connector import Error from mysql.connector import Error
class SQLQueryExecutor: class SQLQueryExecutor:
def __init__(self, parent): def __init__(self, parent):
""" """
Clase para ejecutar consultas SQL en una base de datos MySQL. Clase que permite ejecutar consultas SQL en una base de datos MySQL.
Args: Args:
parent (tk.Frame): Frame donde se colocarán los widgets. parent (tk.Frame): Frame donde se colocarán los widgets de la interfaz gráfica.
""" """
self.parent = parent self.parent = parent
# Campos para ingresar información de conexión # Frame para ingresar los datos de conexión a la base de datos
self.db_info_frame = tk.Frame(self.parent) self.db_info_frame = tk.Frame(self.parent)
self.db_info_frame.pack(pady=10, padx=10, fill="x") self.db_info_frame.pack(pady=10, padx=10, fill="x")
tk.Label(self.db_info_frame, text="Host:").grid(row=0, column=0, sticky="w") tk.Label(self.db_info_frame, text="Host:").grid(row=0, column=0, sticky="w")
self.host_entry = tk.Entry(self.db_info_frame) self.host_entry = tk.Entry(self.db_info_frame)
self.host_entry.insert(0, "localhost") self.host_entry.insert(0, "localhost") # Valor por defecto
self.host_entry.grid(row=0, column=1) self.host_entry.grid(row=0, column=1)
tk.Label(self.db_info_frame, text="Usuario:").grid(row=1, column=0, sticky="w") tk.Label(self.db_info_frame, text="Usuario:").grid(row=1, column=0, sticky="w")
self.user_entry = tk.Entry(self.db_info_frame) self.user_entry = tk.Entry(self.db_info_frame)
self.user_entry.insert(0, "root") self.user_entry.insert(0, "root") # Usuario por defecto
self.user_entry.grid(row=1, column=1) self.user_entry.grid(row=1, column=1)
tk.Label(self.db_info_frame, text="Contraseña:").grid(row=2, column=0, sticky="w") tk.Label(self.db_info_frame, text="Contraseña:").grid(row=2, column=0, sticky="w")
self.password_entry = tk.Entry(self.db_info_frame, show="*") self.password_entry = tk.Entry(self.db_info_frame, show="*") # Campo oculto
self.password_entry.grid(row=2, column=1) self.password_entry.grid(row=2, column=1)
tk.Label(self.db_info_frame, text="Base de datos:").grid(row=3, column=0, sticky="w") tk.Label(self.db_info_frame, text="Base de datos:").grid(row=3, column=0, sticky="w")
@ -41,7 +40,7 @@ class SQLQueryExecutor:
self.connect_button = tk.Button(self.db_info_frame, text="Conectar", command=self.connect_to_database) self.connect_button = tk.Button(self.db_info_frame, text="Conectar", command=self.connect_to_database)
self.connect_button.grid(row=4, column=0, columnspan=2, pady=5) self.connect_button.grid(row=4, column=0, columnspan=2, pady=5)
# Área para ingresar consultas SQL # Área para escribir la consulta SQL
self.query_frame = tk.Frame(self.parent) self.query_frame = tk.Frame(self.parent)
self.query_frame.pack(pady=10, padx=10, fill="both", expand=True) self.query_frame.pack(pady=10, padx=10, fill="both", expand=True)
@ -49,11 +48,11 @@ class SQLQueryExecutor:
self.query_text = tk.Text(self.query_frame, height=10) self.query_text = tk.Text(self.query_frame, height=10)
self.query_text.pack(fill="both", expand=True) self.query_text.pack(fill="both", expand=True)
# Botón para ejecutar consultas # Botón para ejecutar la consulta
self.execute_button = tk.Button(self.query_frame, text="Ejecutar", command=self.execute_query) self.execute_button = tk.Button(self.query_frame, text="Ejecutar", command=self.execute_query)
self.execute_button.pack(pady=5) self.execute_button.pack(pady=5)
# Área para mostrar resultados # Área para mostrar los resultados
self.result_frame = tk.Frame(self.parent) self.result_frame = tk.Frame(self.parent)
self.result_frame.pack(pady=10, padx=10, fill="both", expand=True) self.result_frame.pack(pady=10, padx=10, fill="both", expand=True)
@ -62,7 +61,7 @@ class SQLQueryExecutor:
self.result_text.pack(fill="both", expand=True) self.result_text.pack(fill="both", expand=True)
def connect_to_database(self): def connect_to_database(self):
"""Conecta a la base de datos utilizando los datos proporcionados.""" """Conecta a la base de datos MySQL utilizando los datos ingresados por el usuario."""
self.host = self.host_entry.get() self.host = self.host_entry.get()
self.user = self.user_entry.get() self.user = self.user_entry.get()
self.password = self.password_entry.get() self.password = self.password_entry.get()
@ -81,7 +80,7 @@ class SQLQueryExecutor:
messagebox.showerror("Error de Conexión", str(e)) messagebox.showerror("Error de Conexión", str(e))
def execute_query(self): def execute_query(self):
"""Ejecuta la consulta SQL en un hilo separado.""" """Ejecuta la consulta SQL en un hilo separado para evitar bloquear la interfaz."""
query = self.query_text.get("1.0", tk.END).strip() query = self.query_text.get("1.0", tk.END).strip()
if not query: if not query:
messagebox.showwarning("Consulta Vacía", "Por favor, ingrese una consulta SQL.") messagebox.showwarning("Consulta Vacía", "Por favor, ingrese una consulta SQL.")
@ -90,7 +89,7 @@ class SQLQueryExecutor:
threading.Thread(target=self.run_query, args=(query,), daemon=True).start() threading.Thread(target=self.run_query, args=(query,), daemon=True).start()
def run_query(self, query): def run_query(self, query):
"""Ejecuta la consulta y muestra los resultados.""" """Ejecuta la consulta en la base de datos y muestra los resultados."""
try: try:
cursor = self.connection.cursor() cursor = self.connection.cursor()
cursor.execute(query) cursor.execute(query)

View File

@ -4,7 +4,6 @@ from tkinter import messagebox
import threading import threading
import random import random
class TicTacToe: class TicTacToe:
def __init__(self, parent): def __init__(self, parent):
""" """
@ -14,19 +13,19 @@ class TicTacToe:
parent (tk.Frame): Frame donde se colocará el juego. parent (tk.Frame): Frame donde se colocará el juego.
""" """
self.parent = parent self.parent = parent
self.board = [""] * 9 # Tablero de 3x3 representado como una lista self.board = [""] * 9 # Representación del tablero 3x3
self.current_player = "X" # Jugador inicial self.current_player = "X" # Jugador que inicia la partida
self.vs_computer = False # Modo jugador vs máquina self.vs_computer = False # Modo jugador vs máquina
# Etiqueta para el título # Título del juego
title = tk.Label(self.parent, text="Tic Tac Toe", font=("Helvetica", 16, "bold")) title = tk.Label(self.parent, text="Tic Tac Toe", font=("Helvetica", 16, "bold"))
title.pack(pady=10) title.pack(pady=10)
# Botón para alternar entre modos # Botón para alternar entre modos de juego
self.mode_button = tk.Button(self.parent, text="Modo: Jugador vs Jugador", command=self.toggle_mode) self.mode_button = tk.Button(self.parent, text="Modo: Jugador vs Jugador", command=self.toggle_mode)
self.mode_button.pack(pady=5) self.mode_button.pack(pady=5)
# Crear el tablero # Crear la cuadrícula del tablero
self.buttons = [] self.buttons = []
self.board_frame = tk.Frame(self.parent) self.board_frame = tk.Frame(self.parent)
self.board_frame.pack() self.board_frame.pack()
@ -38,12 +37,12 @@ class TicTacToe:
font=("Helvetica", 20), font=("Helvetica", 20),
width=5, width=5,
height=2, height=2,
command=self.create_button_command(i) # Aquí usamos la función auxiliar command=self.create_button_command(i)
) )
button.grid(row=i // 3, column=i % 3) button.grid(row=i // 3, column=i % 3)
self.buttons.append(button) self.buttons.append(button)
# Etiqueta para el estado del juego # Mensaje que indica el turno del jugador
self.status_label = tk.Label(self.parent, text="Turno: X", font=("Helvetica", 12)) self.status_label = tk.Label(self.parent, text="Turno: X", font=("Helvetica", 12))
self.status_label.pack(pady=5) self.status_label.pack(pady=5)
@ -55,7 +54,7 @@ class TicTacToe:
self.reset_game() self.reset_game()
def reset_game(self): def reset_game(self):
"""Reinicia el tablero y el estado del juego.""" """Reinicia el juego a su estado inicial."""
self.board = [""] * 9 self.board = [""] * 9
self.current_player = "X" self.current_player = "X"
for button in self.buttons: for button in self.buttons:
@ -63,12 +62,11 @@ class TicTacToe:
self.status_label.config(text="Turno: X") self.status_label.config(text="Turno: X")
def make_move(self, index): def make_move(self, index):
"""Realiza un movimiento en el tablero.""" """Registra un movimiento y actualiza el tablero."""
if self.board[index] == "": if self.board[index] == "":
self.board[index] = self.current_player self.board[index] = self.current_player
self.buttons[index].config(text=self.current_player) self.buttons[index].config(text=self.current_player)
# Verificar si hay un ganador
winner = self.check_winner() winner = self.check_winner()
if winner: if winner:
self.end_game(f"¡Ganador: {winner}!") self.end_game(f"¡Ganador: {winner}!")
@ -77,28 +75,11 @@ class TicTacToe:
self.end_game("¡Empate!") self.end_game("¡Empate!")
return return
# Cambiar de jugador
self.current_player = "O" if self.current_player == "X" else "X" self.current_player = "O" if self.current_player == "X" else "X"
self.status_label.config(text=f"Turno: {self.current_player}") self.status_label.config(text=f"Turno: {self.current_player}")
# Si está en modo Jugador vs Máquina y es el turno de la máquina
if self.vs_computer and self.current_player == "O":
threading.Thread(target=self.computer_move).start()
def computer_move(self):
"""Simula el movimiento de la máquina."""
self.status_label.config(text="Turno: Máquina (O)")
available_moves = [i for i, v in enumerate(self.board) if v == ""]
move = random.choice(available_moves)
def delayed_move():
time.sleep(1) # Simular el tiempo de "pensar"
self.make_move(move)
threading.Thread(target=delayed_move).start()
def check_winner(self): def check_winner(self):
"""Verifica si hay un ganador.""" """Verifica si hay un ganador en el juego."""
winning_combinations = [ winning_combinations = [
(0, 1, 2), (3, 4, 5), (6, 7, 8), # Filas (0, 1, 2), (3, 4, 5), (6, 7, 8), # Filas
(0, 3, 6), (1, 4, 7), (2, 5, 8), # Columnas (0, 3, 6), (1, 4, 7), (2, 5, 8), # Columnas
@ -108,16 +89,3 @@ class TicTacToe:
if self.board[a] == self.board[b] == self.board[c] and self.board[a] != "": if self.board[a] == self.board[b] == self.board[c] and self.board[a] != "":
return self.board[a] return self.board[a]
return None return None
def end_game(self, message):
"""Finaliza el juego mostrando un mensaje."""
messagebox.showinfo("Fin del Juego", message)
self.reset_game()
def create_button_command(self, index):
"""Crea un comando para un botón con un índice específico."""
def command():
self.make_move(index)
return command

View File

@ -9,52 +9,59 @@ from tkinter import messagebox
class WebScraperToDB: class WebScraperToDB:
def __init__(self, parent): def __init__(self, parent):
""" """
Inicializa el widget de scraping con integración a base de datos. Inicializa la interfaz gráfica para scraping web con integración a base de datos.
Args:
parent (tk.Frame): Contenedor en el que se mostrará la interfaz gráfica.
""" """
self.parent = parent self.parent = parent
self.scraping_thread = None self.scraping_thread = None # Hilo que ejecutará el scraping
self.stop_event = threading.Event() self.stop_event = threading.Event() # Evento para detener el scraping
# Crear campos de conexión para la base de datos # Crear la sección de conexión a la base de datos
db_frame = tk.Frame(self.parent) db_frame = tk.Frame(self.parent)
db_frame.pack(pady=5) db_frame.pack(pady=5)
# Campos de entrada para la conexión a MySQL
tk.Label(db_frame, text="Host:").grid(row=0, column=0) tk.Label(db_frame, text="Host:").grid(row=0, column=0)
self.host_entry = tk.Entry(db_frame) self.host_entry = tk.Entry(db_frame)
self.host_entry.insert(0, "localhost") self.host_entry.insert(0, "localhost") # Valor predeterminado
self.host_entry.grid(row=0, column=1) self.host_entry.grid(row=0, column=1)
tk.Label(db_frame, text="Usuario:").grid(row=1, column=0) tk.Label(db_frame, text="Usuario:").grid(row=1, column=0)
self.user_entry = tk.Entry(db_frame) self.user_entry = tk.Entry(db_frame)
self.user_entry.insert(0, "root") self.user_entry.insert(0, "root") # Usuario predeterminado
self.user_entry.grid(row=1, column=1) self.user_entry.grid(row=1, column=1)
tk.Label(db_frame, text="Contraseña:").grid(row=2, column=0) tk.Label(db_frame, text="Contraseña:").grid(row=2, column=0)
self.password_entry = tk.Entry(db_frame, show="*") self.password_entry = tk.Entry(db_frame, show="*") # Campo oculto para seguridad
self.password_entry.grid(row=2, column=1) self.password_entry.grid(row=2, column=1)
tk.Label(db_frame, text="Nombre BD:").grid(row=3, column=0) tk.Label(db_frame, text="Nombre BD:").grid(row=3, column=0)
self.database_entry = tk.Entry(db_frame) self.database_entry = tk.Entry(db_frame)
self.database_entry.insert(0, "scraping_db") self.database_entry.insert(0, "scraping_db") # Base de datos predeterminada
self.database_entry.grid(row=3, column=1) self.database_entry.grid(row=3, column=1)
# Botón para crear la base de datos
tk.Button(db_frame, text="Crear Base de Datos", command=self.create_database).grid(row=4, column=0, columnspan=2, pady=5) tk.Button(db_frame, text="Crear Base de Datos", command=self.create_database).grid(row=4, column=0, columnspan=2, pady=5)
# Área para URL y botones de control # Sección de controles para scraping
control_frame = tk.Frame(self.parent) control_frame = tk.Frame(self.parent)
control_frame.pack(pady=5) control_frame.pack(pady=5)
# Campo de entrada para la URL a scrape
tk.Label(control_frame, text="URL para Scraping:").grid(row=0, column=0) tk.Label(control_frame, text="URL para Scraping:").grid(row=0, column=0)
self.url_entry = tk.Entry(control_frame, width=50) self.url_entry = tk.Entry(control_frame, width=50)
self.url_entry.insert(0, "https://quotes.toscrape.com/") self.url_entry.insert(0, "https://quotes.toscrape.com/") # URL de prueba
self.url_entry.grid(row=0, column=1) self.url_entry.grid(row=0, column=1)
# Campo para Selector HTML # Campo para ingresar el selector HTML
tk.Label(control_frame, text="Selector HTML:").grid(row=2, column=0) tk.Label(control_frame, text="Selector HTML:").grid(row=2, column=0)
self.selector_entry = tk.Entry(control_frame, width=50) self.selector_entry = tk.Entry(control_frame, width=50)
self.selector_entry.insert(0, "h1") # Valor predeterminado self.selector_entry.insert(0, "h1") # Selector predeterminado
self.selector_entry.grid(row=2, column=1) self.selector_entry.grid(row=2, column=1)
# Botones de control
self.start_button = tk.Button(control_frame, text="Iniciar Scraping", command=self.start_scraping) self.start_button = tk.Button(control_frame, text="Iniciar Scraping", command=self.start_scraping)
self.start_button.grid(row=1, column=0, pady=5) self.start_button.grid(row=1, column=0, pady=5)
@ -64,7 +71,7 @@ class WebScraperToDB:
self.reset_button = tk.Button(control_frame, text="Resetear Scraping", command=self.reset_database) self.reset_button = tk.Button(control_frame, text="Resetear Scraping", command=self.reset_database)
self.reset_button.grid(row=1, column=2, pady=5) self.reset_button.grid(row=1, column=2, pady=5)
# Área para mostrar el estado # Etiqueta para mostrar el estado del scraping
self.status_label = tk.Label(self.parent, text="Estado: Inactivo", fg="red") self.status_label = tk.Label(self.parent, text="Estado: Inactivo", fg="red")
self.status_label.pack(pady=5) self.status_label.pack(pady=5)
@ -78,7 +85,7 @@ class WebScraperToDB:
self.scraped_data_text.pack(fill="both", expand=True) self.scraped_data_text.pack(fill="both", expand=True)
def create_database(self): def create_database(self):
"""Crea la base de datos y la tabla para almacenar datos de scraping.""" """Crea la base de datos y la tabla para almacenar los datos de scraping."""
try: try:
connection = mysql.connector.connect( connection = mysql.connector.connect(
host=self.host_entry.get(), host=self.host_entry.get(),
@ -119,9 +126,7 @@ class WebScraperToDB:
selector = self.selector_entry.get() selector = self.selector_entry.get()
try: try:
headers = { headers = {"User-Agent": "Mozilla/5.0"}
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36"
}
connection = mysql.connector.connect( connection = mysql.connector.connect(
host=self.host_entry.get(), host=self.host_entry.get(),
user=self.user_entry.get(), user=self.user_entry.get(),
@ -134,7 +139,7 @@ class WebScraperToDB:
response = requests.get(url, headers=headers) response = requests.get(url, headers=headers)
soup = BeautifulSoup(response.text, "html.parser") soup = BeautifulSoup(response.text, "html.parser")
# Busca elementos según el selector ingresado por el usuario # Busca elementos en la página usando el selector proporcionado
elements = soup.select(selector) elements = soup.select(selector)
if not elements: if not elements:
self.status_label.config(text="Estado: Sin datos encontrados.", fg="orange") self.status_label.config(text="Estado: Sin datos encontrados.", fg="orange")
@ -143,9 +148,9 @@ class WebScraperToDB:
for element in elements: for element in elements:
title_text = element.get_text(strip=True) title_text = element.get_text(strip=True)
link = element.get("href", "Sin enlace") # Asegúrate de que el selector apunte a elementos <a> link = element.get("href", "Sin enlace") # Extrae el enlace si está disponible
# Insertar en la base de datos # Insertar datos en la base de datos
cursor.execute("INSERT INTO scraped_data (title, link) VALUES (%s, %s)", (title_text, link)) cursor.execute("INSERT INTO scraped_data (title, link) VALUES (%s, %s)", (title_text, link))
connection.commit() connection.commit()
@ -157,8 +162,7 @@ class WebScraperToDB:
self.status_label.config(text=f"Estado: Scrapeando {title_text}...", fg="green") self.status_label.config(text=f"Estado: Scrapeando {title_text}...", fg="green")
# Pausa entre iteraciones time.sleep(5) # Pausa entre iteraciones
time.sleep(5)
connection.close() connection.close()
self.status_label.config(text="Estado: Inactivo", fg="red") self.status_label.config(text="Estado: Inactivo", fg="red")
@ -173,7 +177,7 @@ class WebScraperToDB:
self.stop_button.config(state="disabled") self.stop_button.config(state="disabled")
def reset_database(self): def reset_database(self):
"""Elimina todos los datos de la tabla.""" """Elimina todos los datos de la tabla scraped_data."""
try: try:
connection = mysql.connector.connect( connection = mysql.connector.connect(
host=self.host_entry.get(), host=self.host_entry.get(),