Rastreo sin servidor con Scrapy y AWS

Aprenda a escribir una araña Scrapy, implementarla en AWS Lambda y almacenar los datos extraídos en S3 con este tutorial.
9 min de lectura
Serverless Scraping with Scrapy and AWS blog image

En la guía de hoy, vamos a escribir un Scrapy Spider y lo implementaremos en AWS Lambda. En lo que respecta al código, aquí es bastante sencillo. Cuando se trabaja con servicios en la nube como Lambda, hay muchos elementos móviles. Le mostraremos cómo navegar por estos elementos móviles y cómo manejarlos cuando algo falla.

Requisitos previos

Para realizar esta tarea, necesitarás lo siguiente:

  • aquí
  • conocimientos básicos sobre scraping con Scrapy

¿Qué es Serverless?

La arquitectura sin servidor ha sido aclamada como el futuro de la informática. Aunque el tiempo de ejecución real de una aplicación sin servidor puede ser más caro por hora, si aún no estás pagando por ejecutar un servidor, Lambda tiene sentido.

Supongamos que tu Scraper tarda un minuto en ejecutarse y lo ejecutas una vez al día. Con un servidor tradicional, pagarías por un mes de tiempo de actividad de 24 horas, pero tu uso real es de solo 30 minutos. Con servicios como Lambda, solo pagas por lo que realmente utilizas.

Ventajas

  • Facturación: solo pagas por lo que utilizas.
  • Escalabilidad: Lambda se escala automáticamente, no tienes que preocuparte por ello.
  • Gestión del servidor: no tienes que dedicar tiempo a gestionar un servidor. Todo esto se hace automáticamente.

Inconvenientes

  • Latencia: si tu función ha estado inactiva, tardará más en iniciarse y ejecutarse.
  • Tiempo de ejecución: las funciones Lambda se ejecutan con un tiempo de espera predeterminado de 3 segundos y un tiempo máximo de 15 minutos. Los servidores tradicionales son mucho más flexibles.
  • Portabilidad: no solo depende de la compatibilidad del sistema operativo, sino que también está a merced de su proveedor. No puede simplemente copiar su función Lambda y ejecutarla en Azure o Google Cloud.

Bright Data tiene una solución que no tiene esas limitaciones. Veámosla a continuación.

Funciones sin servidor: la mejor alternativa

The flow of Bright Data's Serverless Functions

Mientras que AWS Lambda y Scrapy ofrecen Scraping web sin servidor, las funciones sin servidor de Bright Data proporcionan una solución específica para un Scraping web más rápido y fiable. Con más de 70 plantillas JavaScript preconstruidas, un IDE integrado basado en la nube y una solución de desbloqueo impulsada por IA, puedes evitar los CAPTCHA, escalar sin esfuerzo y centrarte en extraer datos sin la molestia de gestionar la infraestructura.

A diferencia del enfoque de AWS y Scrapy, la solución de Bright Data incluye gestión de Proxy, escalado automático e integración directa con plataformas de almacenamiento como S3 o Google Cloud. Con un precio a partir de solo 2,7 $ por cada 1000 cargas de página, las funciones sin servidor hacen que el Scraping web avanzado sea más sencillo, rápido y rentable.

Ahora, continuemos con nuestra guía de Scrapy y AWS.

Introducción

Configuración de los servicios

Una vez que tengas tu cuenta de AWS, necesitarás un bucket de S3. Dirígete a la página «Todos los servicios» y desplázate hacia abajo.

A list of all AWS services

Finalmente, verá una sección llamada Almacenamiento. La primera opción de esta sección se llama S3. Haga clic en ella.

The S3 storage service

A continuación, haz clic en el botón Crear bucket.

Creating a new S3 bucket

Ahora, debe asignar un nombre a su bucket y elegir la configuración. Nosotros utilizaremos la configuración predeterminada.

Naming the new S3 bucket and choosing your settings

