Splash

Splash es una herramienta de renderizado de pรกginas web para web scraping de sitios dinรกmicos que utilizan JavaScript. Permite obtener el contenido completo de las pรกginas renderizadas, lo que facilita la extracciรณn de datos de aplicaciones web modernas. Proporciona funciones para interactuar con elementos dinรกmicos y obtener datos precisos.

Para poder utilizar splash necesitas tener instalado docker y para utilizarlo en el vanegador tienes que ejecutar el siguiente comando:

sudo docker run -it -p 8050:8050 scrapinghub/splash

# Busca en el navegador
http://127.0.0.1:8050

Splash funciona con el lenguje Lua y al igual que en C los scripts requeiren de una funcion main con su return al final. Para ejecutar las distintas acciones es recomendable utilizar la funcion assert, ya que esta comprueba si la funcion en su interior ha sido ejecutada correctamente y de no ser asi devuelve un error.

funcion main(splash, args)
    url = args.url
    assert(splash:go(url))
    assert(splash:wait(1))
    return
    {
        image = splash:png(),
        html = splash:html()
    }
end

Buscar elementos

Cuando se trabaja con Splash, una de las tareas fundamentales es la bรบsqueda y extracciรณn de elementos especรญficos en el HTML renderizado de una pรกgina web. Splash proporciona diversas opciones y comandos para llevar a cabo esta tarea.

Selecciรณn de elementos por etiqueta

Puedes utilizar el comando splash:select para seleccionar elementos basados en su etiqueta. Por ejemplo, para seleccionar todos los elementos div en la pรกgina, puedes utilizar el siguiente cรณdigo:

local divs = splash:select_all('div')
for _, div in ipairs(divs) do
    -- Realizar acciones con los elementos seleccionados
end

Selecciรณn de elementos por clase o ID

Si deseas buscar elementos por su clase o ID, puedes utilizar los selectores de CSS en conjunto con el comando splash:select. Por ejemplo, para seleccionar un elemento con una clase especรญfica, puedes hacer lo siguiente:

local element = splash:select('.mi-clase')

Si en cambio deseas seleccionar un elemento por su ID, puedes utilizar:

local element = splash:select('#mi-id')

Extracciรณn de atributos y texto de elementos

Una vez que hayas seleccionado un elemento, puedes extraer atributos especรญficos o el texto contenido en รฉl. Por ejemplo, para obtener el valor del atributo href de un enlace (<a>), puedes utilizar:

local link = splash:select('a')
local href = link.node.attributes.href

local href = link:get_attribute('href')

Si deseas obtener el texto contenido dentro de un elemento, puedes utilizar la propiedad node.text. Por ejemplo:

local paragraph = splash:select('p')
local text = paragraph.node.text

Bรบsqueda de elementos anidados

Splash tambiรฉn te permite buscar elementos anidados dentro de un elemento seleccionado previamente. Puedes utilizar el comando :select en conjunto con el selector CSS correspondiente. Por ejemplo, para seleccionar todos los elementos <li> dentro de una lista <ul>, puedes hacer lo siguiente:

luaCopy codelocal ul = splash:select('ul')
local lis = ul:select_all('li')

Recuerda adaptar los selectores CSS segรบn la estructura y los elementos especรญficos que deseas buscar en la pรกgina.

Acciones con Splash

Splash es una herramienta poderosa para interactuar con pรกginas web dinรกmicas y realizar diversas acciones automatizadas. A continuaciรณn, exploraremos las diferentes acciones que se pueden realizar con Splash y cรณmo utilizarlas en el contexto del web scraping.

Centrar elementos

El mรฉtodo focus se utiliza para establecer el foco en un elemento HTML, como un campo de entrada de texto o un botรณn. Esto permite que el elemento estรฉ listo para recibir eventos de teclado o interacciones del usuario.

local input = assert(splash:select('.my-input'))
input:focus()

En este ejemplo, input:focus() establece el foco en un elemento con la clase CSS .my-input. Despuรฉs de eso, el elemento estรก listo para recibir eventos de teclado o interacciones del usuario.

Escribir texto en campos de formulario

Una de las formas de escribir texto en campos de formulario utilizando Splash es a travรฉs del mรฉtodo splash:send_text. Sin embargo, tambiรฉn es posible utilizar el mรฉtodo element:send_text para interactuar directamente con un elemento especรญfico. Por ejemplo:

