Uma plataforma de baixo código que combina a simplicidade sem código com o poder do código completo 🚀
Comece gratuitamente
Depurando scripts do Puppeteer: do modo slowMo às técnicas avançadas
25 de março de 2025
.
10
min ler

Depurando scripts do Puppeteer: do modo slowMo às técnicas avançadas

Jorge Miloradovitch
Pesquisador, redator e entrevistador de casos de uso
Índice

depuração Marionetista scripts podem parecer esmagadores, mas dominar algumas técnicas-chave pode economizar tempo e frustração. Aqui está um rápido resumo do que você aprenderá:

  • Comece com a depuração visual: Usar slowMo modo de navegação e modo de navegação headful para observar seu script em ação.
  • Erros de captura: Adicionar try-catch blocos e automatizar capturas de tela de erros para melhor solução de problemas.
  • Aproveite os logs do console: Rastreie erros de página, solicitações com falha e mensagens personalizadas para obter insights mais profundos.
  • Seletores de alça e temporização: Use estratégias de seleção robustas e gerencie tempos limite para evitar armadilhas comuns.
  • Organize seu código: Divida os scripts em módulos para ações, seletores e validações para simplificar a manutenção.

Exemplo de configuração rápida:

const browser = await puppeteer.launch({
    headless: false,
    slowMo: 100,
    devtools: true
});

Dicas de depuração:

  1. Habilitar registro: Corra com DEBUG="puppeteer:*" para registros detalhados.
  2. Usar capturas de tela: Capture os estados das páginas para ver o que deu errado.
  3. Gerenciar recursos: Sempre limpe o navegador e as instâncias da página para evitar travamentos.

Ao combinar essas técnicas, você otimizará seu processo de depuração e aumentará a confiabilidade dos seus scripts do Puppeteer.

Configuração do ambiente de depuração

Configurações básicas de depuração

Configure o Puppeteer para depuração com estas opções de inicialização:

const browser = await puppeteer.launch({
    headless: false,
    slowMo: 20,
    devtools: true
});

Para habilitar o registro detalhado, execute seu script com o seguinte comando:

DEBUG="puppeteer:*" node script.js

Depois de configurado, use ferramentas de depuração para analisar e refinar o comportamento do seu script.

Ferramentas de depuração necessárias

Aqui estão algumas ferramentas para ajudar você a resolver problemas de forma eficaz:

ferramenta Propósito Característica chave
chromedevtools Inspecionar scripts Ferramentas de console e rede
Código VS Debugger Gerenciar pontos de interrupção Execução passo a passo
Utilitário de captura de tela Solução de problemas visuais Capturar estados da página

Você também pode adicionar pontos de verificação no seu código para melhor visibilidade:

await page.screenshot({ path: 'before_click.png' });
await page.click('#button');
await page.screenshot({ path: 'after_click.png' });

Organização do Script

Uma boa organização é tão importante quanto as ferramentas que você usa. Divida seu script em módulos lógicos e inclua tratamento de erros para uma depuração mais suave:

try {
    await page.waitForSelector('#target-element');
    await page.click('#target-element');
} catch (error) {
    console.error(`Navigation failed: ${error.message}`);
    await page.screenshot({ path: 'error-state.png' });
}

Para reduzir a chance de detecção de bots, integre o plugin stealth:

const puppeteer = require('puppeteer-extra');
const StealthPlugin = require('puppeteer-extra-plugin-stealth');
puppeteer.use(StealthPlugin());

Por fim, garanta o gerenciamento adequado dos recursos implementando procedimentos de limpeza:

async function cleanup() {
    if (page) await page.close();
    if (browser) await browser.close();
}

Esta configuração fornece uma base sólida para depuração visual e de console em seus projetos.

Marionetista - 3 abordagens a considerar na depuração

Marionetista

Métodos de depuração visual

Observar seus scripts em ação pode revelar problemas que a análise de código tradicional pode deixar passar. Esses métodos expandem suas opções de depuração além dos logs de console e rastreamento de erros.

Guia do modo SlowMo

O SlowMo introduz um atraso entre as ações do Puppeteer, facilitando o acompanhamento do que está acontecendo:

