Guía para el scraping de sitios web dinámicos con Python

Comentarios: 0

Una importante habilidad para obtener datos de páginas web es el web scraping. Pinterest e Instagram, que cargan contenidos de forma dinámica gracias a la interacción de los usuarios con ellos, son ejemplos de este tipo de sitios web. Los métodos de scraping habituales son insuficientes cuando se maneja material basado en JavaScript. En este artículo, hablaremos de Playwright como herramienta de automatización, mientras que lxml se utilizará para la extracción de datos de este tipo de sitios dinámicos que requieren Javascript para funcionar correctamente. En esta nota, podemos discutir la utilización de proxies en Playwright para evadir la detección como bots. En este tutorial, vamos a scrapear el perfil de Instagram para recuperar todas las URLs de las publicaciones simulando el comportamiento del usuario, como desplazarse y esperar a que se carguen las publicaciones.

Herramientas que usaremos en esta guía:

  • Playwright (para la automatización del navegador);
  • lxml (para la extracción de datos mediante XPath);
  • Python (como nuestro lenguaje de programación).

Guía paso a paso para scrapear publicaciones de Instagram

Ilustraremos el proceso con el ejemplo de scrapear un perfil de Instagram para extraer URLs de posts, simulando acciones del usuario como desplazarse por la página y esperar a que se carguen nuevos datos. Los sitios web dinámicos cargan su contenido de forma asíncrona mediante peticiones AJAX, lo que significa que no todo el contenido de la página es accesible de forma inmediata.

Paso 1. Instalar las librerías necesarias

Antes de empezar, instala los paquetes necesarios:


pip install playwright
pip install lxml

También tendrás que instalar los navegadores Playwright:


playwright install

Paso 2. Configuración de Playwright para el raspado dinámico de sitios web

Usaremos Playwright para automatizar el navegador, cargar el contenido dinámico de Instagram y desplazarnos por la página para cargar más publicaciones. Vamos a crear un script básico de automatización:

Script de automatización (Headless Browser):


import asyncio
from playwright.async_api import async_playwright

async def scrape_instagram():
    async with async_playwright() as p:
        browser = await p.chromium.launch(headless=True)  # Modo sin cabeza Sin respuesta visual
        page = await browser.new_page()
        
        # Visite la URL del perfil
        await page.goto("https://www.instagram.com/profile name/", wait_until="networkidle")

        # Haga clic en el botón para cargar más mensajes
        await page.get_by_role("button", name="Show more posts from").click()
        
        # Desplazar la página para cargar contenido dinámico
        scroll_count = 5  # Personalízalo en función de las veces que quieras desplazarte
        for _ in range(scroll_count):
            await page.evaluate('window.scrollBy(0, 700);')
            await page.wait_for_timeout(3000)  # Esperar a que se carguen los mensajes
            await page.wait_for_load_state("networkidle")
        
        # Obtener el contenido de la página
        content = await page.content()
        await browser.close()
        
        return content

# Ejecutar la función asíncrona
asyncio.run(scrape_instagram())

Paso 3. Análisis sintáctico de la página con lxml y XPath

Una vez cargado el contenido, podemos usar lxml para parsear el HTML y extraer datos usando XPath. En este caso, estamos extrayendo las URLs de todos los posts del perfil.

Parseando el contenido de la página y extrayendo las URLs de los posts:


from lxml import html
import json

def extract_post_urls(page_content):
    # Analiza el contenido HTML con lxml
    tree = html.fromstring(page_content)
    
    # XPath para extraer las URL de las entradas
    post_urls_xpath = '//a[contains(@href, "/p/")]/@href'
    
    # Extraer URL
    post_urls = tree.xpath(post_urls_xpath)
    
    # Convertir URL relativas en absolutas
    base_url = "https://www.instagram.com"
    post_urls = [f"{base_url}{url}" for url in post_urls]
    
    return post_urls

Función de ejemplo para guardar los datos extraídos en formato JSON:


def save_data(profile_url, post_urls):
    data = {profile_url: post_urls}
    with open('instagram_posts.json', 'w') as json_file:
        json.dump(data, json_file, indent=4)

# Raspar y extraer URL
page_content = asyncio.run(scrape_instagram())
post_urls = extract_post_urls(page_content)

# Guardar las URL extraídas en un archivo JSON
save_data("https://www.instagram.com/profile name/", post_urls)

Paso 4. Manejo del scroll infinito con Playwright

Para scrapear sitios web dinámicos, a menudo es necesario simular un scroll infinito. En nuestro script, desplazamos la página usando JavaScript:


(window.scrollBy(0, 700))

Y espera a que se cargue el nuevo contenido usando este comando:


 wait_for_load_state("networkidle")

Paso 5. Uso de proxies con Playwright

Instagram tiene estrictos límites de tasa y medidas anti-bot. Para evitar que te bloqueen, puedes utilizar proxies para rotar las direcciones IP y distribuir las solicitudes. Playwright facilita la integración de proxies en tu automatización de scraping.

Implementación de proxies en Playwright:


async def scrape_with_proxy():
    async with async_playwright() as p:
        browser = await p.chromium.launch(
            headless=False, 
            proxy={"server": "http://your-proxy-server:port"}
        )
        page = await browser.new_page()
        await page.goto("https://www.instagram.com/profile name/", wait_until="networkidle")
        # Continúe raspando como antes...

Playwright también soporta proxy para ser pasado como nombre de usuario contraseña y servidor ejemplo se da a continuación.


