Latenode

Condiciones de espera personalizadas con waitForFunction en Puppeteer

Mejore sus scripts de Puppeteer con condiciones de espera personalizadas mediante waitForFunction para garantizar interacciones fiables con contenido web dinámico.

9 min de lectura
Código de Puppeteer con una condición de espera personalizada

¿Quiere que sus scripts de Puppeteer gestionen mejor los sitios web dinámicos? Esta es la clave: waitForFunction le permite definir reglas de espera personalizadas para garantizar que su automatización funcione sin problemas con contenido cambiante.

¿Por qué usar waitForFunction?

  • Controle los tiempos: Espere hasta que se cumplan condiciones específicas (por ejemplo, que se carguen elementos o cambie el texto).
  • Gestione contenido dinámico: Ideal para sitios web modernos y dinámicos.
  • Evite errores: Omita retrasos innecesarios o interacciones prematuras.

Cómo funciona:

  • Escriba condiciones de JavaScript que devuelvan true cuando estén listas.
  • Use opciones como la frecuencia de sondeo (raf, mutation o milisegundos) y los tiempos de espera para mejorar el rendimiento.
  • Combine comprobaciones del DOM con respuestas de API para casos de uso avanzados.

Ejemplo:

await page.waitForFunction(
  () => document.querySelector('.status').textContent === 'Ready'
);

Características principales:

  • Supervise la visibilidad de los elementos, el contenido de texto o las propiedades personalizadas.
  • Combine varias condiciones para flujos complejos.
  • Gestione tiempos de espera y errores de forma eficaz.

Consejo: Use waitForFunction para sustituir las llamadas sleep obsoletas y mejorar la eficiencia.

Resumen rápido:

CaracterísticaQué hace
Modos de sondeoComprueba condiciones mediante 'raf', 'mutation' o intervalos personalizados
Condiciones personalizadasEspera estados específicos del DOM o respuestas de API
Gestión de tiempos de esperaEstablece tiempos de espera específicos por operación o globales

Este método garantiza que sus scripts sean fiables, eficientes y estén preparados para cualquier reto de contenido dinámico.

¿Cómo esperar / pausar durante N segundos en puppeteer?

Fundamentos de waitForFunction

El método waitForFunction de Puppeteer le permite configurar condiciones personalizadas que sus scripts deben esperar antes de continuar. A continuación, verá cómo utilizarlo eficazmente.

Cómo escribir funciones de espera básicas

Esta es una forma sencilla de crear una función de espera:

// Wait until the input element has a specific value
await page.waitForFunction(
  'document.getElementById("loginUsername").value === "hello"'
);

// Using an arrow function for a condition
await page.waitForFunction(
  () => document.querySelector('.status').textContent === 'Ready'
);

La clave es que su función debe devolver un valor verdadero antes de que el script pueda continuar [1].

Ahora, veamos cómo configurarlo para obtener un mejor rendimiento.

Configuración de los parámetros de la función

Puede ajustar waitForFunction mediante un objeto de opciones. Los parámetros principales incluyen:

ParámetroDescripciónValores habituales
pollingFrecuencia con la que se comprueba la condición'raf', 'mutation' o milisegundos
timeoutTiempo máximo de esperaPredeterminado: 30.000 ms (30 segundos)

Modos de sondeo [4]:

  1. RequestAnimationFrame ('raf')
    Ideal para supervisar cambios de estilo, ya que comprueba las condiciones durante cada fotograma de animación.

  2. Mutation Observer ('mutation')
    Útil para rastrear cambios en la estructura del DOM. Activa comprobaciones cada vez que se actualiza el DOM.

  3. Intervalo personalizado (milisegundos)
    Por ejemplo, esto comprueba la condición cada segundo:

    await page.waitForFunction(
      () => document.readyState === 'complete',
      { polling: 1000, timeout: 5000 }
    );
    

Elija el modo de sondeo según sus necesidades:

  • Use 'raf' para animaciones o actualizaciones de estilo.
  • Elija 'mutation' para cambios relacionados con el DOM.
  • Establezca un intervalo personalizado (milisegundos) para casos de uso más amplios.

Creación de reglas de espera personalizadas

Comprobación del estado de visualización de los elementos

Para confirmar que un elemento es visible, puede comprobar su presencia y dimensiones:

await page.waitForFunction(() => {
    const element = document.querySelector('.tv-lightweight-charts');
    return element && element.offsetHeight > 0 && element.offsetWidth > 0;
});

Esto garantiza que el elemento exista y tenga dimensiones visibles en la página. Resulta especialmente útil para el contenido dinámico que tarda en cargarse correctamente [2].

Comprobación de texto y propiedades de elementos

