Web Scraping Con Scrapy: La manera fácil
Mihai Maxim el 30 Ene 2023

Web scraping con Scrapy
Scrapy es una potente biblioteca de Python para extraer datos de sitios web. Es rápido, eficiente y fácil de usar - confía en mí, he estado allí. Si usted es un científico de datos, un desarrollador, o alguien que le encanta jugar con los datos, Scrapy tiene algo que ofrecerle. Y lo mejor de todo es que es gratuito y de código abierto.
Los proyectos Scrapy vienen con una estructura de archivos que ayuda a organizar el código y los datos. Esto facilita la creación y el mantenimiento de los raspadores web, por lo que merece la pena tenerlo en cuenta si tiene previsto realizar un raspado web serio. Web scraping con Scrapy Es como tener un asistente útil (aunque virtual) a tu lado mientras te embarcas en tu viaje de extracción de datos.
Lo que vamos a construir
Cuando aprendes algo nuevo, una cosa es leer sobre ello y otra hacerlo. Es por eso que hemos decidido construir un scraper juntos a medida que avanzamos a través de esta guía. Es la mejor manera de obtener una comprensión práctica de cómo funciona el raspado web con Scrapy.
¿Qué vamos a construir exactamente? Construiremos un raspador que extraiga definiciones de palabras del sitio web Urban Dictionary. Es un objetivo divertido para el scraping y ayudará a que el proceso de aprendizaje sea más ameno. Nuestro scraper será sencillo: devolverá las definiciones de varias palabras que se encuentran en el sitio web del Urban Dictionary. Utilizaremos el soporte integrado de Scrapy para seleccionar y extraer datos de documentos HTML con el fin de extraer las definiciones que necesitamos.
Empecemos. En la siguiente sección, repasaremos los requisitos previos que necesitarás para seguir este tutorial. Nos vemos allí.
Requisitos previos
Antes de sumergirnos en la construcción de nuestro scraper, hay algunas cosas que necesitarás configurar. En esta sección, vamos a cubrir cómo instalar Scrapy y configurar un entorno virtual para nuestro proyecto. La documentación de Scrapy sugiere instalar Scrapy en un entorno virtual dedicado. Al hacerlo, evitarás cualquier conflicto con los paquetes de tu sistema.
Estoy ejecutando Scrapy en Ubuntu 22.04.1 WSL (Windows Subsystem for Linux), así que voy a configurar un entorno virtual para mi máquina.
Te animo a que leas el capítulo "Entendiendo la estructura de carpetas" para entender completamente las herramientas con las que estamos trabajando. También, echa un vistazo al capítulo "Scrapy Shell", hará tu experiencia de desarrollo mucho más fácil.
Configuración de un entorno virtual Python
Para configurar un entorno virtual para Python en Ubuntu, puedes utilizar el comando mkvirtualenv. Primero, asegúrate de que tienes virtualenv y virtualenvwrapper instalados:
$ sudo apt-get install virtualenv virtualenvwrapper
Añada estas líneas al final de su archivo .bashrc:
export WORKON_HOME=$HOME/.virtualenvs
export PROJECT_HOME=$HOME/Deve
export VIRTUALENVWRAPPER_PYTHON='/usr/bin/python3'
source /usr/local/bin/virtualenvwrapper.sh
Yo utilicé Vim para editar el archivo, pero puedes elegir el editor que prefieras:
vim ~/.bashrc
// Utilice ctr + i para entrar en el modo insertar, utilice la flecha hacia abajo para desplazarse hasta el final del archivo.
// Pegue las líneas al final del archivo.
// Pulse escape para salir del modo insertar, escriba wq y pulse enter para guardar los cambios y salir de Vim.
A continuación, cree un nuevo entorno virtual con mkvirtualenv:
$ mkvirtualenv scrapy_env
Ahora deberías ver un (scrapy_env) añadido al principio de tu línea de terminal.
Para salir del entorno virtual, escriba $ desactivar
Para volver al entorno virtual scrappy_env, escribe $ workon scrapy_env
Instalación de Scrapy
Puede instalar Scrapy con el gestor de paquetes pip:
$ pip install scrapy
Esto instalará la última versión de Scrapy.
Puedes crear un nuevo proyecto con el comando scrapy startproject:
$ scrapy startproject miproyecto
Esto inicializará un nuevo proyecto Scrapy llamado "myproject". Debe contener la estructura del proyecto por defecto.
Comprender la estructura de carpetas
Esta es la estructura por defecto del proyecto:
myproject
├── myproject
│ ├── __init__.py
│ ├── items.py
│ ├── middlewares.py
│ ├── pipelines.py
│ ├── settings.py
│ └── spiders
│ └── __init__.py
└── scrapy.cfg
items.py
items.py es un modelo para los datos extraídos. Este modelo se utilizará para almacenar los datos que extraigas del sitio web.
Ejemplo:
import scrapy
class Producto(scrapy.Artículo):
nombre = scrapy.Campo()
precio = scrapy.Campo()
descripción = scrapy.Campo()
Aquí definimos un Item llamado Producto. Puede ser utilizado por un Spider (ver /spiders) para almacenar información sobre el nombre, precio y descripción de un producto.
/arañas
/spiders es una carpeta que contiene clases Spider. En Scrapy, las arañas son clases que definen cómo se debe raspar un sitio web.
Ejemplo:
import scrapy
from myproject.items import Product
class MySpider(scrapy.Spider):
name = 'myspider'
start_urls = ['<example_website_url>']
def parse(self, response):
# Extract the data for each product
for product_div in response.css('div.product'):
product = Product()
product['name'] = product_div.css('h3.name::text').get()
product['price'] = product_div.css('span.price::text').get()
product['description'] = product_div.css('p.description::text').get()
yield product
La "araña" recorre las start_urls, extrae el nombre, precio y descripción de todos los productos encontrados en las páginas (usando selectores css) y almacena los datos en el Item Producto (ver items.py). A continuación, "cede" estos elementos, lo que hace que Scrapy los pase al siguiente componente del pipeline (ver pipelines.py).
Yield es una palabra clave en Python que permite a una función devolver un valor sin terminar la función. En su lugar, produce el valor y suspende la ejecución de la función hasta que se solicite el siguiente valor.
Por ejemplo:
def count_up_to(max):
count = 1
while count <= max:
yield count
count += 1
for number in count_up_to(5):
print(number)
// returns 1 2 3 4 5 (each on a new line)
pipelines.py
Los pipelines se encargan de procesar los ítems (ver ítems.py y /spiders) que extraen las arañas. Puedes utilizarlas para limpiar el HTML, validar los datos y exportarlos a un formato personalizado o guardarlos en una base de datos.
Ejemplo:
import pymongo
class MongoPipeline(object):
def __init__(self):
self.conn = pymongo.MongoClient('localhost', 27017)
self.db = self.conn['mydatabase']
self.product_collection = self.db['products']
self.other_collection = self.db['other']
def process_item(self, item, spider):
if spider.name == 'product_spider':
//inserta el elemento en product_collection
elif spider.name == 'other_spider':
//inserta el elemento en la otra_colección
return item
Creamos un Pipeline llamado MongoPipeline. Se conecta a dos colecciones MongoDB (product_collection y other_collection). El pipeline recibe items (ver items.py) desde spiders (ver /spiders) y los procesa en la función process_item. En este ejemplo, la función process_item añade los ítems a sus colecciones designadas.
settings.py
settings.py almacena una variedad de configuraciones que controlan el comportamiento del proyecto Scrapy, tales como los pipelines, middlewares, y extensiones que deberían usarse, así como configuraciones relacionadas con cómo el proyecto debería manejar las peticiones y respuestas.
Por ejemplo, se puede utilizar para establecer el orden de ejecución de los pipelines (ver pipelines.py):
ITEM_PIPELINES = {
'myproject.pipelines.MongoPipeline': 300,
'myproject.pipelines.JsonPipeline': 302,
}
// MongoPipeline will execute before JsonPipeline, because it has a lower order number(300)
O establecer un contenedor de exportación:
FEEDS = {
'items': {'uri': 'file:///tmp/items.json', 'format': 'json'},
}
// this will save the scraped data to a items.json
scrappy.cfg
scrapy.cfg es el archivo de configuración para los ajustes principales del proyecto.
[settings]
default = [nombre del proyecto].settings
[deploy]
#url = http://localhost:6800/
project = [nombre del proyecto].
middlewares.py
Hay dos tipos de middlewares en Scrapy: middlewares downloader y middlewares spider.
Los middlewares de descarga son componentes que se pueden utilizar para modificar solicitudes y respuestas, gestionar errores e implementar una lógica de descarga personalizada. Se sitúan entre la araña y el descargador de Scrapy.
Los middlewares de araña son componentes que pueden utilizarse para implementar una lógica de procesamiento personalizada. Se sitúan entre el motor y la araña.
El caparazón de chatarra
Antes de embarcarnos en el emocionante viaje de implementar nuestro raspador de Urban Dictionary, primero deberíamos familiarizarnos con Scrapy Shell. Esta consola interactiva nos permite probar nuestra lógica de raspado y ver los resultados en tiempo real. Es como una caja de arena virtual donde podemos jugar y afinar nuestro enfoque antes de soltar nuestra araña en la web. Créeme, te ahorrará mucho tiempo y dolores de cabeza a largo plazo. Así que vamos a divertirnos un poco y conocer el Scrapy Shell.
Abrir el caparazón
Para abrir el Scrapy Shell, primero tendrá que navegar hasta el directorio de su proyecto Scrapy en su terminal. A continuación, sólo tiene que ejecutar el siguiente comando:
scrapy shell
Esto abrirá el Scrapy Shell y se le presentará con un símbolo del sistema donde puede introducir y ejecutar comandos Scrapy. También puede pasar una URL como argumento al comando shell para raspar directamente una página web, así:
scrapy shell <url>
Por ejemplo:
scrapy shell https://www.urbandictionary.com/define.php?term=YOLO
Devolverá (en el objeto de respuesta) el html de la página web que contiene las definiciones de la palabra YOLO (en el Urban Dictionary).
Alternativamente, una vez que entras en el shell, puedes utilizar el comando fetch para obtener una página web.
fetch('https://www.urbandictionary.com/define.php?term=YOLO')
También puede iniciar el intérprete de órdenes con el parámetro nolog para que no muestre registros:
scrapy shell --nolog
Trabajar con el shell
En este ejemplo, he obtenido la URL "https://www.urbandictionary.com/define.php?term=YOLO" y he guardado el html en el archivo test_output.html.
(scrapy_env) mihai@DESKTOP-0RN92KH:~/myproject$ scrapy shell --nolog
[s] Available Scrapy objects:
[s] scrapy scrapy module (contains scrapy.Request, scrapy.Selector, etc)
[s] crawler <scrapy.crawler.Crawler object at 0x7f1eef80f6a0>
[s] item {}
[s] settings <scrapy.settings.Settings object at 0x7f1eef80f4c0>
[s] Useful shortcuts:
[s] fetch(url[, redirect=True]) Fetch URL and update local objects (by default, redirects are followed)
[s] fetch(req) Fetch a scrapy.Request and update local objects
[s] shelp() Shell help (print this help)
[s] view(response) View response in a browser
>>> response // response is empty
>>> fetch('https://www.urbandictionary.com/define.php?term=YOLO')
>>> response
<200 https://www.urbandictionary.com/define.php?term=Yolo>
>>> with open('test_output.html', 'w') as f:
... f.write(response.text)
...
118260
Ahora inspeccionemos test_output.html e identifiquemos los selectores que necesitaremos para extraer los datos de nuestro Urban Dictionary scraper.