const browser = await puppeteer.launch({
    headless: false,
    slowMo: 250,
    devtools: true
});

A slowMo valor (em milissegundos) controla o atraso entre ações. Ajuste-o com base no que você está testando:

Tipo de operação SlowMo recomendado (ms) Caso de uso
Cliques simples 100-250 Passos básicos de navegação
Preenchimento de formularios 250-500 Testando validação de entrada
Conteúdo dinâmico 500-1000 Verificando estados de carregamento

Depois de configurar o SlowMo, emparelhe-o com o Modo de visualização do navegador para monitorar como a interface do usuário se comporta durante a execução do script.

Modo de visualização do navegador

O Modo de Exibição do Navegador permite que você veja seu script sendo executado em uma janela visível do navegador, o que é especialmente útil para depurar conteúdo dinâmico e interações complexas.

const browser = await puppeteer.launch({
    headless: false,
    defaultViewport: { width: 1700, height: 800 },
    args: ['--start-maximized']
});

Por exemplo, a Acme Corp.A equipe de QA da usou esse modo em junho de 2024 para solucionar problemas de um script de web scraping. Eles identificaram seletores incorretos e os corrigiram, reduzindo o tempo de depuração em 40%.

Para complementar isso, capture capturas de tela de estados visuais importantes para análise posterior.

Gravação Visual

Capturas de tela e vídeos podem criar um registro claro da execução do seu script, facilitando a depuração:

// Screenshot of a specific element
await page.screenshot({
    path: 'element-state.png',
    clip: {
        x: 0,
        y: 0,
        width: 500,
        height: 300
    }
});

// Full-page screenshot
await page.screenshot({
    path: 'full-page.png',
    fullPage: true
});

Comece habilitando o Modo de Visualização do Navegador, use o SlowMo para rastreamento detalhado e documente os principais momentos com capturas de tela. Juntos, esses passos criam um processo de depuração visual completo.

Métodos de depuração do console

Os métodos de console fornecem uma maneira direta de obter insights baseados em texto sobre como seus scripts estão se comportando. Essas saídas funcionam junto com a depuração visual para fornecer detalhes precisos sobre a execução do script.

Rastreamento de mensagens do console

O Puppeteer facilita a captura de mensagens do navegador com manipuladores de eventos como estes:

page.on('console', msg => {
    console.log('PAGE LOG:', msg.text());
});

page.on('pageerror', err => {
    console.error('PAGE ERROR:', err.message);
});

page.on('requestfailed', request => {
    console.error('REQUEST FAILED:', request.url());
});

Esta configuração cria um sistema de registro que rastreia mensagens de console, erros de página e solicitações com falha. Para deixar as coisas mais claras, você pode categorizar mensagens por tipo:

Tipo de mensagem Propósito Exemplo de saída
Folhas para Informações gerais Fluxo de execução padrão
erro Problemas maiores Operações com falha
Aviso Preocupações potenciais Lentidão no desempenho
Info Atualizações de status Conclusão da tarefa

Melhores práticas do Console.log

utilização console.log sabiamente pode tornar a depuração muito mais fácil. Coloque logs estrategicamente para rastrear o progresso e identificar problemas:

// Log before attempting to find an element
console.log(`Looking for element: ${selector}`);
const element = await page.$(selector);
// Log after confirming the element exists
console.log(`Element found: ${!!element}`);

// Log form data before filling it out
console.log(`Form data: ${JSON.stringify(formData)}`);
await page.type('#email', formData.email);

Métodos de registro estendidos

Para problemas mais complexos, técnicas avançadas de registro podem mudar o jogo:

// Enable detailed debugging for Puppeteer
process.env.DEBUG = 'puppeteer:*';
process.env.DEBUG_MAX_STRING_LENGTH = null;

// Monitor pending protocol calls
const browser = await puppeteer.launch({
    dumpio: true
});
console.log(browser.debugInfo.pendingProtocolErrors);

Uma equipe viu uma queda de 40% nas falhas de teste após adotar o registro detalhado de protocolos.