Cuando haya terminado, haga clic en el botón Crear bucket situado en la esquina inferior derecha de la página.

Creating the new S3 bucket

Una vez creado, tu bucket aparecerá en la pestaña Buckets, en Amazon S3.

Clicking the create bucket button when the configuration is done

Configuración de su proyecto

Cree una nueva carpeta de proyecto.

mkdir scrapy_aws

Vaya a la nueva carpeta y cree un entorno virtual.

cd scrapy_aws
python3 -m venv venv  

Activa el entorno.

source venv/bin/activate

Instala Scrapy.

pip install scrapy

Qué rastrear

Para sitios web dinámicos, medidas anti-bot o scraping a gran escala, utiliza el Navegador de scraping de Bright Data. Automatiza tareas, evita los CAPTCHA y se adapta a la perfección.

Usaremos books.toscrape como nuestro sitio de destino. Es un sitio educativo dedicado por completo al Scraping web. Si miras la imagen de abajo, cada libro es un artículo con el nombre de clase product_pod. Queremos extraer todos estos elementos de la página.

Inspecting one of the book in an article tag

El título de cada libro está incrustado en un elemento a que está anidado dentro de un elemento h3.

Inspecting the book title

Cada precio está incrustado en un p que está anidado dentro de un div. Tiene un nombre de clase price_color.

Inspecting the book price

Escribir nuestro código

Ahora, escribiremos nuestro Scraper y lo probaremos localmente. Abre un nuevo archivo Python y pega el siguiente código en él. Hemos llamado al nuestro aws_spider.py.

import scrapy


class BookSpider(scrapy.Spider):
    name = "books"
    allowed_domains = ["books.toscrape.com"]
    start_urls = ["https://books.toscrape.com"]

    def parse(self, response):
        for card in response.css("article"):
            yield {
                "title": card.css("h3 > a::text").get(),
                "price": card.css("div > p::text").get(),
            }
        next_page = response.css("li.next > a::attr(href)").get()

        if next_page:
            yield scrapy.Request(response.urljoin(next_page))

Puedes probar la araña con el siguiente comando. Debería generar un archivo JSON con todos los libros y sus precios.

 python -m scrapy runspider aws_spider.py -o books.json

Ahora necesitamos un controlador. La función del controlador es sencilla: ejecutar la araña. Aquí crearemos dos controladores que son básicamente iguales. La principal diferencia es que uno se ejecuta localmente y el otro en Lambda.

Este es nuestro controlador local, al que hemos llamado lambda_function_local.py.

import subprocess

def handler(event, context):
    # Ruta del archivo de salida para pruebas locales.
    output_file = "books.json"

    # Ejecutar la araña Scrapy con el indicador -o para guardar la salida en books.json
    subprocess.run(["python", "-m", "scrapy", "runspider", "aws_spider.py", "-o", output_file])

    # Devuelve un mensaje de éxito
    return {
        'statusCode': '200',
        'body': f"¡Rastreo completado! Salida guardada en {output_file}",
    }

# Añade este bloque para pruebas locales
if __name__ == "__main__":
    # Simula un evento y contexto de invocación de AWS Lambda
    fake_event = {}
    fake_context = {}

    # Llama al controlador e imprime el resultado
    result = handler(fake_event, fake_context)
    print(result)

Elimine books.json. Puede probar el controlador local con el siguiente comando. Si todo funciona correctamente, verá un nuevo books.json en la carpeta de su proyecto. Recuerde cambiar bucket_name por su propio bucket.

python lambda_function_local.py

Ahora, aquí está el controlador que usaremos para Lambda. Es bastante similar, solo tiene algunos pequeños ajustes para almacenar nuestros datos en nuestro bucket de S3.

import subprocess
import boto3