Podemos observar que:
- Cada contenedor de definición de palabra tiene la clase "definición".
- El significado de la palabra se encuentra dentro del div con la clase "significado".
- Los ejemplos de la palabra se encuentran dentro del div con la clase "ejemplo".
- La información sobre el autor de la entrada y la fecha se encuentran dentro del div con la clase "colaborador".
Ahora vamos a probar algunos selectores en el Scrapy Shell:
Para obtener referencias a cada contenedor de definición podemos utilizar selectores CSS o XPath:
Puede obtener más información sobre los selectores XPath aquí: https://www.webscrapingapi.com/the-ultimate-xpath-cheat-sheet
definiciones = response.css('div.definition')
definiciones = response.xpath('//div[contains(@class, "definición")]')
Debemos extraer el significado, el ejemplo y la información posterior de cada contenedor de definición. Probemos algunos selectores con el primer contenedor:
>>> first_def = definitions[0]
>>> meaning = first_def.css('div.meaning').xpath(".//text()").extract()
>>> meaning
['Yolo ', 'significa', ', '', 'Sólo se vive una vez', ''.']
>>> meaning = "".join(significado)
>>> significado
'Yolo significa, 'Sólo se vive una vez'.'
>>> ejemplo = first_def.css('div.ejemplo').xpath(".//texto()").extract()
>>> ejemplo = "".join(ejemplo)
>>> ejemplo
'"Ponte el cinturón de seguridad". Jessica said.\r "HAH, YOLO!" Replica Anna.\r(Luego proceden a tener un accidente de coche. Larga historia corta...Ponte el cinturón de seguridad.)'
>>> post_data = first_def.css('div.contributor').xpath(".//text()").extract()
>>> post_data
['by ', 'Soy feo', ' April 24, 2019']
Utilizando el shell Scrapy, hemos podido encontrar rápidamente un selector general que se adapta a nuestras necesidades.
definition.css('div.<meaning|example|contributor>').xpath(".//text()").extract()
// returns an array with all the text found inside the <meaning|example|contributor>
ex: ['Yolo ', 'means', ', '', 'You Only Live Once', ''.']
Para obtener más información sobre los selectores de Scrapy, consulte la documentación. https://docs.scrapy.org/en/latest/topics/selectors.html
Aplicación del raspador de Urban Dictionary
¡Buen trabajo! Ahora que le has cogido el truco al uso de Scrapy Shell y entiendes el funcionamiento interno de un proyecto Scrapy, es hora de sumergirse en la implementación de nuestro raspador Urban Dictionary. A estas alturas, deberías sentirte seguro y preparado para asumir la tarea de extraer todas esas divertidísimas (y a veces cuestionables) definiciones de palabras de la web. Así que sin más preámbulos, ¡comencemos a construir nuestro scraper!
Definición de un artículo
Primero, implementaremos un Item: (ver items.py)
class UrbanDictionaryItem(scrapy.Item):
significado = scrapy.Field()
autor = scrapy.Field()
fecha = scrapy.Field()
ejemplo = scrapy.Field()
Esta estructura contendrá los datos extraídos del Spider.
Definir una araña
Así es como definiremos nuestro Spider (véase /spiders):
importar scrapy
from ..items import UrbanDictionaryItem
clase UrbanDictionarySpider(scrapy.Spider):
nombre = 'diccionario_urbano
start_urls = ['https://www.urbandictionary.com/define.php?term=Yolo']
def parse(self, response):
definiciones = response.css('div.definition')
para definición en definiciones:
item = UrbanDictionaryItem()
item['significado'] = definition.css('div.significado').xpath(".//text()").extract()
item['ejemplo'] = definition.css('div.ejemplo').xpath(".//texto()").extract()
author = definition.css('div.contributor').xpath(".//text()").extract()
item['fecha'] = autor[2]
item['autor'] = autor[1]
elemento de rendimiento
Para ejecutar la araña urban_dictionary, utilice el siguiente comando:
scrapy crawl urban_dictionary
// los resultados deberían aparecer en la consola (muy probablemente en la parte superior de los logs)
Creación de una canalización
En este punto, los datos están sin desinfectar.
{'author': 'Soy ugly',
'date': ' April 24, 2019',
'example': ['“Put your ',
'seatbelt',
' on.” Jessica said.\n',
'“HAH, YOLO!” Replies Anna.\n',
'(They then proceed to have a ',
'car crash',
'. ',
'Long story short',
'...Wear a seatbelt.)'],
'meaning': ['Yolo ', 'means', ', ‘', 'You Only Live Once', '’.']}
Queremos modificar los campos "ejemplo" y "significado" para que contengan cadenas, no matrices. Para ello, escribiremos un Pipeline (ver pipelines.py) que transformará las matrices en cadenas concatenando las palabras.
class SanitizePipeline:
def process_item(self, item, spider):
# Sanitize the 'meaning' field
item['meaning'] = "".join(item['meaning'])
# Sanitize the 'example' field
item['example'] = "".join(item['ejemplo'])
# Limpia el campo 'fecha'
item['fecha'] = item['fecha'].strip()
return item
//ex: ['Yolo ', 'significa', ', '', 'Sólo se vive una vez', ''.'] se convierte en
'Yolo significa, 'Sólo se vive una vez'.'
Habilitar la canalización
Después de definir el Pipeline, necesitamos habilitarlo. Si no lo hacemos, nuestros objetos UrbanDictionaryItem no serán desinfectados. Para ello, añádelo a tu archivo settings.py (ver settings.py):
ITEM_PIPELINES = {
'myproject.pipelines.SanitizePipeline': 1,
}
De paso, también puede especificar un archivo de salida para colocar los datos obtenidos.
FEEDS = {
'items': {'uri': 'file:///tmp/items.json', 'format': 'json'},
}
// this will put the scraped data in an items.json file.
Opcional: Implementación de un middleware proxy
El scraping web puede ser un poco pesado. Uno de los principales problemas con los que nos encontramos a menudo es que muchos sitios web requieren la ejecución de javascript para mostrar completamente su contenido. Esto puede causar grandes problemas para nosotros como web scrapers, ya que nuestras herramientas a menudo no tienen la capacidad de ejecutar javascript como lo hace un navegador web normal. Esto puede conducir a la extracción de datos incompletos, o peor aún, a que nuestra IP sea baneada del sitio web por hacer demasiadas peticiones en un corto período de tiempo.
Nuestra solución a este problema es WebScrapingApi. Con nuestro servicio, sólo tiene que realizar solicitudes a la API y ésta se encargará de todo el trabajo pesado por usted. Ejecutará JavaScript, rotará proxies, e incluso manejará CAPTCHAs, asegurando que usted pueda raspar incluso el más obstinado de los sitios web con facilidad.
Un middleware proxy reenviará cada solicitud de obtención hecha por Scrapy al servidor proxy. El servidor proxy hará la petición por nosotros y nos devolverá el resultado.
Primero, definiremos una clase ProxyMiddleware dentro del archivo middlewares.py.
import base64
class ProxyMiddleware:
def process_request(self, request, spider):
# Set the proxy for the request
request.meta['proxy'] = "http://proxy.webscrapingapi.com:80"
request.meta['verify'] = False
# Set the proxy authentication for the request
proxy_user_pass = "webscrapingapi.proxy_type=residential.render_js=1:<API_KEY>"
encoded_user_pass = base64.b64encode(proxy_user_pass.encode()).decode()
request.headers['Proxy-Authorization'] = f'Basic {encoded_user_pass}'
En este ejemplo, hemos utilizado el servidor proxy WebScrapingApi.
webscrapingapi.proxy_type=residential.render_js=1 is the proxy authentication username, <API_KEY> the password.
Puede obtener una API_KEY gratuita creando una nueva cuenta en https://www.webscrapingapi.com/.
Después de definir el ProxyMiddleware, todo lo que tenemos que hacer es habilitarlo como DOWNLOAD_MIDDLEWARE en el archivo settings.py.
DOWNLOADER_MIDDLEWARES = {
'myproject.middlewares.ProxyMiddleware': 1,
}
Y, eso es todo. Como puedes ver, el web scraping con Scrapy puede simplificar mucho nuestro trabajo.
Conclusión
¡Lo hemos conseguido! Construimos un scraper que puede extraer definiciones de Urban Dictionary y aprendimos mucho sobre Scrapy en el camino. Desde la creación de elementos personalizados hasta la utilización de middlewares y pipelines, hemos demostrado lo potente y versátil que puede ser el web scraping con Scrapy. ¿Y lo mejor de todo? Todavía queda mucho por descubrir.
Enhorabuena por haber llegado hasta el final de este viaje conmigo. Ahora debería sentirse seguro de su capacidad para abordar cualquier proyecto de web scraping que se le presente. Sólo recuerde, el web scraping no tiene por qué ser desalentador o abrumador. Con las herramientas y los conocimientos adecuados, puede ser una experiencia divertida y gratificante. Si alguna vez necesita ayuda, no dude en ponerse en contacto con nosotros en https://www.webscrapingapi.com/. Sabemos todo sobre el web scraping y estaremos encantados de ayudarle en todo lo que podamos.
Noticias y actualidad
Manténgase al día de las últimas guías y noticias sobre raspado web suscribiéndose a nuestro boletín.
We care about the protection of your data. Read our <l>Privacy Policy</l>.Privacy Policy.

Artículos relacionados

Explore las complejidades del scraping de datos de productos de Amazon con nuestra guía en profundidad. Desde las mejores prácticas y herramientas como Amazon Scraper API hasta las consideraciones legales, aprenda a superar los desafíos, eludir los CAPTCHA y extraer información valiosa de forma eficiente.


Explore la comparación en profundidad entre Scrapy y Selenium para el scraping web. Desde la adquisición de datos a gran escala hasta la gestión de contenido dinámico, descubra los pros, los contras y las características únicas de cada uno. Aprenda a elegir el mejor marco de trabajo en función de las necesidades y la escala de su proyecto.


Aprenda a scrapear sitios web dinámicos con JavaScript utilizando Scrapy y Splash. Desde la instalación hasta la escritura de una araña, el manejo de la paginación y la gestión de las respuestas de Splash, esta completa guía ofrece instrucciones paso a paso tanto para principiantes como para expertos.
