Proyecto
This commit is contained in:
parent
650b20dda5
commit
27d83cc9ad
|
@ -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()
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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
|
|
|
@ -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(),
|
||||||
|
|
Loading…
Reference in New Issue