async def scrape_with_proxy():
    async with async_playwright() as p:
        browser = await p.chromium.launch(
            headless=False, 
            proxy={"server": "http://your-proxy-server:port", "username": "username", "password": "password"}
        )
        page = await browser.new_page()
        await page.goto("https://www.instagram.com/profile name/", wait_until="networkidle")
        # Continúe raspando como antes...

Los proxies ayudan a evitar las prohibiciones de IP, los desafíos CAPTCHA y garantizan un raspado sin problemas de sitios web con muchos datos o restringidos, como Instagram.

Código completo


import asyncio
from playwright.async_api import async_playwright
from lxml import html
import json

# Función para automatizar el navegador y raspar contenido dinámico con proxies
async def scrape_instagram(profile_url, proxy=None):
    async with async_playwright() as p:
        # Configurar el navegador con proxy si se proporciona
        browser_options = {
            'headless': True,  # Utilizar el navegador encabezado para ver la acción (puede establecerse en True para el modo headless)
        }
        if proxy:
            browser_options['proxy'] = proxy

        # Iniciar el navegador
        browser = await p.chromium.launch(**browser_options)
        page = await browser.new_page()

        # Visite la página del perfil de Instagram
        await page.goto(profile_url, wait_until="networkidle")
        
        # Pruebe a hacer clic en el botón "Mostrar más mensajes" (opcional, puede fallar si no se encuentra el botón)
        try:
           await page.click('button:has-text("Show more posts from")')
        except Exception as e:
           print(f"No 'Show more posts' button found: {e}")


        # Desplaza la página para cargar más entradas
        scroll_count = 5  # Número de desplazamientos para cargar los mensajes
        for _ in range(scroll_count):
            await page.evaluate('window.scrollBy(0, 500);')
            await page.wait_for_timeout(3000)  # Esperar a que se carguen los nuevos mensajes
            await page.wait_for_load_state("networkidle")

        # Obtener el contenido completo de la página después de desplazarse
        content = await page.content()
        await browser.close()  # Cierre el navegador cuando haya terminado
        
        return content

# Función para analizar el contenido de la página y extraer las direcciones URL de los mensajes.
def extract_post_urls(page_content):
    # Analiza el contenido HTML con lxml
    tree = html.fromstring(page_content)
    
    # XPath para extraer las URL de las entradas
    post_urls_xpath = '//a[contains(@href, "/p/")]/@href'
    
    # Extraer las URL de las entradas utilizando XPath
    post_urls = tree.xpath(post_urls_xpath)
    
    # Convertir URL relativas en absolutas
    base_url = "https://www.instagram.com"
    post_urls = [f"{base_url}{url}" for url in post_urls]
    
    return post_urls

# Función para guardar las URLs extraídas en un archivo JSON
def save_data(profile_url, post_urls):
    # Estructurar los datos en formato JSON
    data = {profile_url: post_urls}
    
    # Save the data to a file
    with open('instagram_posts.json', 'w') as json_file:
        json.dump(data, json_file, indent=4)
    print(f"Data saved to instagram_posts.json")

# Función principal para ejecutar el rascador y guardar los datos
async def main():
    # Definir la URL del perfil de Instagram
    profile_url = "https://www.instagram.com/profile name/"
    
    # Opcionalmente, configure un proxy
    proxy = {"server": "server", "username": "username", "password": "password"}  # Utilice Ninguno si no necesita un proxy
    
    # Rastrea la página de Instagram con proxies
    page_content = await scrape_instagram(profile_url, proxy=proxy)
    
    # Extraer las URL de las entradas del contenido de la página recuperada
    post_urls = extract_post_urls(page_content)
    
    # Guarda las URLs extraídas en un archivo JSON
    save_data(profile_url, post_urls)

if __name__ == '__main__':
   asyncio.run(main())

Herramientas de automatización alternativas para el web scraping

Aunque Playwright es una excelente opción para el scraping de sitios web dinámicos, otras herramientas podrían ser adecuadas para diferentes escenarios:

  1. Selenium: Selenium es uno de los frameworks de automatización de navegadores más antiguos y funciona de forma similar a Playwright.
  2. Puppeteer: Puppeteer es otra herramienta popular para la automatización del navegador, especialmente para el raspado de sitios web con JavaScript pesado. Al igual que Playwright, controla navegadores sin cabeza y permite la interacción con contenido dinámico;
  3. Requests + BeautifulSoup: para sitios web más sencillos que no requieren JavaScript para cargar contenido, la biblioteca Requests combinada con BeautifulSoup es una alternativa ligera. Sin embargo, no maneja bien el contenido dinámico.

Cada herramienta ofrece puntos fuertes únicos y se puede elegir en función de las necesidades y condiciones específicas del proyecto.

Para realizar con éxito el scraping de sitios web dinámicos que utilizan activamente JavaScript y solicitudes AJAX, se necesitan herramientas potentes capaces de gestionar con eficacia el desplazamiento infinito y los elementos interactivos complejos. Una de estas soluciones es Playwright, una herramienta de Microsoft que proporciona una automatización completa del navegador, lo que la convierte en una opción ideal para plataformas como Instagram. Combinado con la biblioteca lxml para el análisis sintáctico de HTML, Playwright simplifica enormemente la extracción de datos, lo que permite automatizar las interacciones con los elementos de la página y el proceso de análisis sintáctico sin intervención manual. Además, el uso de servidores proxy ayuda a eludir la protección anti-bot y evita el bloqueo de IP, garantizando operaciones de scraping estables e ininterrumpidas.

Comentarios:

0 Comentarios