// Filter out specific network domain messages
// Command: DEBUG="puppeteer:*" DEBUG_COLORS=true node script.js 2>&1 | grep -v '"Network'

Esses métodos adicionam uma camada baseada em texto ao seu processo de depuração, ajudando você a detectar e resolver problemas de forma mais eficaz.

sbb-itb-23997f1

Métodos de depuração avançados

A depuração de scripts complexos do Puppeteer envolve o uso de estratégias eficazes de tratamento de erros e técnicas avançadas para garantir que os scripts sejam executados sem problemas.

Try-Catch para tratamento de erros

Use blocos try-catch para gerenciar erros de forma eficaz e manter seu script em execução:

async function navigateAndScreenshot(url, selector) {
    try {
        await page.goto(url, { waitUntil: 'networkidle0' });
        const element = await page.waitForSelector(selector, { timeout: 5000 });
        await element.screenshot({ path: 'element.png' });
    } catch (error) {
        if (error instanceof TimeoutError) {
            console.error(`Element ${selector} not found within timeout`);
            // Add recovery logic if needed
            await page.reload();
        } else {
            console.error(`Navigation failed: ${error.message}`);
            throw error; // Re-throw unexpected errors
        }
    }
}

Você pode melhorar o tratamento de erros combinando blocos try-catch com classes de erro personalizadas para melhor categorização e resposta.

Classes de erro personalizadas

A criação de classes de erro personalizadas ajuda você a identificar e classificar problemas de forma mais eficiente:

class PuppeteerScriptError extends Error {
    constructor(message, details = {}) {
        super(message);
        this.name = 'PuppeteerScriptError';
        this.details = details;
        this.timestamp = new Date().toISOString();
    }
}

class SelectorError extends PuppeteerScriptError {
    constructor(selector, context) {
        super(`Failed to find selector: ${selector}`, {
            selector,
            context,
            type: 'SELECTOR_ERROR'
        });
        this.name = 'SelectorError';
    }
}

Essas classes permitem que você rastreie e depure operações assíncronas com mais clareza.

Depuração de código assíncrono

Código assíncrono frequentemente introduz problemas de tempo e promessas não resolvidas. Enfrente esses problemas com as seguintes técnicas:

// Enable detailed debugging for protocol calls
const browser = await puppeteer.launch({
    dumpio: true
});

// Monitor unresolved promises periodically
setInterval(() => {
    const pending = browser.debugInfo.pendingProtocolErrors;
    if (pending.length > 0) {
        console.log('Pending protocol calls:', pending);
    }
}, 5000);

// Handle async errors with a timeout mechanism
async function safeExecute(promiseFn) {
    try {
        return await Promise.race([
            promiseFn(),
            new Promise((_, reject) => 
                setTimeout(() => reject(new Error('Operation timed out')), 30000)
            )
        ]);
    } catch (error) {
        console.error(`Operation failed: ${error.message}`);
        throw new PuppeteerScriptError('Execution timeout', {
            originalError: error,
            operation: promiseFn.name
        });
    }
}

Ao utilizar a blockchain da debugInfo interface, você pode monitorar retornos de chamada pendentes e identificar promessas não resolvidas durante a comunicação do protocolo do navegador.

Nível de depuração Propósito Implementação
Basico Lidar com erros comuns Blocos try-catch padrão
Nível intermediário Classificar erros Hierarquia de classes de erro personalizada
Avançado Problemas de protocolo de rastreamento Monitoramento de interface de depuração

Soluções para problemas comuns

Esta seção aborda os desafios frequentes do Puppeteer e fornece correções claras para manter seus scripts de automação funcionando sem problemas.

Problemas com o seletor

Problemas de seletor podem frequentemente interromper a execução do script. Veja como lidar com eles efetivamente:

async function findElement(page) {
  try {
    const element = await page.waitForSelector('[data-testid="target"]', {
      timeout: 5000
    });
    return element;
  } catch {
    return page.waitForSelector('.target-class', {
      timeout: 5000
    });
  }
}

Para elementos dentro de iframes ou Sombra DOM, use estas abordagens:

// Access iframe content
const frame = await page.frames().find(f => f.name() === 'content-frame');
const button = await frame.$('button[data-hook="create"]');

// Handle Shadow DOM elements
await page.evaluateHandle(selector => {
  const element = document.querySelector('parent-element')
    .shadowRoot
    .querySelector(selector);
  return element;
}, 'target-selector');

O manuseio adequado dos seletores garante que seus scripts localizem elementos de forma confiável.

Problemas de tempo

Uma vez que os seletores estejam estáveis, gerenciar o tempo é crucial para uma execução tranquila:

await page.setDefaultNavigationTimeout(30000);
await page.setDefaultTimeout(10000);

async function waitForContent(page) {
  await Promise.all([
    page.waitForNavigation({ waitUntil: 'networkidle0' }),
    page.click('#load-more-button')
  ]);
}

Aqui está uma referência rápida para controles de tempo:

Problema de tempo Solução Implementação
Carregamento de página esperarPorNavegação Aguarde a rede ociosa
Conteúdo Dinâmico esperarPorSeletor Use com tempo limite apropriado
Atualizações AJAX esperarPorResposta Monitorar solicitações de rede específicas

Essas estratégias ajudam a alinhar o tempo do seu script com o comportamento da página.

Correções de travamento do navegador

Mesmo com estratégias sólidas de seletor e tempo, travamentos do navegador ainda podem ocorrer. Veja como minimizar e se recuperar deles:

const browser = await puppeteer.launch({
  args: [
    '--disable-dev-shm-usage',
    '--enable-gpu',
    '--no-first-run',
    '--disable-extensions'
  ]
});

Para recuperação de falhas:

let browser;
try {
  browser = await puppeteer.launch();
  const page = await browser.newPage();

  page.on('error', err => {
    console.error('Page crashed:', err);
  });

  await page.goto('https://example.com');
} catch (error) {
  console.error('Browser error:', error);
} finally {
  if (browser) {
    await browser.close();
  }
}

Se você estiver trabalhando no Linux, verifique se há dependências ausentes:

ldd chrome | grep not

Para otimizar o uso de recursos, ajuste os sinalizadores do navegador:

const browser = await puppeteer.launch({
  args: [
    '--disable-dev-shm-usage',
    '--disable-accelerated-2d-canvas',
    '--disable-gpu'
  ]
});

Configure a recuperação automática para maior resiliência:

async function checkAndRecoverPage(page) {
  if (!page.isClosed()) {
    try {
      await page.reload();
    } catch {
      page = await browser.newPage();
    }
  }
  return page;
}

Otimização de Depuração de Script

Aprimore seus scripts para facilitar a manutenção e agilizar a resolução de erros com base em técnicas comprovadas de depuração.

Clareza de código

Mantenha seu código legível agrupando configurações e usando nomes claros e descritivos:

// Group related configurations
const browserConfig = {
  headless: false,
  defaultViewport: { width: 1920, height: 1080 },
  args: ['--no-sandbox', '--disable-setuid-sandbox']
};

// Use descriptive function names
async function validatePageContent(page) {
  const pageTitle = await page.title();
  console.log(`Validating content for page: ${pageTitle}`);

  const contentExists = await page.evaluate(() => {
    const mainContent = document.querySelector('.main-content');
    return {
      hasHeader: !!document.querySelector('header'),
      hasContent: !!mainContent,
      contentLength: mainContent?.textContent.length || 0
    };
  });

  return contentExists;
}

Organização do módulo

Divida seus scripts em módulos separados para simplificar a depuração. Essa abordagem isola seletores, ações e validações, facilitando a localização e a correção de erros.

// selectors.js
export const SELECTORS = {
  loginForm: '#login-form',
  submitButton: '[data-testid="submit-btn"]',
  errorMessage: '.error-notification'
};

// actions.js
export async function performLogin(page, credentials) {
  await page.type(SELECTORS.loginForm + ' input[name="username"]', credentials.username);
  await page.type(SELECTORS.loginForm + ' input[name="password"]', credentials.password);
  await Promise.all([
    page.waitForNavigation(),
    page.click(SELECTORS.submitButton)
  ]);
}