Además de las comprobaciones visuales, puede supervisar el contenido de texto o propiedades específicas de los elementos:

// Wait for specific text content
await page.waitForFunction(
    selector => {
        const element = document.querySelector(selector);
        return element && element.textContent.includes('Ready');
    },
    {},
    '.status-message'
);

Para comprobaciones de propiedades más detalladas, pase argumentos adicionales:

const expectedValue = 'completed';
const selector = '.status';

await page.waitForFunction(
    (sel, val) => {
        const element = document.querySelector(sel);
        return element && element.getAttribute('data-state') === val;
    },
    {},
    selector,
    expectedValue
);

Combinación de varias reglas de espera

Una vez que haya probado las condiciones individuales, puede combinarlas para casos más complejos. Por ejemplo:

await page.waitForFunction(() => {
    // Check multiple elements and conditions
    const button = document.querySelector('.donate-button');
    const searchBox = document.querySelector('.search-button');

    return button && 
           searchBox && 
           button.offsetHeight > 0 && 
           searchBox.offsetHeight > 0 &&
           !button.disabled;
});

Para gestionar varios elementos con condiciones independientes, use combinaciones de Promise [5]:

Patrón de esperaCaso de usoImplementación
Todos los elementosEsperar varios elementos necesariosPromise.all()
Cualquier elementoContinuar cuando aparezca el primer elementoPromise.race()
Lógica personalizadaGestionar comprobaciones condicionales complejasFunciones de espera combinadas

Para operaciones asíncronas, puede crear condiciones de espera avanzadas:

await page.waitForFunction(
    async () => {
        const response = await fetch('/api/status');
        const data = await response.json();
        return data.isReady && document.querySelector('.content').offsetHeight > 0;
    },
    { polling: 'mutation' }
);

Este método combina la validación de respuestas de API con las comprobaciones de elementos del DOM, garantizando que tanto los datos como el contenido visual estén listos [1].

sbb-itb-23997f1

Métodos avanzados de waitForFunction

Escritura de condiciones complejas de JavaScript

Para aplicaciones web más dinámicas, puede utilizar waitForFunction para crear condiciones detalladas de JavaScript. Este es un ejemplo:

await page.waitForFunction(
    (threshold) => {
        const chart = document.querySelector('.tv-lightweight-charts');
        const dataPoints = chart?.querySelectorAll('.data-point');

        return chart && 
               dataPoints?.length > threshold && 
               Array.from(dataPoints).every(point => 
                   point.getBoundingClientRect().height > 0 &&
                   !point.classList.contains('loading')
               );
    },
    { polling: 'mutation' },
    5
);

Este script garantiza lo siguiente:

  • El contenedor del gráfico existe.
  • Hay un número mínimo de puntos de datos.
  • Todos los puntos de datos son visibles.
  • Ninguno de los puntos está en estado de carga.

También puede combinar comprobaciones asíncronas con evaluaciones del DOM para casos más complejos:

await page.waitForFunction(
    async () => {
        // Check if the container is ready
        const container = document.querySelector('.dynamic-content');
        if (!container || container.offsetHeight === 0) return false;

        // Validate API response
        try {
            const response = await fetch('/api/status');
            const data = await response.json();
            return data.isReady && container.children.length > 0;
        } catch {
            return false;
        }
    },
    { 
        polling: 'raf',
        timeout: 30000
    }
);

Este enfoque combina comprobaciones del DOM con una llamada a la API para garantizar que tanto la interfaz de usuario como el backend estén sincronizados.

Gestión de tiempos de espera y errores

La gestión de tiempos de espera es crucial al trabajar con waitForFunction. Este es un ejemplo de cómo gestionar los tiempos de espera eficazmente:

try {
    await page.setDefaultTimeout(60000); // Set a global timeout of 60 seconds

    await page.waitForFunction(
        () => {
            const element = document.querySelector('.dynamic-element');
            return element?.complete === true;
        },
        {
            timeout: 45000, // Specific timeout for this operation
            polling: 'mutation'
        }
    );
} catch (error) {
    if (error.name === 'TimeoutError') {
        console.error('Element state check timed out:', error.message);
        await page.reload(); // Reload page as a fallback
    }
    throw error;
}

A continuación, un resumen rápido de las estrategias de tiempo de espera:

Estrategia de tiempo de esperaCaso de usoConfiguración
Tiempo de espera predeterminadoOperaciones generalespage.setDefaultTimeout()
Tiempo de espera de navegaciónCargas de páginapage.setDefaultNavigationTimeout()
Específico por operaciónComprobaciones detalladasUse la opción timeout en el método
Espera infinitaRetrasos conocidostimeout: 0

