Scrapping - mas README.md

This commit is contained in:
Kevin William Olarte Braun 2024-12-14 23:09:39 +01:00
parent 3b8fff8caa
commit 892852835f
13 changed files with 307 additions and 103 deletions

View File

@ -5,6 +5,7 @@ from models.NetworkingScanner import NetworkScanner
from models.Sniffer import packet_callback, sniff from models.Sniffer import packet_callback, sniff
from models.MusicPlayer import MusicPlayerModel from models.MusicPlayer import MusicPlayerModel
from models.GamblingGameModel import GamblingGameModel from models.GamblingGameModel import GamblingGameModel
from models.ScraperModel import ScraperModel
import tkinter as tk import tkinter as tk
import time import time
import datetime import datetime
@ -21,6 +22,9 @@ class MainController:
self.game_model = GamblingGameModel() self.game_model = GamblingGameModel()
self.roulette_running = False self.roulette_running = False
self.roulette_thread = None self.roulette_thread = None
self.model = ScraperModel() # Modelo para gestionar el scraping
self.scraper_running = False
def connect_events(self): def connect_events(self):
"""Conecta los eventos de la vista con las funciones del controlador.""" """Conecta los eventos de la vista con las funciones del controlador."""
@ -37,6 +41,54 @@ class MainController:
self.view.button_start_roulette.config(command=self.start_roulette) self.view.button_start_roulette.config(command=self.start_roulette)
self.view.button_stop_roulette.config(command=self.stop_roulette) self.view.button_stop_roulette.config(command=self.stop_roulette)
"""Conecta los eventos de la vista con las funciones del controlador."""
self.view.button_start_scraper.config(command=self.start_scraper_thread)
self.view.button_stop_scraper.config(command=self.stop_scraper)
def start_scraper_thread(self):
"""Inicia el scraping en un hilo separado."""
start_url = self.view.entry_scraper_url.get().strip()
if not start_url:
self.view.text_scraper_output.insert("end", "Por favor, introduce una URL válida.\n")
return
self.model.add_url(start_url) # Añadir URL inicial al modelo
self.scraper_running = True
self.view.button_start_scraper.config(state="disabled")
self.view.button_stop_scraper.config(state="normal")
# Iniciar hilo para el scraping
threading.Thread(target=self.run_scraper, daemon=True).start()
def stop_scraper(self):
"""Detiene el scraping."""
self.scraper_running = False
self.view.button_start_scraper.config(state="normal")
self.view.button_stop_scraper.config(state="disabled")
self.view.text_scraper_output.insert("end", "Scraper detenido.\n")
def run_scraper(self):
"""Ejecuta el scraping y actualiza la interfaz con los resultados."""
while self.scraper_running and self.model.has_pending_urls():
current_url, result = self.model.scrape_next_url()
if isinstance(result, str): # Error
self.view.text_scraper_output.insert("end", f"{result}\n")
else: # Éxito
self.view.text_scraper_output.insert("end", f"Explorando: {current_url}\n")
for link in result:
self.view.text_scraper_output.insert("end", f" - {link}\n")
self.view.text_scraper_output.see("end")
time.sleep(1) # Retardo para evitar sobrecarga
self.scraper_running = False
self.view.text_scraper_output.insert("end", "Scraping completado.\n")
self.view.button_start_scraper.config(state="normal")
self.view.button_stop_scraper.config(state="disabled")
def start_sniffer_thread(self): def start_sniffer_thread(self):
"""Inicia el sniffer en un hilo separado.""" """Inicia el sniffer en un hilo separado."""

View File

@ -38,6 +38,8 @@ class MainView:
self.create_status_bar() self.create_status_bar()
self.create_music_player() self.create_music_player()
self.create_scraper_ui()
def create_tabs(self): def create_tabs(self):
"""Crea las solapas dentro del notebook.""" """Crea las solapas dentro del notebook."""
@ -189,3 +191,27 @@ class MainView:
self.result_label = ttk.Label(tab, text="", font=("Arial", 12), foreground="blue") self.result_label = ttk.Label(tab, text="", font=("Arial", 12), foreground="blue")
self.result_label.pack(pady=10) self.result_label.pack(pady=10)
def create_scraper_ui(self):
"""
Crea la interfaz para el scraping:
- Input y botones en el frame_left.
- TextArea de resultados en la Solapa 5.
"""
# --- Input y botones en frame_left ---
tk.Label(self.frame_left, text="URL del Scraper:", bg="lightblue", font=("Arial", 10)).pack(pady=5)
self.entry_scraper_url = tk.Entry(self.frame_left, width=25, font=("Arial", 10))
self.entry_scraper_url.pack(pady=5)
self.button_start_scraper = tk.Button(self.frame_left, text="Iniciar Scraper", font=("Arial", 10))
self.button_start_scraper.pack(pady=5)
self.button_stop_scraper = tk.Button(self.frame_left, text="Detener Scraper", font=("Arial", 10), state="disabled")
self.button_stop_scraper.pack(pady=5)
# --- TextArea en Solapa 5 ---
tab5 = self.notebook.nametowidget(self.notebook.tabs()[4]) # Obtener la solapa 5
tk.Label(tab5, text="Resultados del Scraper", font=("Arial", 12)).pack(pady=5)
self.text_scraper_output = scrolledtext.ScrolledText(tab5, wrap=tk.WORD, height=20, width=80)
self.text_scraper_output.pack(pady=10, padx=10, fill="both", expand=True)