// validators.js
export async function checkLoginStatus(page) {
  const errorElement = await page.$(SELECTORS.errorMessage);
  if (errorElement) {
    throw new Error('Login failed: ' + await page.evaluate(el => el.textContent, errorElement));
  }
}

Essa estrutura modular não apenas organiza seu código, mas também ajuda a otimizar o rastreamento de erros.

Configuração de rastreamento de erros

Configure o rastreamento de erros para identificar problemas rapidamente e fornecer contexto detalhado para depuração:

class PuppeteerError extends Error {
  constructor(message, action, selector) {
    super(message);
    this.name = 'PuppeteerError';
    this.action = action;
    this.selector = selector;
    this.timestamp = new Date().toISOString();
  }
}

async function executeWithTracking(page, action, description) {
  try {
    await action();
  } catch (error) {
    const screenshot = await page.screenshot({
      path: `error-${Date.now()}.png`,
      fullPage: true
    });

    throw new PuppeteerError(
      `Failed to ${description}`,
      error.message,
      error.selector
    );
  }
}

Você também pode automatizar o registro de erros e avisos do console:

page.on('console', message => {
  const type = message.type();
  const text = message.text();

  if (type === 'error' || type === 'warning') {
    console.log(`[${type.toUpperCase()}] ${text}`);

    // Log to external service or file
    logger.log({
      level: type,
      message: text,
      timestamp: new Date().toISOString(),
      url: page.url()
    });
  }
});

Validação para Operações Críticas

Adicione verificações de validação para garantir que operações críticas sejam concluídas com sucesso:

async function validateOperation(page, action) {
  const beforeState = await page.evaluate(() => ({
    url: window.location.href,
    elements: document.querySelectorAll('*').length
  }));

  await action();

  const afterState = await page.evaluate(() => ({
    url: window.location.href,
    elements: document.querySelectorAll('*').length
  }));

  return {
    urlChanged: beforeState.url !== afterState.url,
    elementsDelta: afterState.elements - beforeState.elements
  };
}

Essas técnicas, combinadas com métodos de depuração anteriores, ajudam você a identificar e resolver problemas rapidamente, mantendo seus scripts sustentáveis.

Conclusão

Principais técnicas de depuração

Usando depuração visual no modo headful com slowMo permite feedback imediato sobre scripts e ajustes precisos de tempo. Para cenários mais detalhados, o protocolo DevTools fornece depuração passo a passo e acesso a logs de processo para insights mais profundos.

const browser = await puppeteer.launch({
    headless: false,
    slowMo: 100,
    devtools: true,
    dumpio: true
});

Para melhorar seu fluxo de trabalho, considere incorporar práticas de monitoramento contínuo e gerenciamento de recursos junto com esses métodos de depuração.

Próximos passos

Agora que você tem uma base sólida em técnicas de depuração, veja como você pode otimizar e manter seus scripts do Puppeteer:

  • Monitoramento de desempenho: Use o registro detalhado para rastrear tempos de execução e uso de recursos. Isso ajuda a identificar gargalos e torna a depuração mais eficiente.
  • Prevenção de erros: Adicione o puppeteer-extra-plugin-stealth plugin para minimizar a detecção de automação e reduzir falhas de script.
  • Gestão de Recursos: Concentre-se no uso eficiente da memória e implemente rotinas de limpeza para manter seus scripts funcionando sem problemas.

Aqui está um exemplo de uma função de limpeza para gerenciar recursos de forma eficaz:

async function cleanupResources(page) {
    await page.evaluate(() => {
        if (window.performance.memory) {
            console.log(`Heap size limit: ${(window.performance.memory.jsHeapSizeLimit / 1024 / 1024).toFixed(2)} MB`);
        }
    });
    await page.close();
}

Fique à frente verificando regularmente o repositório Puppeteer GitHub para atualizações, novos recursos e melhores práticas. Manter seu kit de ferramentas atualizado garante que seus scripts permaneçam eficientes e adaptáveis ​​conforme as tecnologias da web mudam.

Artigos Relacionados

Blogs relacionados

Caso de uso

Apoiado por