Proyecto 1: Copias de Seguridad Automáticas
🧭 Navegación:
- Anterior: Introducción a Proyectos de Automatización
- Siguiente: Organizador de Archivos por Tipo
🔄 El problema: Proteger tus datos importantes
Todos hemos experimentado alguna vez la pérdida de archivos importantes: un documento en el que trabajamos durante horas, fotos familiares irremplazables, o información crítica para nuestro trabajo o estudios. Estas pérdidas pueden ocurrir por diversos motivos:
- Fallas de hardware
- Errores humanos (borrado accidental)
- Malware o virus
- Robo o daño físico del dispositivo
- Corrupción de archivos
La solución es implementar un sistema de copias de seguridad (backups) que automáticamente resguarde tus archivos importantes de forma regular.
🎯 Objetivo del proyecto
Crearemos un script de Python que:
- Identifique archivos y carpetas importantes que necesitan respaldo
- Copie estos archivos a una ubicación segura (disco externo, carpeta en la nube, etc.)
- Organice los backups por fecha para facilitar la recuperación
- Comprima los archivos para ahorrar espacio
- Mantenga un registro (log) de las operaciones realizadas
- Se ejecute automáticamente según una programación definida
📋 Planificación del sistema
Componentes principales:
- Configuración: Definir qué archivos/carpetas respaldar y dónde
- Respaldo: Copiar los archivos a la ubicación de destino
- Organización: Estructurar los backups por fecha
- Compresión: Reducir el tamaño de los archivos respaldados
- Registro: Documentar las operaciones realizadas
- Programación: Ejecutar el script automáticamente
Bibliotecas que utilizaremos:
import os # Para operaciones con el sistema de archivos
import shutil # Para copiar archivos y directorios
import zipfile # Para comprimir archivos
import datetime # Para obtener la fecha actual
import logging # Para registrar eventos
import schedule # Para programar la ejecución automática
import time # Para pausas en la ejecución
💻 Implementación paso a paso
Paso 1: Configuración inicial
Primero, definiremos las rutas de origen (archivos a respaldar) y destino (donde se guardarán los backups):
# backup_config.py
# Rutas de origen (archivos/carpetas a respaldar)
SOURCE_PATHS = [
'/ruta/a/documentos_importantes',
'/ruta/a/fotos_familiares',
'/ruta/a/proyectos/python'
]
# Ruta de destino (donde se guardarán los backups)
BACKUP_DESTINATION = '/ruta/a/backups'
# Configuración de registro (logs)
LOG_FILE = '/ruta/a/backups/backup_log.txt'
# Programación (cuándo ejecutar el backup)
BACKUP_SCHEDULE = {
'daily': '20:00', # Todos los días a las 8:00 PM
'weekly': 'monday', # Cada lunes
}
Paso 2: Configuración del sistema de registro (logging)
Es importante mantener un registro de las operaciones realizadas:
# backup_logger.py
import logging
from datetime import datetime
def setup_logger(log_file):
"""Configura el sistema de registro."""
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s',
handlers=[
logging.FileHandler(log_file),
logging.StreamHandler() # También muestra mensajes en consola
]
)
logging.info(f"=== Iniciando sesión de backup: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')} ===")
return logging.getLogger()
Paso 3: Función principal de respaldo
Esta función se encargará de realizar la copia de seguridad:
# backup_functions.py
import os
import shutil
import zipfile
from datetime import datetime
import logging
def create_backup(source_paths, backup_destination):
"""
Crea una copia de seguridad de los archivos especificados.
Args:
source_paths: Lista de rutas a respaldar
backup_destination: Directorio donde se guardarán los backups
Returns:
str: Ruta del archivo de backup creado
"""
# Crear carpeta de destino si no existe
if not os.path.exists(backup_destination):
os.makedirs(backup_destination)
logging.info(f"Creado directorio de destino: {backup_destination}")
# Crear subcarpeta con la fecha actual
today = datetime.now().strftime('%Y-%m-%d')
backup_dir = os.path.join(backup_destination, today)
if not os.path.exists(backup_dir):
os.makedirs(backup_dir)
logging.info(f"Creado directorio para backup de hoy: {backup_dir}")
# Nombre del archivo zip (con hora para evitar sobreescrituras)
timestamp = datetime.now().strftime('%H-%M-%S')
zip_filename = f"backup_{today}_{timestamp}.zip"
zip_path = os.path.join(backup_dir, zip_filename)
# Crear archivo zip
with zipfile.ZipFile(zip_path, 'w', zipfile.ZIP_DEFLATED) as zipf:
# Procesar cada ruta de origen
for source_path in source_paths:
if os.path.exists(source_path):
logging.info(f"Respaldando: {source_path}")
# Si es un directorio, añadir todos sus contenidos
if os.path.isdir(source_path):
for root, dirs, files in os.walk(source_path):
for file in files:
file_path = os.path.join(root, file)
# Guardar con ruta relativa dentro del zip
arcname = os.path.relpath(file_path, os.path.dirname(source_path))
zipf.write(file_path, arcname)
logging.debug(f"Añadido al zip: {file_path}")
# Si es un archivo, añadirlo directamente
elif os.path.isfile(source_path):
arcname = os.path.basename(source_path)
zipf.write(source_path, arcname)
logging.debug(f"Añadido al zip: {source_path}")
else:
logging.warning(f"Ruta no encontrada, omitiendo: {source_path}")
logging.info(f"Backup completado: {zip_path}")
logging.info(f"Tamaño del archivo: {os.path.getsize(zip_path) / (1024*1024):.2f} MB")
return zip_path
Paso 4: Limpieza de backups antiguos
Para evitar que el espacio de almacenamiento se llene con backups antiguos:
def cleanup_old_backups(backup_destination, days_to_keep=30):
"""
Elimina backups más antiguos que el número de días especificado.
Args:
backup_destination: Directorio donde se guardan los backups
days_to_keep: Número de días a mantener los backups
"""
if not os.path.exists(backup_destination):
logging.warning(f"Directorio de backups no encontrado: {backup_destination}")
return
logging.info(f"Iniciando limpieza de backups antiguos (manteniendo {days_to_keep} días)")
# Calcular la fecha límite
cutoff_date = datetime.now() - datetime.timedelta(days=days_to_keep)
# Revisar cada subdirectorio (que debería ser una fecha)
for item in os.listdir(backup_destination):
item_path = os.path.join(backup_destination, item)
# Solo procesar directorios
if os.path.isdir(item_path):
try:
# Intentar parsear el nombre del directorio como fecha
dir_date = datetime.strptime(item, '%Y-%m-%d')
# Si es más antiguo que la fecha límite, eliminar
if dir_date < cutoff_date:
shutil.rmtree(item_path)
logging.info(f"Eliminado backup antiguo: {item_path}")
except ValueError:
# Si el nombre del directorio no es una fecha, ignorarlo
logging.warning(f"Directorio con formato inesperado, ignorando: {item}")
logging.info("Limpieza de backups antiguos completada")
Paso 5: Script principal
Ahora, uniremos todo en un script principal:
# backup_system.py
import schedule
import time
from backup_config import SOURCE_PATHS, BACKUP_DESTINATION, LOG_FILE, BACKUP_SCHEDULE
from backup_logger import setup_logger
from backup_functions import create_backup, cleanup_old_backups
def run_backup():
"""Ejecuta el proceso de backup completo."""
logger = setup_logger(LOG_FILE)
logger.info("Iniciando proceso de backup programado")
try:
# Crear backup
backup_file = create_backup(SOURCE_PATHS, BACKUP_DESTINATION)
# Limpiar backups antiguos (mantener últimos 30 días)
cleanup_old_backups(BACKUP_DESTINATION, days_to_keep=30)
logger.info("Proceso de backup completado exitosamente")
return backup_file
except Exception as e:
logger.error(f"Error durante el proceso de backup: {str(e)}")
return None
# Programar backups
if BACKUP_SCHEDULE.get('daily'):
schedule.every().day.at(BACKUP_SCHEDULE['daily']).do(run_backup)
print(f"Backup diario programado para las {BACKUP_SCHEDULE['daily']}")
if BACKUP_SCHEDULE.get('weekly'):
if BACKUP_SCHEDULE['weekly'].lower() == 'monday':
schedule.every().monday.at("00:00").do(run_backup)
# Añadir más días según sea necesario
print(f"Backup semanal programado para {BACKUP_SCHEDULE['weekly']}")
# Ejecutar un backup inmediato al iniciar
print("Ejecutando backup inicial...")
run_backup()
# Mantener el script en ejecución para que los backups programados funcionen
while True:
schedule.run_pending()
time.sleep(60) # Verificar cada minuto
🚀 Uso del sistema
Configuración inicial
-
Instala las dependencias necesarias:
pip install schedule
-
Modifica el archivo
backup_config.py
para especificar:- Las rutas que deseas respaldar
- La ubicación donde se guardarán los backups
- La programación de los backups
-
Ejecuta el script principal:
python backup_system.py
Ejecución como servicio
Para que el sistema funcione continuamente en segundo plano:
En Windows:
Puedes crear una tarea programada:
- Abre el Programador de tareas
- Crea una nueva tarea básica
- Configúrala para que se ejecute al inicio del sistema
- Apunta al script
backup_system.py
En Linux:
Puedes crear un servicio systemd:
- Crea un archivo
.service
en/etc/systemd/system/
- Configúralo para ejecutar el script
- Habilita e inicia el servicio
🔍 Comprueba tu comprensión
- ¿Qué sucedería si una de las rutas de origen no existe?
- ¿Cómo modificarías el código para respaldar solo archivos modificados después de la última copia de seguridad?
- ¿Qué otras estrategias de respaldo podrías implementar además de la compresión en ZIP?
- ¿Cómo adaptarías el sistema para enviar notificaciones por correo electrónico cuando se complete un backup?
🛠️ Ideas para mejoras
- Respaldo incremental: Respaldar solo los archivos que han cambiado desde el último backup
- Cifrado: Añadir protección con contraseña a los archivos ZIP
- Notificaciones: Enviar correos electrónicos o mensajes cuando se complete un backup
- Interfaz gráfica: Crear una GUI simple para configurar y monitorear los backups
- Respaldo en la nube: Integrar con servicios como Google Drive, Dropbox o AWS S3
- Verificación: Comprobar la integridad de los archivos respaldados
📝 Resumen
En este proyecto, has creado un sistema completo de copias de seguridad automáticas que:
- Respalda archivos y carpetas importantes
- Organiza los backups por fecha
- Comprime los archivos para ahorrar espacio
- Mantiene un registro detallado de las operaciones
- Se ejecuta automáticamente según una programación
- Limpia backups antiguos para gestionar el espacio
Este sistema no solo te protege contra la pérdida de datos, sino que también te ha permitido aplicar conceptos importantes de Python como el manejo de archivos, la programación de tareas, el registro de eventos y la organización de código en módulos.
En el próximo proyecto, aprenderemos a organizar archivos automáticamente por tipo.