Para mejorar la gestión de errores:

  • Ajuste la configuración de tiempo de espera según la complejidad de cada operación.
  • Use bloques try-catch para recuperarse de los errores de forma eficaz.
  • Supervise la actividad de red para identificar cuellos de botella.
  • Implemente acciones alternativas, como recargar la página, cuando se produzcan tiempos de espera.
  • Vuelva a comprobar los selectores para evitar retrasos innecesarios.

Estas prácticas ayudarán a garantizar que sus scripts sean fiables y eficientes.

Cómo hacer que waitForFunction se ejecute más rápido

Consejos de velocidad y recursos

Para que waitForFunction funcione de forma más eficiente, céntrese en estrategias de espera inteligentes y una gestión adecuada de los recursos. Use las herramientas de desarrollo del navegador para medir los tiempos de carga y establecer tiempos de espera precisos.

// Optimize waiting with a networkidle strategy
await page.goto('https://example.com', {
    waitUntil: 'networkidle2',
    timeout: 30000
});

// Combine checks in a single evaluate call
await page.evaluate(() => {
    const element = document.querySelector('.dynamic-content');
    const isVisible = element?.offsetHeight > 0;
    const hasData = element?.children.length > 0;
    return isVisible && hasData;
});

Para reducir el uso de recursos:

  • Bloquee recursos innecesarios, como imágenes o fuentes.
  • Use waitForSelector o waitForFunction en lugar de waitForTimeout, que está obsoleto.
  • Combine varias comprobaciones en una sola llamada evaluate para reducir la comunicación entre el navegador y Node.
EstrategiaImpacto en el rendimientoMejor caso de uso
networkidle2ModeradoNavegación de páginas
waitForSelectorRápidoComprobaciones de un solo elemento
waitForFunctionVariableCondiciones complejas
evaluate combinadoEl más rápidoComprobaciones de varios elementos

Estos métodos pueden ayudar a resolver cuellos de botella comunes, que se explican en la siguiente sección.

Solución de problemas habituales

Los problemas de rendimiento suelen deberse a patrones de espera ineficientes. A continuación, verá cómo resolverlos:

Problemas con los selectores
Los selectores demasiado rígidos pueden provocar fallos. Simplifíquelos para mejorar la fiabilidad:

// Avoid rigid selectors like this
await page.waitForSelector('div.container > div:nth-child(2) > span.text-red');

// Use a more flexible approach
await page.waitForFunction(
    () => document.querySelector('.text-red')?.offsetParent !== null
);

Gestión de recursos
Gestione los recursos y evite retrasos innecesarios:

try {
    await page.waitForFunction(
        () => document.readyState === 'complete' &&
              performance.now() > 1000
    );
} catch (error) {
    console.error('Page load timeout:', error.message);
}

"Puppeteer tiene una arquitectura basada en eventos que elimina gran parte de la inestabilidad potencial. No es necesario realizar llamadas maliciosas a sleep[undefined] en los scripts de puppeteer." - README de Puppeteer [6]

Incluya siempre los métodos de espera en bloques try...catch para gestionar los errores de forma eficaz y ofrecer opciones alternativas. Este enfoque garantiza que sus scripts sigan siendo sólidos y fiables.

Usos habituales de las reglas de espera personalizadas

Carga de productos en tiendas online

Garantizar que los productos se carguen correctamente es imprescindible para recopilar datos precisos. Use una regla de espera personalizada para pausar la ejecución hasta que los artículos de producto estén completamente cargados:

await page.waitForFunction(() => {
    const products = document.querySelectorAll('.product-card');
    return products.length > 0 && all images and prices fully load;
});

Para mayor precisión, puede utilizar este enfoque:

await page.waitForFunction(() => {
    const productDetails = document.querySelector('.product-details');
    return productDetails && 
           productDetails.offsetHeight > 0 && 
           productDetails.querySelector('.inventory-status') !== null;
}, {timeout: 30000});

Esto garantiza que su script espere a que se carguen todos los elementos necesarios, lo que mejora la fiabilidad de la recopilación de datos en casos de comercio electrónico.

Carga de contenido en aplicaciones web modernas

Las aplicaciones web dinámicas suelen requerir condiciones de espera específicas para gestionar la carga de contenido. Por ejemplo, puede esperar a que un elemento concreto sea completamente visible:

await page.waitForFunction(() => {
    const element = document.querySelector('.tv-lightweight-charts');
    return element && element.offsetHeight > 0 && element.offsetWidth > 0;
});

Si necesita que se carguen varias secciones, combine las condiciones de esta forma:

await page.waitForFunction(() => {
    const contentLoaded = document.querySelector('.content').children.length > 0;
    const dataUpdated = document.body.textContent.includes('Last updated:');
    return contentLoaded && dataUpdated;
}, {polling: 1000});

