DI logo and Scrapy logo

La necesidad de acelerar el web scraping y, al mismo tiempo, evitar activar sistemas anti-bot exige herramientas funcionales de scraping. Scrapy es una de las más utilizadas. Sigue leyendo para saber por qué merece tu atención y cómo usarla de forma eficaz.

¿Qué es Scrapy y qué ventajas te ofrece?

Scrapy es un framework de web crawling de código abierto para Python. Su popularidad tiene motivos claros, ya que sus ventajas incluyen:

  • capacidad para gestionar varios requests simultáneamente, de modo que el web scraping lleva menos tiempo
  • no hace falta mantener código
  • es adecuado para proyectos a gran escala
  • permite personalizar la gestión de requests y responses, por ejemplo añadir rotación de user-agent, gestionar reintentos y administrar proxies
  • funciona bien con sitios web con mucho JavaScript y ofrece funciones como request delay y auto-throttling para evitar sobrecargar los servidores 
  • incluye un item pipeline integrado, por lo que puedes extraer, almacenar y guardar datos en varios formatos, como JSON, CSV y XML
  • incluye selectores CSS y expresiones XPath, lo que te permite extraer con precisión los elementos HTML necesarios 

Para conocer todas las funciones de Scrapy, visita su documentación oficial. En este artículo nos centraremos en cómo usar Scrapy. Visitaremos nuestro blog y extraeremos todos los títulos de los artículos para mostrarte cómo funciona la herramienta. 

Como el web scraping implica riesgo de bloqueos, usar herramientas de crawling junto con proxies no es nada nuevo. En este tutorial te mostraremos cómo instalar y personalizar Scrapy y cómo implementar proxies. 

Preparación 

Antes de empezar, asegúrate de tener todos los programas y herramientas necesarios. Para este tutorial necesitamos: 

  • Visual Studio Code (o cualquier otro IDE compatible con Python) 
  • Python (versión 3.10.0 en nuestro caso)
  • pip (usamos la versión 25.0.1)

Puedes descargar VS Code aquí e instalar Python desde su sitio web oficial. Si no tienes pip (se incluye automáticamente en Python versión 3.4 y posteriores), abre el Bloc de notas y guarda este código en un archivo get-pip.py:


import urllib.request
import os
import sys

try:
    # download get-pip.py
    url = "https://bootstrap.pypa.io/get-pip.py"
    urllib.request.urlretrieve(url, "get-pip.py")

    # install pip
    os.system(f"{sys.executable} get-pip.py")
finally:
    # remove the script
    if os.path.exists("get-pip.py"):
        os.remove("get-pip.py")

      
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
      

Luego, abre el símbolo del sistema y ve a la carpeta donde guardaste el archivo:


cd path/to/your/file

      
        
      

Por ejemplo, guardamos el archivo en la carpeta Documents, así que nuestro comando se vería como cd/Documents.

Después, ejecuta el siguiente comando:


python get-pip.py

      
        
      

Para comprobar si pip funciona correctamente, usa este comando:


pip --version

      
        
      

Ahora que tienes todo listo, empecemos.

Instalar Scrapy e iniciar un proyecto

Primero debemos instalar Scrapy. Para hacerlo, abre el símbolo del sistema (o puedes hacerlo en la terminal de VS Code) y ejecuta el siguiente comando:


pip install Scrapy

      
        
      

Nota: Si has instalado todas las herramientas necesarias pero sigues viendo el mensaje “The term pip isn’t recognized as a name of cmdlet, function, script file, or operable program” u otros errores en la terminal de VS Code, intenta ajustar la configuración de VS Code. Ve a Terminal>Integrated: Default Profile (puedes escribir terminal integrated en la barra de búsqueda), cambia el perfil predeterminado al símbolo del sistema y reinicia VS Code para activar la nueva configuración.

Para iniciar un proyecto, ve a la carpeta de tu proyecto en la terminal de VS Code. En nuestro caso, la carpeta se llama Project S y está ubicada en la carpeta Documents, así que escribimos cd Documents/Project S.

Luego, escribe este comando:


scrapy startproject your_project_name

      
        
      

Asegúrate de sustituir your_project_name por un nombre real. Por ejemplo, usamos dataimpulse_blog.

A continuación, ve a la carpeta del proyecto:


cd your_project_name

      
        
      

Cuando estés allí, usa este comando para crear un spider:


scrapy genspider your_spider_name url_domain

      
        
      

En nuestro caso, el comando se ve así scrapy genspider blog_titles dataimpulse.com

Ajustar el código

Tanto si abres la carpeta de tu proyecto en VS Code como mediante el Explorador de archivos, verás varios archivos Python allí. Debemos modificarlos para extraer los datos necesarios.

Primero, en la carpeta “spiders” abre blog_titles.py y sustituye su código existente por este:


import scrapy