def handler(event, context):
    # Define las rutas de los archivos de salida locales y S3.
    local_output_file = "/tmp/books.json"  # Debe estar en /tmp para Lambda.
    bucket_name = "aws-scrapy-bucket"
    s3_key = "scrapy-output/books.json"  # Ruta en el bucket S3

    # Ejecuta la araña Scrapy y guarda la salida localmente
    subprocess.run(["python3", "-m", "scrapy", "runspider", "aws_spider.py", "-o", local_output_file])

    # Subir el archivo a S3
    s3 = boto3.client("s3")
    s3.upload_file(local_output_file, bucket_name, s3_key)

    return {
        'statusCode': 200,
        'body': f"¡Rastreo completado! Resultado subido a s3://{bucket_name}/{s3_key}"
    }
  • Primero guardamos nuestros datos en un archivo temporal: local_output_file = "/tmp/books.json". Esto evita que se pierdan.
  • Los subimos a nuestro bucket con s3.upload_file(archivo_de_salida_local, nombre_del_bucket, clave_s3).

Implementación en AWS Lambda

Ahora, tenemos que implementar en AWS Lambda.

Creamos una carpeta de paquete.

mkdir package

Copie nuestras dependencias en la carpeta del paquete.

cp -r venv/lib/python3.*/site-packages/* package/

Copie los archivos. Asegúrese de copiar el controlador que creó para Lambda, no el controlador local que probamos anteriormente.

cp lambda_function.py aws_spider.py paquete/

Comprima la carpeta del paquete en un archivo zip.

zip -r lambda_function.zip package/

Una vez creado el archivo ZIP, debemos dirigirnos a AWS Lambda y seleccionar Crear función. Cuando se le solicite, introduzca su información básica, como el tiempo de ejecución (Python) y la arquitectura.

Asegúrate de añadirle permiso para acceder a tu bucket de S3.

Creating a new function

Una vez creada la función, seleccione Cargar desde el menú desplegable. Se encuentra en la esquina superior derecha de la pestaña Fuente.

Lambda upload from

Seleccione el archivo .zip y cargue el archivo ZIP que ha creado.

Uploading the created ZIP file

Haga clic en el botón de prueba y espere a que se ejecute la función. Una vez ejecutada, compruebe su bucket de S3 y debería tener un nuevo archivo, books.json.

The new books.json file in your S3 bucket

Consejos para la resolución de problemas

No se encuentra Scrapy

Es posible que aparezca un error indicando que no se encuentra Scrapy. Si es así, debe añadir lo siguiente a su matriz de comandos en subprocess.run().

Adding a piece of code in the subprocess.run() function

Problemas generales de dependencia

Debe asegurarse de que sus versiones de Python sean las mismas. Compruebe su instalación local de Python.

python --version

Si este comando muestra una versión diferente a la de su función Lambda, cambie la configuración de Lambda para que coincida.

Problemas con el controlador

The handler should match the function you wrote

Su controlador debe coincidir con la función que escribió en lambda_function.py. Como puede ver arriba, tenemos lambda_function.handler. lambda_function representa el nombre de su archivo Python. handler es el nombre de la función.

No se puede escribir en S3

Es posible que se encuentre con problemas de permisos a la hora de almacenar la salida. Si es así, debe añadir estos permisos a su instancia Lambda.

Vaya a la consola de IAM y busque su función Lambda. Haga clic en ella y, a continuación, haga clic en el menú desplegable Añadir permisos.

Haga clic en Adjuntar políticas.

Clicking on 'attach policies' in the Lambda function

Seleccione AmazonS3FullAccess.

Selecting AmazonS3FullAccess

Conclusión

¡Lo ha conseguido! En este punto, debería ser capaz de desenvolverse en la pesadilla de interfaz de usuario conocida como consola de AWS. Ya sabe cómo escribir un rastreador con Scrapy. Ya sabe cómo empaquetar el entorno con Linux o WSL para garantizar la compatibilidad binaria con Amazon Linux.

Si no te gusta el scraping manual, echa un vistazo a nuestras API de scraping web y nuestros Conjuntos de datos listos para usar. ¡Regístrate ahora para empezar tu prueba gratuita!