local input = splash:select('.search-input')
input:send_text('texto de bรบsqueda')

splash:send_text('.search-input', 'texto de bรบsqueda')

En este caso, se selecciona el elemento de entrada con la clase .search-input utilizando splash:select y luego se utiliza send_text en ese elemento para escribir el texto de bรบsqueda especificado.

Hacer clic en elementos

El mรฉtodo splash:mouse_click que mencionamos anteriormente se puede utilizar para simular clics en elementos. Sin embargo, tambiรฉn es posible utilizar el mรฉtodo element:click para hacer clic en un elemento especรญfico. Por ejemplo:

local button = splash:select('.btn-submit')
button:click()

splash:mouse_click('.btn-submit')

Aquรญ, se selecciona el botรณn con la clase .btn-submit utilizando splash:select y se utiliza click en ese elemento para simular el clic.

Presionar teclas

Ademรกs de la opciรณn de usar splash:send_keys para enviar eventos de teclado, tambiรฉn es posible utilizar el mรฉtodo element:send_keys para presionar teclas en un elemento especรญfico. Por ejemplo:

local input = splash:select('.search-input')
input:send_keys('<Enter>')

En este caso, se selecciona el campo de entrada con la clase .search-input utilizando splash:select y se utiliza send_keys en ese elemento para simular la pulsaciรณn de la tecla Enter.

Esperar a elementos

En ocasiones, es necesario esperar a que aparezcan ciertos elementos en la pรกgina antes de realizar acciones adicionales. Puedes utilizar el comando splash:wait para esperar a que un elemento especรญfico estรฉ presente en la pรกgina. Por ejemplo:

local input = splash:select('.search-input')
splash:wait(input)

splash:wait('.elemento-esperado')

Este comando espera hasta que aparezca un elemento con la clase .elemento-esperado. Tambien se puede utilizar este metodo para esperar un timepo especifico. Por ejemplo 5 segundos:

splash:wait(5)

Capturar capturas de pantalla

Splash te permite capturar capturas de pantalla de la pรกgina renderizada. Puedes usar el comando splash:png para obtener una imagen PNG de la pรกgina. Por ejemplo:

local screenshot = splash:png()

Este comando captura una captura de pantalla de la pรกgina actual y la guarda en la variable screenshot.

Modo incognito

El atributo splash.private_mode_enabled en Splash habilita el modo de navegaciรณn privada, que protege la privacidad al eliminar cookies, ignorar cachรฉs y no almacenar el historial de navegaciรณn.

splash.private_mode_enabled = true

User-Agent

Cuando utilizas Splash, tienes varios mรฉtodos disponibles para cambiar el User-Agent en tus solicitudes. Los mรฉtodos mรกs comunes son los siguientes:

set_user_agent

El mรฉtodo set_user_agent te permite establecer un User-Agent personalizado en el objeto splash. Puedes utilizarlo dentro del script Lua para cambiar el User-Agent de todas las solicitudes siguientes. Aquรญ tienes un ejemplo:

function main(splash, args)
    splash:set_user_agent("Mi User-Agent Personalizado")

    -- Resto del cรณdigo...
end

Al llamar a set_user_agent, especificas el User-Agent que deseas utilizar en tus solicitudes posteriores.

set_custom_headers

El mรฉtodo set_custom_headers te permite establecer encabezados personalizados en el objeto splash. Esto incluye la posibilidad de cambiar el User-Agent. Puedes utilizarlo dentro del script Lua para configurar los encabezados de las solicitudes. Aquรญ tienes un ejemplo:

function main(splash, args)
    headers = {
        ["User-Agent"] = "Mi User-Agent Personalizado"
    }
    splash:set_custom_headers(headers)

    -- Resto del cรณdigo...
end

Al llamar a set_custom_headers, proporcionas un diccionario de encabezados personalizados. Puedes incluir el User-Agent y otros encabezados segรบn tus necesidades.

on_request

El mรฉtodo on_request te permite manipular cada solicitud individualmente y modificar sus encabezados, incluido el User-Agent. Puedes utilizarlo para personalizar el User-Agent en solicitudes especรญficas. Aquรญ tienes un ejemplo:

function main(splash, args)
    splash:on_request(function(request)
        if string.find(request.url, "example.com") then
            request:set_header("User-Agent", "Mi User-Agent Personalizado")
        end
        return request
    end)

    -- Resto del cรณdigo...