class BlogTitlesSpider(scrapy.Spider):
    name = 'blog_titles'
    allowed_domains = ['dataimpulse.com']
    start_urls = ['https://dataimpulse.com/blog/']
    def parse(self, response):
        self.logger.info(f"Visited {response.url}")

       
        titles = response.css('h3.blog-title a::text').getall()
        for title in titles:
            yield {'title': title.strip()}

       
        next_page = response.css('a.next::attr(href)').get()
        if next_page:
            yield response.follow(next_page, callback=self.parse)

      
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
      

Aquí defines la página que necesitas extraer y los datos que quieres recopilar (títulos, en este caso). También modificas el método parse.

A continuación, abre middlewares.py y pega allí el siguiente fragmento de código:


# Define here the models for your spider middleware
#
# See documentation in:
# https://docs.scrapy.org/en/latest/topics/spider-middleware.html

from scrapy import signals

# useful for handling different item types with a single interface
from itemadapter import is_item, ItemAdapter


class BlogscraperSpiderMiddleware:
    # Not all methods need to be defined. If a method is not defined,
    # scrapy acts as if the spider middleware does not modify the
    # passed objects.

    @classmethod
    def from_crawler(cls, crawler):
        # This method is used by Scrapy to create your spiders.
        s = cls()
        crawler.signals.connect(s.spider_opened, signal=signals.spider_opened)
        return s

    def process_spider_input(self, response, spider):
        # Called for each response that goes through the spider
        # middleware and into the spider.

        # Should return None or raise an exception.
        return None

    def process_spider_output(self, response, result, spider):
        # Called with the results returned from the Spider, after
        # it has processed the response.

        # Must return an iterable of Request, or item objects.
        for i in result:
            yield i

    def process_spider_exception(self, response, exception, spider):
        # Called when a spider or process_spider_input() method
        # (from other spider middleware) raises an exception.

        # Should return either None or an iterable of Request or item objects.
        pass
    
    def process_start_requests(self, start_requests, spider):
        # Called with the start requests of the spider, and works
        # similarly to the process_spider_output() method, except
        # that it doesn’t have a response associated.

        # Must return only requests (not items).
        for r in start_requests:
            yield r

    def spider_opened(self, spider):
        spider.logger.info("Spider opened: %s" % spider.name)


class BlogscraperDownloaderMiddleware:
    # Not all methods need to be defined. If a method is not defined,
    # scrapy acts as if the downloader middleware does not modify the
    # passed objects.

    @classmethod
    def from_crawler(cls, crawler):
        # This method is used by Scrapy to create your spiders.
        s = cls()
        crawler.signals.connect(s.spider_opened, signal=signals.spider_opened)
        return s

    def process_request(self, request, spider):
        # Called for each request that goes through the downloader
        # middleware.

        # Must either:
        # - return None: continue processing this request
        # - or return a Response object
        # - or return a Request object
        # - or raise IgnoreRequest: process_exception() methods of
        #   installed downloader middleware will be called
        request.meta['proxy'] = spider.settings.get('http://login:password@hostname:port')

    def process_response(self, request, response, spider):
        # Called with the response returned from the downloader.

        # Must either;
        # - return a Response object
        # - return a Request object
        # - or raise IgnoreRequest
        return response

    def process_exception(self, request, exception, spider):
        # Called when a download handler or a process_request()
        # (from other downloader middleware) raises an exception.

        # Must either:
        # - return None: continue processing this exception
        # - return a Response object: stops process_exception() chain
        # - return a Request object: stops process_exception() chain
        pass

    def spider_opened(self, spider):
        spider.logger.info("Spider opened: %s" % spider.name)

      
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
      

Presta atención a la línea 81. Aquí debes escribir tus credenciales reales en el formato http://login:password@hostname:port Para obtenerlas, ve al plan de proxy necesario en tu panel de DataImpulse. No olvides cambiar el formato de tu proxy en la esquina inferior derecha. Si tienes dificultades, no dudes en usar nuestra guía para gestionar tu cuenta de DataImpulse.

Por último, ve a settings.py y asegúrate de que se vea así:


# Scrapy settings for blogscraper project
#
# For simplicity, this file contains only settings considered important or
# commonly used. You can find more settings consulting the documentation:
#
#     https://docs.scrapy.org/en/latest/topics/settings.html
#     https://docs.scrapy.org/en/latest/topics/downloader-middleware.html
#     https://docs.scrapy.org/en/latest/topics/spider-middleware.html

BOT_NAME = "dataimpulse_blog"

SPIDER_MODULES = ["dataimpulse_blog.spiders"]
NEWSPIDER_MODULE = "dataimpulse_blog.spiders"


# Crawl responsibly by identifying yourself (and your website) on the user-agent
#USER_AGENT = "blogscraper (+http://www.yourdomain.com)"

# Obey robots.txt rules
ROBOTSTXT_OBEY = True