View File

@ -75,6 +75,49 @@ El objetivo principal de este proyecto es implementar tareas distribuidas en dif
--- ---
## 📝 Explicación de las principales funcionalidades
### Solapas (Tabs)
1. **IP Tracker**
- Permite rastrear información sobre una dirección IP, como ubicación, tipo, y más, utilizando la API de ipwhois.io.
- Los resultados se muestran en un área de texto con scroll.
2. **Escaneo de Red**
- Realiza un escaneo de dispositivos conectados a la red local usando la biblioteca `python-nmap`.
- Lista dispositivos encontrados con sus respectivas direcciones IP y MAC.
3. **Sniffer**
- Captura y analiza paquetes de red en tiempo real utilizando `Scapy`.
- Muestra información relevante del paquete, como origen, destino, protocolo y puertos.
- Incluye funcionalidad para iniciar y detener el análisis.
4. **Juego de Azar (Ruleta)**
- Un mini-juego de ruleta donde el usuario puede apostar seleccionando un número del 1 al 10.
- Calcula si el jugador gana o pierde y actualiza el saldo en la interfaz.
5. **Scraper**
- Permite explorar una URL inicial y extraer enlaces relacionados usando `BeautifulSoup`.
- Los resultados se almacenan en una base de datos MongoDB y se muestran en la interfaz en tiempo real.
### Frame Izquierdo
- **Gestión del Scraper:**
- Entrada para la URL inicial del scraping.
- Botones para iniciar y detener la operación.
### Frame Derecho
- **Reproductor de Música:**
- Lista canciones disponibles en una carpeta local.
- Botones para reproducir, detener y actualizar la lista de canciones.
### Barra Inferior (Estado)
- **Indicadores del sistema:**
- Uso de CPU y RAM en tiempo real.
- Velocidad de subida y descarga de red.
- Fecha y hora actualizadas dinámicamente.
---
## 🌍 Contribuciones ## 🌍 Contribuciones
Si deseas contribuir a este proyecto: Si deseas contribuir a este proyecto:
@ -90,12 +133,5 @@ Si deseas contribuir a este proyecto:
## 🎮 Autor ## 🎮 Autor
**Kevin Developer**\ **Kevin Developer**
[GitHub](https://github.com/KevinOlarte1) [GitHub](https://github.com/KevinOlarte1)
---
## 📝 Tutorial
(En este apartado podrás incluir un tutorial detallado para que los usuarios aprendan a utilizar tu proyecto paso a paso.)

Binary file not shown.

63
models/ScraperModel.py Normal file
View File

@ -0,0 +1,63 @@
import requests
from bs4 import BeautifulSoup
from urllib.parse import urljoin
from pymongo import MongoClient
class ScraperModel:
def __init__(self):
self.to_visit = []
self.visited = set()
# Conexión a MongoDB
self.client = MongoClient("mongodb://localhost:27017/")
self.db = self.client["scraping"]
self.collection = self.db["visited_links"]
# Crear índice único para evitar duplicados
self.collection.create_index("url", unique=True)
def add_url(self, url):
"""Añade una URL a la lista de pendientes."""
if url not in self.visited and url not in self.to_visit:
self.to_visit.append(url)
def scrape_next_url(self):
"""Scrapea la siguiente URL."""
if not self.to_visit:
return None, []
current_url = self.to_visit.pop(0)
self.visited.add(current_url)
try:
# Solicitar la URL
response = requests.get(current_url, timeout=10)
response.raise_for_status()
except requests.RequestException as e:
return current_url, f"Error al acceder a {current_url}: {e}"
# Procesar los enlaces encontrados
soup = BeautifulSoup(response.text, 'html.parser')
found_links = []
for link in soup.find_all('a', href=True):
full_url = urljoin(current_url, link['href'])
if full_url not in self.visited and full_url not in self.to_visit:
self.to_visit.append(full_url)
found_links.append(full_url)
# Guardar URL visitada en MongoDB
self.save_to_database(current_url)
return current_url, found_links
def save_to_database(self, url):
"""Guarda la URL visitada en la base de datos."""
try:
self.collection.insert_one({"url": url})
except Exception as e:
print(f"Error al guardar en la base de datos: {e}")
def has_pending_urls(self):
"""Verifica si hay URLs pendientes."""
return bool(self.to_visit)

Binary file not shown.

View File

@ -1,123 +1,150 @@
import tkinter as tk import requests
from tkinter import messagebox from bs4 import BeautifulSoup
import threading from urllib.parse import urljoin
import random from pymongo import MongoClient
import time import time
import tkinter as tk
from tkinter import scrolledtext
import threading
class GamblingGameWithThreads: def setup_database():
"""
Configura la conexión a la base de datos MongoDB y retorna la colección.
"""
client = MongoClient("mongodb://localhost:27017/") # Conectar a MongoDB
db = client["scraping"] # Base de datos llamada 'scraping'
collection = db["visited_links"] # Colección llamada 'visited_links'
# Crear índice único para evitar duplicados
collection.create_index("url", unique=True)
return collection
def insert_visited_link(collection, url):
"""
Inserta una URL visitada en la base de datos.
"""
try:
collection.insert_one({"url": url})
except Exception as e:
print(f"Error al insertar la URL visitada {url}: {e}")
class ScraperApp:
def __init__(self, root): def __init__(self, root):
self.root = root self.root = root
self.root.title("Juego de Azar - Ruleta con Hilos") self.root.title("Scraper de Enlaces con Hilos")
self.root.geometry("400x400") self.root.geometry("800x500")
# Variables del juego # Base de datos MongoDB
self.balance = 100 self.collection = setup_database()
self.roulette_number = None
self.roulette_running = False
self.roulette_thread = None
# Etiqueta de saldo # Variable para detener el scraping
self.balance_label = tk.Label(self.root, text=f"Saldo: $ {self.balance}", font=("Arial", 14)) self.running = False
self.balance_label.pack(pady=10)
# Entrada para la apuesta # Frame para la URL y botón
tk.Label(self.root, text="Tu Apuesta ($):", font=("Arial", 12)).pack() frame_top = tk.Frame(self.root)
self.bet_entry = tk.Entry(self.root, width=10, font=("Arial", 12)) frame_top.pack(pady=10)
self.bet_entry.pack(pady=5)
# Entrada para elegir número tk.Label(frame_top, text="Introduce la URL inicial:", font=("Arial", 12)).pack(side=tk.LEFT, padx=5)
tk.Label(self.root, text="Elige un número (1-10):", font=("Arial", 12)).pack() self.url_entry = tk.Entry(frame_top, width=50, font=("Arial", 12))
self.number_entry = tk.Entry(self.root, width=10, font=("Arial", 12)) self.url_entry.pack(side=tk.LEFT, padx=5)
self.number_entry.pack(pady=5) self.start_button = tk.Button(frame_top, text="Iniciar Scraping", font=("Arial", 12), command=self.start_scraping)
self.start_button.pack(side=tk.LEFT, padx=5)
# Botones de control self.stop_button = tk.Button(frame_top, text="Detener Scraping", font=("Arial", 12), command=self.stop_scraping, state="disabled")
self.start_button = tk.Button(self.root, text="Iniciar Ruleta", font=("Arial", 12), command=self.start_roulette) self.stop_button.pack(side=tk.LEFT, padx=5)
self.start_button.pack(pady=10)
self.stop_button = tk.Button(self.root, text="Detener Ruleta", font=("Arial", 12), state="disabled", command=self.stop_roulette) # TextArea para los resultados
self.stop_button.pack(pady=5) self.result_area = scrolledtext.ScrolledText(self.root, wrap=tk.WORD, font=("Arial", 12), height=20, width=90)
self.result_area.pack(pady=10)
# Resultado del juego def start_scraping(self):
self.result_label = tk.Label(self.root, text="", font=("Arial", 12), fg="blue") """
self.result_label.pack(pady=10) Inicia el scraping en un hilo separado.
"""
# Número de la ruleta en tiempo real start_url = self.url_entry.get().strip()
self.roulette_label = tk.Label(self.root, text="Ruleta: ---", font=("Arial", 16), fg="red") if not start_url:
self.roulette_label.pack(pady=10) self.result_area.insert(tk.END, "Por favor, introduce una URL válida.\n")
def start_roulette(self):
"""Inicia el giro de la ruleta en un hilo."""
if self.roulette_running:
messagebox.showwarning("Advertencia", "La ruleta ya está girando.")
return return
try: self.result_area.insert(tk.END, f"Iniciando scraping desde: {start_url}\n")
bet = int(self.bet_entry.get()) self.result_area.see(tk.END)
chosen_number = int(self.number_entry.get())
except ValueError:
messagebox.showerror("Error", "Por favor, ingresa valores numéricos válidos.")
return
if bet <= 0 or chosen_number < 1 or chosen_number > 10: self.running = True
messagebox.showwarning("Advertencia", "La apuesta debe ser mayor a $0 y elige un número entre 1 y 10.")
return
if bet > self.balance:
messagebox.showwarning("Advertencia", "No tienes suficiente saldo para esta apuesta.")
return
self.bet = bet
self.chosen_number = chosen_number
self.roulette_running = True
self.start_button.config(state="disabled") self.start_button.config(state="disabled")
self.stop_button.config(state="normal") self.stop_button.config(state="normal")
# Crear y arrancar el hilo de la ruleta # Iniciar un hilo para el scraping
self.roulette_thread = threading.Thread(target=self.spin_roulette) self.scraping_thread = threading.Thread(target=self.scrape_links_forever, args=(start_url,))
self.roulette_thread.start() self.scraping_thread.daemon = True # Hilo se detiene cuando la app se cierra
self.scraping_thread.start()
def spin_roulette(self): def stop_scraping(self):
"""Simula el giro continuo de la ruleta.""" """
while self.roulette_running: Detiene el scraping.
self.roulette_number = random.randint(1, 10) """
self.roulette_label.config(text=f"Ruleta: {self.roulette_number}") self.running = False
time.sleep(0.1) self.result_area.insert(tk.END, "Deteniendo scraping...\n")
self.result_area.see(tk.END)
def stop_roulette(self):
"""Detiene la ruleta y evalúa el resultado del juego."""
if not self.roulette_running:
return
self.roulette_running = False
self.start_button.config(state="normal") self.start_button.config(state="normal")
self.stop_button.config(state="disabled") self.stop_button.config(state="disabled")
# Evaluar resultado def scrape_links_forever(self, start_url):
if self.chosen_number == self.roulette_number: """
winnings = self.bet * 2 Scrapea enlaces indefinidamente y guarda solo los visitados en MongoDB.
self.balance += winnings Se ejecuta en un hilo separado.
self.result_label.config(
text=f"¡Ganaste! El número fue {self.roulette_number}. Ganaste $ {winnings}.", Args:
fg="green", start_url (str): URL inicial para comenzar el scraping.
) """
else: to_visit = [start_url] # Lista de URLs por visitar
self.balance -= self.bet visited = set() # Conjunto para evitar bucles
self.result_label.config(
text=f"Perdiste. El número fue {self.roulette_number}. Perdiste $ {self.bet}.",
fg="red",
)
# Actualizar saldo while to_visit and self.running:
self.balance_label.config(text=f"Saldo: $ {self.balance}") current_url = to_visit.pop(0) # Tomar la URL actual de la lista
# Revisar si el jugador se quedó sin saldo if current_url in visited:
if self.balance <= 0: continue
messagebox.showinfo("Juego Terminado", "¡Te quedaste sin saldo! Gracias por jugar.")
self.result_area.insert(tk.END, f"Explorando: {current_url}\n")
self.result_area.see(tk.END)
visited.add(current_url) # Marcar como visitada
try:
# Realizar la solicitud HTTP
response = requests.get(current_url, timeout=10)
response.raise_for_status()
except requests.RequestException as e:
self.result_area.insert(tk.END, f"Error al acceder a {current_url}: {e}\n")
self.result_area.see(tk.END)
continue
# Parsear el contenido HTML
soup = BeautifulSoup(response.text, 'html.parser')
# Encontrar y procesar los enlaces
for link in soup.find_all('a', href=True):
full_url = urljoin(current_url, link['href'])
if full_url not in visited and full_url not in to_visit:
to_visit.append(full_url)
# Insertar la URL visitada en la base de datos
insert_visited_link(self.collection, current_url)
# Retardo para evitar sobrecargar el servidor
time.sleep(1)
# Finalización del scraping
self.result_area.insert(tk.END, "Scraping finalizado.\n")
self.result_area.see(tk.END)
self.start_button.config(state="normal")
self.stop_button.config(state="disabled")
if __name__ == "__main__": if __name__ == "__main__":
root = tk.Tk() root = tk.Tk()
app = GamblingGameWithThreads(root) app = ScraperApp(root)
root.mainloop() root.mainloop()