end

Al utilizar on_request, puedes verificar la URL de cada solicitud y establecer el User-Agent de manera selectiva en base a tus criterios.

Diferencias entre los mรฉtodos

  • set_user_agent y set_custom_headers son mรฉtodos generales para establecer el User-Agent en todas las solicitudes o en todas las solicitudes con encabezados personalizados. Son รบtiles cuando deseas aplicar el mismo User-Agent a todas las solicitudes.

  • on_request te permite modificar las solicitudes individualmente y personalizar el User-Agent segรบn criterios especรญficos. Es รบtil cuando deseas tener un control mรกs granular sobre el User-Agent en diferentes solicitudes.

En resumen, los mรฉtodos set_user_agent y set_custom_headers son adecuados para establecer un User-Agent global, mientras que on_request te brinda la flexibilidad de personalizar el User-Agent en solicitudes individuales. Puedes elegir el mรฉtodo que mejor se adapte a tus necesidades y escenarios de uso en particular.

scrapy-splash

Scrapy-Splash es una extensiรณn de Scrapy que permite el scrapeo de contenido dinรกmico al interactuar con Splash, un renderizador web basado en navegador. Simplifica el proceso de renderizado de pรกginas web con JavaScript, lo que facilita el scrapeo de sitios que dependen de interacciones dinรกmicas.

Orden de funcionamiento

Aquรญ estรก el orden de ejecuciรณn nuevamente:

  1. Scrapy envรญa una solicitud a Splash.

  2. El script Lua en Splash se ejecuta.

  3. Dentro del script Lua, se realizan las acciones, como hacer clic en botones o escribir texto.

  4. Splash procesa y renderiza la pรกgina web, teniendo en cuenta las acciones realizadas en el script Lua.

  5. Splash devuelve el HTML renderizado junto con otros datos como respuesta a Scrapy.

  6. Scrapy recibe la respuesta de Splash y continรบa con el procesamiento de la respuesta en su propia lรณgica de scrapeo.

En resumen, las acciones que realices con scrapy-splash se ejecutan dentro del script Lua en Splash, entre el envรญo de la solicitud desde Scrapy y la devoluciรณn de la respuesta a Scrapy. Esto permite interactuar con la pรกgina web antes de extraer los datos deseados.

Integrar Scrapy-splash

Para utilizar Scrapy Splash en nuestro proyecto, primero necesitamos instalar el descargador scrapy-splash:

pip install scrapy-splash

Luego, debemos agregar la configuraciรณn requerida de Splash en el archivo settings.py de nuestro proyecto Scrapy:

# settings.py

# Splash Server Endpoint
SPLASH_URL = 'http://localhost:8050'


# Enable Splash downloader middleware and change HttpCompressionMiddleware priority
DOWNLOADER_MIDDLEWARES = {
    'scrapy_splash.SplashCookiesMiddleware': 723,
    'scrapy_splash.SplashMiddleware': 725,
    'scrapy.downloadermiddlewares.httpcompression.HttpCompressionMiddleware': 810,
}

# Enable Splash Deduplicate Args Filter
SPIDER_MIDDLEWARES = {
    'scrapy_splash.SplashDeduplicateArgsMiddleware': 100,
}

# Define the Splash DupeFilter
DUPEFILTER_CLASS = 'scrapy_splash.SplashAwareDupeFilter'

Usar splash desde scrapy

Como vamos a utilizar splash para hacer el request a la pagina web, es necesario reeescribir el emtodo start_requests y en vez de usar el metodo scrapy.Request tenemos que usar un metodo propio de la libreria splash-request que se llama SplashRequest:

import scrapy
from quotes_js_scraper.items import QuoteItem
from scrapy_splash import SplashRequest 

lua_script = """
function main(splash, args)
    assert(splash:go(args.url))

  while not splash:select('div.quote') do
    splash:wait(0.1)
    print('waiting...')
  end
  return {html=splash:html()}
end
"""

class QuotesSpider(scrapy.Spider):
    name = 'quotes'

    def start_requests(self):
        url = 'https://quotes.toscrape.com/scroll'
        yield SplashRequest(
            url, 
            callback=self.parse, 
            endpoint='execute', 
            args={'lua_source': lua_script}
            )

    def parse(self, response):
        print(response.body)

Last updated