From 8f6cf92054a49567607eed1a84fa6d3cabd7c3a5 Mon Sep 17 00:00:00 2001 From: imunnic Date: Tue, 4 Feb 2025 21:11:33 +0100 Subject: [PATCH] docker --- Dockerfile | 18 +++++++++++++ crontab.txt | 1 + docker-compose.yml | 65 ++++++++++++++++++++++++++++++++++++++++++++++ init.sql | 12 +++++++++ webscrapper.py | 58 ++++++++++++++++++++++++++++++++++++++--- 5 files changed, 150 insertions(+), 4 deletions(-) create mode 100644 Dockerfile create mode 100644 crontab.txt create mode 100644 docker-compose.yml create mode 100644 init.sql diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..f505d47 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,18 @@ +# Usa una imagen oficial de Python +FROM python:3.9 + +# Configurar el directorio de trabajo en el contenedor +WORKDIR /app + +# Copiar los archivos de la aplicación al contenedor +COPY app/ /app/ + +# Instalar dependencias si es necesario (ajusta según tu requerimiento) +RUN pip install mysql-connector-python schedule + +# Copiar el archivo de crontab y configurarlo +COPY crontab.txt /etc/cron.d/crontab +RUN chmod 0644 /etc/cron.d/crontab && crontab /etc/cron.d/crontab + +# Iniciar cron y ejecutar el script en segundo plano +CMD cron && tail -f /var/log/cron.log \ No newline at end of file diff --git a/crontab.txt b/crontab.txt new file mode 100644 index 0000000..7935aee --- /dev/null +++ b/crontab.txt @@ -0,0 +1 @@ +0 1 * * * python3 /app/main.py >> /var/log/cron.log 2>&1 diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..a494253 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,65 @@ +version: "3.9" + +services: + app: + build: . + container_name: mi_scraper + depends_on: + - mysql + environment: + - MYSQL_HOST=mysql + - MYSQL_USER=root + - MYSQL_PASSWORD=admin123 + - MYSQL_DATABASE=scraper_db + volumes: + - ./app:/app + restart: always + networks: + - metanet1 + + mysql: + image: mysql:8 + container_name: mi_mysql + restart: always + environment: + MYSQL_ROOT_PASSWORD: admin123 + MYSQL_DATABASE: scraper_db + ports: + - "3306:3306" + volumes: + - mysql_data:/var/lib/mysql + - ./init.sql:/docker-entrypoint-initdb.d/init.sql + networks: + - metanet1 + + metabase: + image: metabase/metabase:latest + container_name: metabase + hostname: metabase + volumes: + - /dev/urandom:/dev/random:ro + ports: + - "3000:3000" + environment: + MB_DB_TYPE: mysql + MB_DB_DBNAME: scraper_db + MB_DB_PORT: 3306 + MB_DB_USER: root + MB_DB_PASS: admin123 + MB_DB_HOST: mysql + networks: + - metanet1 + depends_on: + - mysql + healthcheck: + test: curl --fail -I http://localhost:3000/api/health || exit 1 + interval: 15s + timeout: 5s + retries: 5 + +networks: + metanet1: + driver: bridge + +volumes: + mysql_data: diff --git a/init.sql b/init.sql new file mode 100644 index 0000000..d6ba0d3 --- /dev/null +++ b/init.sql @@ -0,0 +1,12 @@ +CREATE DATABASE IF NOT EXISTS scraper_db; +USE scraper_db; + +CREATE TABLE IF NOT EXISTS noticias ( + id INT AUTO_INCREMENT PRIMARY KEY, + titulo VARCHAR(255) NOT NULL, + contenido TEXT, + autor VARCHAR(255), + fuente VARCHAR(255), + fecha DATETIME, + link TEXT +); diff --git a/webscrapper.py b/webscrapper.py index e27e6c2..a53facd 100644 --- a/webscrapper.py +++ b/webscrapper.py @@ -5,6 +5,7 @@ import os import time import subprocess from googlenewsdecoder import gnewsdecoder +import mysql.connector HEADERS = { "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" @@ -107,6 +108,7 @@ def search_news(query): } news_list.append(news_item) + except Exception as e: print(f"Error al procesar un artículo para '{query}': {e}") @@ -131,15 +133,63 @@ def search_from_keywords_file(): all_news.extend(news_list) # Añadir las noticias encontradas para cada palabra clave time.sleep(2) # Pausa para evitar bloqueos por demasiadas solicitudes en poco tiempo - # Guardar todas las noticias en un archivo JSON - with open('news_data.json', 'w', encoding='utf-8') as json_file: - json.dump(all_news, json_file, ensure_ascii=False, indent=4) - print("\nTodas las noticias han sido guardadas en 'news_data.json'.") + + # Guardar todas las noticias en la base de datos + insertar_datos(all_news,"noticias") except FileNotFoundError: print("No se encontró el archivo 'keywords.txt'.") except Exception as e: print(f"Error al leer el archivo 'keywords.txt': {e}") + +def insertar_datos(lista_objetos, tabla): + """ + Inserta una lista de diccionarios en una tabla de MySQL utilizando variables de entorno de Docker. + + :param lista_objetos: Lista de diccionarios con los datos a insertar. + :param tabla: Nombre de la tabla en la base de datos. + """ + if not lista_objetos: + print("Lista vacía, no hay datos para insertar.") + return + + # Obtener configuración de MySQL desde variables de entorno + db_config = { + "host": os.getenv("MYSQL_HOST", "localhost"), + "user": os.getenv("MYSQL_USER", "root"), + "password": os.getenv("MYSQL_PASSWORD", ""), + "database": os.getenv("MYSQL_DATABASE", "test"), + } + + # Obtener las columnas de la primera entrada + columnas = lista_objetos[0].keys() + columnas_str = ", ".join(columnas) + valores_str = ", ".join(["%s"] * len(columnas)) + + # Crear la consulta SQL + query = f"INSERT INTO {tabla} ({columnas_str}) VALUES ({valores_str})" + + # Convertir los datos en tuplas + valores = [tuple(obj[col] for col in columnas) for obj in lista_objetos] + + try: + # Conectar a la base de datos + conexion = mysql.connector.connect(**db_config) + cursor = conexion.cursor() + + # Ejecutar la inserción de múltiples filas + cursor.executemany(query, valores) + conexion.commit() + + print(f"{cursor.rowcount} registros insertados correctamente en {tabla}.") + + except mysql.connector.Error as err: + print(f"Error: {err}") + conexion.rollback() + + finally: + cursor.close() + conexion.close() # Ejecutar la búsqueda desde el archivo search_from_keywords_file()