Este método ayuda a garantizar que sus scripts de automatización interactúen sin problemas con el contenido dinámico.

Detección de mensajes de error en formularios

La detección de errores de formulario utiliza una lógica similar a las comprobaciones de visibilidad de elementos. A continuación, verá cómo supervisar los mensajes de error:

await page.waitForFunction(() => {
    const errorContainer = document.querySelector('.error-messages');
    const hasErrors = errorContainer?.children.length > 0;
    const isVisible = errorContainer?.offsetParent !== null;
    return hasErrors && isVisible;
});

También puede rastrear diversos estados de validación de formularios mediante condiciones de espera específicas:

Tipo de validaciónCondición de esperaCaso de uso
Errores de campoComprobar la presencia de una clase de errorValidación de campos individuales
Errores de todo el formularioSupervisar el contenedor de erroresEstado general del formulario
Mensajes de éxitoObservar las confirmaciones mostradasFinalización del envío
Estados de cargaRastrear el estado del botón de envíoIndicación de procesamiento

Conclusión

Aspectos clave

El método waitForFunction de Puppeteer evalúa condiciones de JavaScript hasta que devuelven true, ofreciendo un control preciso sobre las interacciones dinámicas de la página [3].

Estos son algunos beneficios principales de utilizar waitForFunction:

  • Evaluación flexible: Gestiona funciones asíncronas para supervisar estados complejos de la página [3].
  • Integración de contexto: Permite pasar argumentos de Node.js directamente al contexto del navegador [3].
  • Lógica personalizada: Permite una automatización adaptada a condiciones específicas de la página [2].

Este enfoque resulta especialmente útil cuando los métodos de espera estándar no son suficientes. Por ejemplo, en aplicaciones avanzadas de una sola página, pueden cargarse varios elementos de forma simultánea o ser necesario confirmar estados específicos de JavaScript antes de continuar.

Puppeteer y Latenode en acción

Latenode aprovecha waitForFunction para mejorar la automatización de flujos. Al integrar este método, Latenode ha creado un nodo de supervisión personalizado que comprueba los estados de sitios web y captura pantallas cuando no se cumplen determinadas condiciones [7].

Este es un ejemplo de cómo Latenode utiliza waitForFunction para garantizar que los elementos críticos se rendericen completamente antes de continuar:

await page.waitForFunction(() => {
    const element = document.querySelector('.tv-lightweight-charts');
    return element && element.offsetHeight > 0 && element.offsetWidth > 0;
});

Este fragmento espera a que un elemento con la clase .tv-lightweight-charts no solo aparezca en el DOM, sino que también se renderice por completo [2].

Para obtener los mejores resultados al usar Latenode con Puppeteer:

  • Establezca valores de tiempo de espera adecuados mediante page.setDefaultTimeout().
  • Use bloques try-catch para una gestión sólida de errores.
  • Realice un seguimiento de los tiempos de ejecución para ajustar con precisión sus condiciones de espera.

References

FAQ

Frequently Asked Questions

waitForFunction evalúa periódicamente una condición de JavaScript en el contexto del navegador hasta que devuelve un valor evaluable como verdadero y, posteriormente, se resuelve. Úselo cuando waitForSelector estándar no sea suficiente para contenido dinámico, estados personalizados del DOM o comprobaciones combinadas de API y DOM.

¿Te resultó útil? Compártelo →

Escrito por

Vasiliy Datsenko

Jefe de Soporte al Cliente

Vasiliy Datsenko es Jefe de Soporte al Cliente en Latenode y un escritor de automatización centrado en productos. Su trabajo conecta las conversaciones con los clientes, la investigación sobre automatización de flujos de trabajo, los casos de uso de IA y la educación práctica sobre productos para equipos que intentan automatizar procesos comerciales reales.

Perfil del autor →

Verificado por

Oleg Zankov

CEO Latenode, No-code Expert

Con una ética arraigada en la innovación, la resolución de problemas y la experiencia de usuario, me enfoco en capacitar a los equipos para crear integraciones personalizadas y automatizar flujos de trabajo con facilidad y eficiencia. Trayendo una gran experiencia en desarrollo empresarial, emprendimiento tecnológico y desarrollo de software, reconocí la necesidad de una solución de integración más accesible, escalable y adaptable. Así nació Latenode.com. Con nuestra plataforma, las empresas pueden aprovechar el poder de la tecnología sin necesidad de conocimientos extensos de codificación. Apasionado por fomentar un futuro donde la tecnología nos sirva, y no al revés, mi misión es simplificar procesos complejos. Creo en democratizar la tecnología y equipar a los equipos con las herramientas para innovar, crecer y tener éxito en un mundo cada vez más digital.

Perfil del autor →

Seguir leyendo