# Enable the downloader middlewares
DOWNLOADER_MIDDLEWARES = {
    'scrapy.downloadermiddlewares.httpproxy.HttpProxyMiddleware': 110,
    'scrapy.downloadermiddlewares.useragent.UserAgentMiddleware': None,
    'dataimpulse_blog.middlewares.BlogscraperSpiderMiddleware': 543,  # Add your ProxyMiddleware here
}

# Configure maximum concurrent requests performed by Scrapy (default: 16)
#CONCURRENT_REQUESTS = 32

# Configure a delay for requests for the same website (default: 0)
# See https://docs.scrapy.org/en/latest/topics/settings.html#download-delay
# See also autothrottle settings and docs
#DOWNLOAD_DELAY = 3
# The download delay setting will honor only one of:
#CONCURRENT_REQUESTS_PER_DOMAIN = 16
#CONCURRENT_REQUESTS_PER_IP = 16

# Disable cookies (enabled by default)
#COOKIES_ENABLED = False

# Disable Telnet Console (enabled by default)
#TELNETCONSOLE_ENABLED = False

# Override the default request headers:
#DEFAULT_REQUEST_HEADERS = {
#    "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
#    "Accept-Language": "en",
#}

# Enable or disable spider middlewares
# See https://docs.scrapy.org/en/latest/topics/spider-middleware.html
#SPIDER_MIDDLEWARES = {
#    "blogscraper.middlewares.BlogscraperSpiderMiddleware": 543,
#}

# Enable or disable downloader middlewares
# See https://docs.scrapy.org/en/latest/topics/downloader-middleware.html
#DOWNLOADER_MIDDLEWARES = {
#    "blogscraper.middlewares.BlogscraperDownloaderMiddleware": 543,
#}

# Enable or disable extensions
# See https://docs.scrapy.org/en/latest/topics/extensions.html
#EXTENSIONS = {
#    "scrapy.extensions.telnet.TelnetConsole": None,
#}

# Configure item pipelines
# See https://docs.scrapy.org/en/latest/topics/item-pipeline.html
#ITEM_PIPELINES = {
#    "blogscraper.pipelines.BlogscraperPipeline": 300,
#}

# Enable and configure the AutoThrottle extension (disabled by default)
# See https://docs.scrapy.org/en/latest/topics/autothrottle.html
#AUTOTHROTTLE_ENABLED = True
# The initial download delay
#AUTOTHROTTLE_START_DELAY = 5
# The maximum download delay to be set in case of high latencies
#AUTOTHROTTLE_MAX_DELAY = 60
# The average number of requests Scrapy should be sending in parallel to
# each remote server
#AUTOTHROTTLE_TARGET_CONCURRENCY = 1.0
# Enable showing throttling stats for every response received:
#AUTOTHROTTLE_DEBUG = False

# Enable and configure HTTP caching (disabled by default)
# See https://docs.scrapy.org/en/latest/topics/downloader-middleware.html#httpcache-middleware-settings
#HTTPCACHE_ENABLED = True
#HTTPCACHE_EXPIRATION_SECS = 0
#HTTPCACHE_DIR = "httpcache"
#HTTPCACHE_IGNORE_HTTP_CODES = []
#HTTPCACHE_STORAGE = "scrapy.extensions.httpcache.FilesystemCacheStorage"

# Set settings whose default value is deprecated to a future-proof value
REQUEST_FINGERPRINTER_IMPLEMENTATION = "2.7"
TWISTED_REACTOR = "twisted.internet.asyncioreactor.AsyncioSelectorReactor"
FEED_EXPORT_ENCODING = "utf-8"

      
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
      

Aquí habilitas el middleware y ajustas otros parámetros como caché, cookies, pipelines, etc.

Ahora viene el paso más importante. Abre Terminal y escribe cd para asegurarte de estar en el directorio raíz de tu proyecto (dataimpulse_blog en nuestro caso; debes buscar una carpeta que contenga el archivo scrapy.cfg , ese es el directorio raíz). Luego, usa el siguiente comando:


scrapy crawl blog_titles -o titles.json

      
        
      

Esto ejecutará el spider y guardará todos los resultados en un archivo llamado titles.json. Puedes comprobar los resultados abriendo el archivo directamente en VS Code. Esto es lo que obtuvimos:

Listo. Como puedes ver, Scrapy es fácil de usar. Puedes ajustar los detalles necesarios y aprovechar los proxies para obtener los mejores resultados. Por supuesto, la elección de proxies también es esencial. DataImpulse te ofrece proxies residenciales, de centro de datos y móviles de origen legal con un modelo de precios de pago por uso. Tienes IPs en lista blanca para necesidades universales sin agotar tu presupuesto. Empieza con nosotros haciendo clic en el botón “Pruébalo ahora” o escribiéndonos a [email protected].

Share article: