Tutorial - Automatizando la descarga de una lista de links con Scrapy
Tutorial - Automatizando la descarga de una lista de links con Scrapy
Automatizar las tareas de descargas es un tarea muy común que nos encontraremos tanto en el trabajo como en nuestra vida. En esta ocasión quiero enseñarlos como utilizar Scrapy para descargar automaticamente una lista de Libros en PDF de un artículo en Medium: Springer has released 65 Machine Learning and Data books for free.
En todo proyecto de Scraping, es importante primero analizar como está estructurada la data y como puedo accedarla programaticamente y así planificar nuestro desarrollo. En este caso, podemos ver que existe una lista de URL en el artículo:
¿Qué observamos?
- Al hacer click al link nos lleva el sitio Web de Springer, directamente a link del libro
Y ahora, vemos que hay un botón de acción "Download PDF" para poder efectivamente descargar el libro.
Y es aquí donde damos nuestros primeros pasos hacia el scraping: debemos analizar la estructura del html y chequear de que manera se da el flujo del proceso para poder automatizarlo. Recuerda, en este punto, el Inspector de tu navegador es tu mejor amigo. Yo ya he identificado la manera de como obtener los links y como ejecutar la descarga. No te preocupes si aún no lo ven. Podrán ver este tutorial completado en mi Github y les dejaré el link hacia el repositorio.
Ahora si vamos a lo divertido! comenzamos con Scrapy
Lo primero que vamos a hacer es crear un directorio en nuestro ordenador:
mkdir simple-scrapy-pdf-scrapper
Luego crearemos nuestro Virtual Environment para instalar las diferentes librerias que vayamos a utilizar:
virtualenv -p python3.7 venv
source venv/bin/activate
e instalamos Scrapy
pip install scrapy
Estamos listos para continuar!!
Lo primero que debo hacer es crear el proyecto en scrapy. Para ello debo ejecutar la siguiente instrucción dentro del bash y posicionados en el directorio que hemos creado
scrapy startproject pdf_download
Este comando generará nuestro proyecto Scrapy. ¿Puedes adivinar como se llama? Pues si dijistes pdf_download has acertado.
Ahora, un proyecto puede estar compuesto por uno o más Spider. Pero es necesario crearlas.
scrapy genspider scrape_springer_books https://towardsdatascience.com/springer-has-released-65-machine-learning-and-data-books-for-free-961f8181f189
El comando scrape genspider toma dos argumentos: el primero el nombre de la clase y del spider como tal y el segundo es el start_url
que no es más que la dirección URL que buscará en primer lugar nuestro spider. En este caso, estamos generando una spider llamada scrape_springer_books. Veamos como está quedando la estructura de archivos del proyecto:
Tenemos nuestro template listo. Para afinar la estrategia de código y el método para obtener la data siempre recomiendo usar primero el shell del framework. En este caso pueden verlo funcionando con el siguiente comando:
scrapy shell "https://towardsdatascience.com/springer-has-released-65-machine-learning-and-data-books-for-free-961f8181f189"
El shell les permitirá hacer uso de todos los métodos del framework y plantear a manera de prueba sus ideas. Por ejemplo al cargar el shell con la página inicial que deseamos scrapear veremos los siguiente:
Yo ya he definido que los links que necesito están dentro de un anchor tag en html, y se que el href contiene "link.springer" en su contenido, entonces para seleccionar todos los urls que quiero scrapear uso el siguiente comando:
response.xpath('//a[contains(@href, "link.springer")]/@href')
Vemos que tenemos 64 urls para descargar. Muy bien. Con eso, ya puedo modificar mi archivo scrape_springer_books.py
con la sentencia que necesito. Luego necesito hacer lo mismo pero dentro de la página objetivo. No necesito hacer lo en todas, solo debe ver como es la estructura y luego generalizar para automatizar.
Para el caso de la página donde se encuentra el libro como tal, podemos ver que botón produce la descarga
Esto, en el codigo final correspondería a la siguiente función:
def gotospringer(self, response):
link = 'https://' + allowed_domains[1] + \
response.xpath('//a[contains(@data-track-action, "pdf")]/@href')[0].get()
yield scrapy.Request(link, callback=self.save_pdf)
Luego, cuando el spider ya tenga tenga el PDF lo salvará haciendo uso de la función save_pdf
def save_pdf(self, response):
path = response.url.split('/')[-1]
with open(path, 'wb') as f:
f.write(response.body)
En este punto se está guardando localmente, pero facilmente podría guardarlo en DropBox, en S3, en un FTP o donde se quiera.
Finalmente, para llamar a nuestra Spider debemos ejecutar desde nuestro bash:
scrapy crawl scrape_springer_books
Bonus track
Si quieren nombrar el archivo con el título del libro, deben utilizar el selector h1
y utilizarlo en el save_pdf para generar el nombre del archivo!
De nada!!! :)
Repositorio del Tutorial
Github - Simple Scrapy PDF Scrapper
Necesitas ayuda con tu Proyecto o tienes una idea para desarrollar y necesitas de un Full Stack Developer? Contáctame!