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.MusicPlayer import MusicPlayerModel
from models.GamblingGameModel import GamblingGameModel
from models.ScraperModel import ScraperModel
import tkinter as tk
import time
import datetime
@ -21,6 +22,9 @@ class MainController:
self.game_model = GamblingGameModel()
self.roulette_running = False
self.roulette_thread = None
self.model = ScraperModel() # Modelo para gestionar el scraping
self.scraper_running = False
def connect_events(self):
"""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_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):
"""Inicia el sniffer en un hilo separado."""

View File

@ -38,6 +38,8 @@ class MainView:
self.create_status_bar()
self.create_music_player()
self.create_scraper_ui()
def create_tabs(self):
"""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.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
Si deseas contribuir a este proyecto:
@ -90,12 +133,5 @@ Si deseas contribuir a este proyecto:
## 🎮 Autor
**Kevin Developer**\
[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.)
**Kevin Developer**
[GitHub](https://github.com/KevinOlarte1)

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
from tkinter import messagebox
import threading
import random
import requests
from bs4 import BeautifulSoup
from urllib.parse import urljoin
from pymongo import MongoClient
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):
self.root = root
self.root.title("Juego de Azar - Ruleta con Hilos")
self.root.geometry("400x400")
self.root.title("Scraper de Enlaces con Hilos")
self.root.geometry("800x500")
# Variables del juego
self.balance = 100
self.roulette_number = None
self.roulette_running = False
self.roulette_thread = None
# Base de datos MongoDB
self.collection = setup_database()
# Etiqueta de saldo
self.balance_label = tk.Label(self.root, text=f"Saldo: $ {self.balance}", font=("Arial", 14))
self.balance_label.pack(pady=10)
# Variable para detener el scraping
self.running = False
# Entrada para la apuesta
tk.Label(self.root, text="Tu Apuesta ($):", font=("Arial", 12)).pack()
self.bet_entry = tk.Entry(self.root, width=10, font=("Arial", 12))
self.bet_entry.pack(pady=5)
# Frame para la URL y botón
frame_top = tk.Frame(self.root)
frame_top.pack(pady=10)
# Entrada para elegir número
tk.Label(self.root, text="Elige un número (1-10):", font=("Arial", 12)).pack()
self.number_entry = tk.Entry(self.root, width=10, font=("Arial", 12))
self.number_entry.pack(pady=5)
tk.Label(frame_top, text="Introduce la URL inicial:", font=("Arial", 12)).pack(side=tk.LEFT, padx=5)
self.url_entry = tk.Entry(frame_top, width=50, font=("Arial", 12))
self.url_entry.pack(side=tk.LEFT, padx=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.start_button = tk.Button(self.root, text="Iniciar Ruleta", font=("Arial", 12), command=self.start_roulette)
self.start_button.pack(pady=10)
self.stop_button = tk.Button(frame_top, text="Detener Scraping", font=("Arial", 12), command=self.stop_scraping, state="disabled")
self.stop_button.pack(side=tk.LEFT, padx=5)
self.stop_button = tk.Button(self.root, text="Detener Ruleta", font=("Arial", 12), state="disabled", command=self.stop_roulette)
self.stop_button.pack(pady=5)
# TextArea para los resultados
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
self.result_label = tk.Label(self.root, text="", font=("Arial", 12), fg="blue")
self.result_label.pack(pady=10)
# Número de la ruleta en tiempo real
self.roulette_label = tk.Label(self.root, text="Ruleta: ---", font=("Arial", 16), fg="red")
self.roulette_label.pack(pady=10)
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.")
def start_scraping(self):
"""
Inicia el scraping en un hilo separado.
"""
start_url = self.url_entry.get().strip()
if not start_url:
self.result_area.insert(tk.END, "Por favor, introduce una URL válida.\n")
return
try:
bet = int(self.bet_entry.get())
chosen_number = int(self.number_entry.get())
except ValueError:
messagebox.showerror("Error", "Por favor, ingresa valores numéricos válidos.")
return
self.result_area.insert(tk.END, f"Iniciando scraping desde: {start_url}\n")
self.result_area.see(tk.END)
if bet <= 0 or chosen_number < 1 or chosen_number > 10:
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.running = True
self.start_button.config(state="disabled")
self.stop_button.config(state="normal")
# Crear y arrancar el hilo de la ruleta
self.roulette_thread = threading.Thread(target=self.spin_roulette)
self.roulette_thread.start()
# Iniciar un hilo para el scraping
self.scraping_thread = threading.Thread(target=self.scrape_links_forever, args=(start_url,))
self.scraping_thread.daemon = True # Hilo se detiene cuando la app se cierra
self.scraping_thread.start()
def spin_roulette(self):
"""Simula el giro continuo de la ruleta."""
while self.roulette_running:
self.roulette_number = random.randint(1, 10)
self.roulette_label.config(text=f"Ruleta: {self.roulette_number}")
time.sleep(0.1)
def stop_roulette(self):
"""Detiene la ruleta y evalúa el resultado del juego."""
if not self.roulette_running:
return
self.roulette_running = False
def stop_scraping(self):
"""
Detiene el scraping.
"""
self.running = False
self.result_area.insert(tk.END, "Deteniendo scraping...\n")
self.result_area.see(tk.END)
self.start_button.config(state="normal")
self.stop_button.config(state="disabled")
# Evaluar resultado
if self.chosen_number == self.roulette_number:
winnings = self.bet * 2
self.balance += winnings
self.result_label.config(
text=f"¡Ganaste! El número fue {self.roulette_number}. Ganaste $ {winnings}.",
fg="green",
)
else:
self.balance -= self.bet
self.result_label.config(
text=f"Perdiste. El número fue {self.roulette_number}. Perdiste $ {self.bet}.",
fg="red",
)
def scrape_links_forever(self, start_url):
"""
Scrapea enlaces indefinidamente y guarda solo los visitados en MongoDB.
Se ejecuta en un hilo separado.
Args:
start_url (str): URL inicial para comenzar el scraping.
"""
to_visit = [start_url] # Lista de URLs por visitar
visited = set() # Conjunto para evitar bucles
# Actualizar saldo
self.balance_label.config(text=f"Saldo: $ {self.balance}")
while to_visit and self.running:
current_url = to_visit.pop(0) # Tomar la URL actual de la lista
# Revisar si el jugador se quedó sin saldo
if self.balance <= 0:
messagebox.showinfo("Juego Terminado", "¡Te quedaste sin saldo! Gracias por jugar.")
if current_url in visited:
continue
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__":
root = tk.Tk()
app = GamblingGameWithThreads(root)
app = ScraperApp(root)
root.mainloop()