Volver al curso

Python Desde Cero

leccion
19 / 21
beginner
20 horas
Python para el Mundo Real

Automatizacion con Python: Emails, PDFs y Web Scraping Basico

Lectura
25 min~5 min lectura

Automatizacion con Python: Emails, PDFs y Web Scraping Basico

Una de las fortalezas de Python es automatizar tareas repetitivas. En esta leccion aprenderemos a enviar emails, generar PDFs y hacer web scraping basico para extraer datos de sitios web.

Enviar emails con Python

Python incluye el modulo smtplib para enviar emails a traves de SMTP.

import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart

def enviar_email(destinatario, asunto, cuerpo, remitente, contrasenia):
    mensaje = MIMEMultipart('alternative')
    mensaje['From'] = remitente
    mensaje['To'] = destinatario
    mensaje['Subject'] = asunto
    
    parte_texto = MIMEText(cuerpo, 'plain', 'utf-8')
    mensaje.attach(parte_texto)
    
    try:
        with smtplib.SMTP_SSL('smtp.gmail.com', 465) as servidor:
            servidor.login(remitente, contrasenia)
            servidor.sendmail(remitente, destinatario, mensaje.as_string())
        print(f'Email enviado a {destinatario}')
        return True
    except Exception as e:
        print(f'Error al enviar: {e}')
        return False

enviar_email(
    destinatario='[email protected]',
    asunto='Tu pedido fue confirmado',
    cuerpo='Hola! Tu pedido #1234 fue confirmado. Llegara en 2-3 dias.',
    remitente='[email protected]',
    contrasenia='mi_contrasenia_de_aplicacion'
)

Nota: Para Gmail, necesitas una 'Contrasenia de aplicacion' (no tu contrasenia normal). Ve a Cuenta de Google > Seguridad > Verificacion en dos pasos > Contrasenias de aplicacion.

Enviar email HTML

def enviar_email_html(destinatario, asunto, html_cuerpo, remitente, contrasenia):
    mensaje = MIMEMultipart('alternative')
    mensaje['From'] = remitente
    mensaje['To'] = destinatario
    mensaje['Subject'] = asunto
    
    parte_html = MIMEText(html_cuerpo, 'html', 'utf-8')
    mensaje.attach(parte_html)
    
    with smtplib.SMTP_SSL('smtp.gmail.com', 465) as servidor:
        servidor.login(remitente, contrasenia)
        servidor.sendmail(remitente, destinatario, mensaje.as_string())

html = """
<html>
  <body>
    <h1>Bienvenido!</h1>
    <p>Tu cuenta fue creada exitosamente.</p>
    <a href="https://ejemplo.com/login">Iniciar sesion</a>
  </body>
</html>
"""

enviar_email_html('[email protected]', 'Bienvenido a nuestra plataforma', html, '[email protected]', 'pass')

Enviar emails en lote

import csv

def enviar_campania(archivo_csv, plantilla_asunto, plantilla_cuerpo, remitente, contrasenia):
    enviados = 0
    errores = 0
    
    with open(archivo_csv, 'r', encoding='utf-8') as f:
        reader = csv.DictReader(f)
        for contacto in reader:
            asunto = plantilla_asunto.format(**contacto)
            cuerpo = plantilla_cuerpo.format(**contacto)
            
            if enviar_email(contacto['email'], asunto, cuerpo, remitente, contrasenia):
                enviados += 1
            else:
                errores += 1
    
    print(f'Campania completada: {enviados} enviados, {errores} errores')

plantilla_asunto = 'Hola {nombre}, tenemos una oferta para ti!'
plantilla_cuerpo = 'Hola {nombre},\nTenemos un descuento especial del {descuento}% solo para ti.'

enviar_campania('contactos.csv', plantilla_asunto, plantilla_cuerpo, '[email protected]', 'pass')
Web Scraping basico con requests y BeautifulSoup

El web scraping permite extraer datos de paginas web automaticamente.

# Instalar primero: pip install requests beautifulsoup4
import requests
from bs4 import BeautifulSoup

def obtener_pagina(url):
    try:
        headers = {'User-Agent': 'Mozilla/5.0'}
        respuesta = requests.get(url, headers=headers, timeout=10)
        respuesta.raise_for_status()  # Error si el status no es 200
        return respuesta.text
    except requests.RequestException as e:
        print(f'Error al obtener {url}: {e}')
        return None

def extraer_titulos(html):
    soup = BeautifulSoup(html, 'html.parser')
    titulos = soup.find_all('h2')
    return [t.get_text(strip=True) for t in titulos]

html = obtener_pagina('https://news.ycombinator.com')
if html:
    soup = BeautifulSoup(html, 'html.parser')
    titulos = soup.select('.titleline > a')
    print('Titulos en Hacker News:')
    for i, titulo in enumerate(titulos[:5], 1):
        print(f'{i}. {titulo.get_text()}')

Extraccion estructurada de datos

def scrape_productos(url):
    html = obtener_pagina(url)
    if not html:
        return []
    
    soup = BeautifulSoup(html, 'html.parser')
    productos = []
    
    # Ejemplo generico - adaptar a la estructura HTML real
    for item in soup.find_all('div', class_='producto'):
        nombre = item.find('h3')
        precio = item.find('span', class_='precio')
        
        if nombre and precio:
            productos.append({
                'nombre': nombre.get_text(strip=True),
                'precio': precio.get_text(strip=True)
            })
    
    return productos

productos = scrape_productos('https://ejemplo.com/catalogo')
for p in productos:
    print(f"{p['nombre']}: {p['precio']}")

Guardar datos scrapeados en CSV

import csv

def scrape_y_guardar(url, archivo_salida):
    datos = scrape_productos(url)
    
    if not datos:
        print('Sin datos para guardar')
        return
    
    with open(archivo_salida, 'w', newline='', encoding='utf-8') as f:
        campos = datos[0].keys()
        writer = csv.DictWriter(f, fieldnames=campos)
        writer.writeheader()
        writer.writerows(datos)
    
    print(f'{len(datos)} productos guardados en {archivo_salida}')

scrape_y_guardar('https://ejemplo.com/productos', 'productos_scrapeados.csv')
Automatizacion con el sistema operativo
import os
import shutil
from pathlib import Path
from datetime import datetime

def organizar_descargas(carpeta_origen, carpeta_destino):
    origen = Path(carpeta_origen)
    destino = Path(carpeta_destino)
    destino.mkdir(exist_ok=True)
    
    extensiones = {
        '.jpg': 'Imagenes',
        '.jpeg': 'Imagenes',
        '.png': 'Imagenes',
        '.pdf': 'PDFs',
        '.doc': 'Documentos',
        '.docx': 'Documentos',
        '.xlsx': 'Excel',
        '.csv': 'Datos',
        '.py': 'Python',
        '.mp4': 'Videos',
        '.mp3': 'Audio',
    }
    
    movidos = 0
    for archivo in origen.iterdir():
        if archivo.is_file():
            tipo = extensiones.get(archivo.suffix.lower(), 'Otros')
            carpeta_tipo = destino / tipo
            carpeta_tipo.mkdir(exist_ok=True)
            destino_archivo = carpeta_tipo / archivo.name
            
            if not destino_archivo.exists():
                shutil.move(str(archivo), str(destino_archivo))
                movidos += 1
                print(f'Movido: {archivo.name} -> {tipo}/')
    
    print(f'Total movidos: {movidos} archivos')

organizar_descargas('/Users/usuario/Downloads', '/Users/usuario/Organizado')
Scheduler: Automatizacion programada
# Instalar: pip install schedule
import schedule
import time
from datetime import datetime

def tarea_diaria():
    ahora = datetime.now().strftime('%Y-%m-%d %H:%M')
    print(f'[{ahora}] Ejecutando tarea diaria...')
    # Aqui va tu logica
    # generar_reporte()
    # enviar_email_resumen()
    print('Tarea completada')

def verificar_alertas():
    print('Verificando alertas...')
    # Logica de alertas

# Programar tareas
schedule.every().day.at('09:00').do(tarea_diaria)
schedule.every(30).minutes.do(verificar_alertas)

print('Scheduler iniciado. Esperando tareas...')
while True:
    schedule.run_pending()
    time.sleep(60)  # Revisar cada minuto
Consideraciones eticas del web scraping
  1. Revisa el archivo robots.txt del sitio antes de scrapear
  2. No sobrecarges el servidor con demasiadas peticiones
  3. Agrega delays entre peticiones (time.sleep(1))
  4. Respeta los terminos de servicio del sitio
  5. Muchos sitios prefieren que uses su API oficial si existe
💡 Concepto Clave

Revisemos los puntos más importantes de esta lección antes de continuar.

Resumen

  • smtplib permite enviar emails desde Python
  • requests descarga el contenido de paginas web
  • BeautifulSoup parsea y extrae datos del HTML
  • os y shutil automatizan tareas del sistema de archivos
  • schedule permite ejecutar tareas en horarios especificos

En la proxima leccion aprenderemos a consumir APIs REST para obtener datos del mundo real.

🧠 Pon a prueba tu conocimiento
¿Cuál es el aspecto más importante que aprendiste en esta lección?
  • Comprendo el concepto principal y puedo explicarlo con mis palabras
  • Entiendo cómo aplicarlo en mi situación específica
  • Necesito repasar algunas partes antes de continuar
  • Quiero ver más ejemplos prácticos del tema
✅ ¡Excelente! Continúa con la siguiente lección para profundizar más.