Pular para conteúdo

PARSE_CUSTOM - Extração Personalizada com Seletores CSS

O que é este Node?

O PARSE_CUSTOM é o node responsável por extrair elementos específicos de HTML usando seletores CSS, permitindo extrações precisas e personalizadas de qualquer conteúdo HTML.

Por que este Node existe?

Muitas vezes você precisa extrair apenas partes específicas de um HTML complexo. O PARSE_CUSTOM existe para:

  1. Precisão: Extrair exatamente o que você precisa usando seletores CSS
  2. Flexibilidade: Definir múltiplos seletores para extrair vários elementos diferentes
  3. Simplicidade: Evitar processamento de HTML irrelevante
  4. Automação: Criar scrapers personalizados para estruturas HTML específicas

Como funciona internamente?

Quando o PARSE_CUSTOM é executado, o sistema:

  1. Carrega o HTML: Usa Cheerio para parsear o documento
  2. Limpa conteúdo: Remove scripts e estilos (se configurado)
  3. Aplica seletor único: Se selector está definido, extrai texto do elemento
  4. Aplica seletores múltiplos: Se multipleSelectors está definido, processa linha por linha no formato nome: seletor
  5. Retorna resultado: Texto simples (selector único) ou JSON (múltiplos seletores)

Código interno (html-parser-executor.service.ts:376-409):

private parseCustom($: CheerioAPI, config: HTMLParserNodeData): string {
  // Single selector
  if (config.selector) {
    const element = $(config.selector);
    return element.text().trim();
  }

  // Multiple selectors
  if (config.multipleSelectors) {
    const result: Record<string, string> = {};
    const lines = config.multipleSelectors.split('\n');

    for (const line of lines) {
      const match = line.match(/^([^:]+):\s*(.+)$/);
      if (match) {
        const [, name, selector] = match;
        const trimmedName = name.trim();
        const trimmedSelector = selector.trim();

        try {
          const element = $(trimmedSelector);
          result[trimmedName] = element.text().trim();
        } catch (error) {
          this.logger.warn(`Invalid selector for ${trimmedName}: ${trimmedSelector}`);
          result[trimmedName] = '';
        }
      }
    }

    return JSON.stringify(result, null, 2);
  }

  return '';
}

Quando você DEVE usar este Node?

Use PARSE_CUSTOM sempre que precisar de extrair elementos específicos por seletores CSS:

Casos de uso

  1. Web Scraping específico: "Extrair apenas o preço de produtos em uma página de e-commerce"
  2. Extração de metadados: "Pegar título, autor e data de artigos de blog"
  3. Monitoramento de sites: "Extrair contador de visitantes ou status de serviço"
  4. Integração com sites: "Obter dados específicos de dashboards ou painéis"

Quando NÃO usar PARSE_CUSTOM

  • Precisa de todo o conteúdo: Use parse_text ou parse_markdown
  • Precisa de estrutura completa: Use parse_structured
  • Não sabe os seletores CSS: Use parse_text ou parse_structured primeiro

Parâmetros Detalhados

selector (string, opcional - requer custom mode)

O que é: Seletor CSS único para extrair um elemento específico.

Padrão: Não definido

Flow completo para testar:

{
  "name": "Teste HTML Parser - Selector Único",
  "nodes": [
    {
      "id": "start_1",
      "type": "start",
      "position": { "x": 100, "y": 100 },
      "data": { "label": "Início" }
    },
    {
      "id": "variable_1",
      "type": "variable",
      "position": { "x": 300, "y": 100 },
      "data": {
        "label": "HTML Produto",
        "parameters": {
          "variableName": "produto_html",
          "variableValue": "<div class='produto'><h1 class='titulo'>iPhone 15</h1><span class='preco'>R$ 7.999,00</span><p class='descricao'>Smartphone Apple</p></div>"
        }
      }
    },
    {
      "id": "parser_1",
      "type": "html_parser",
      "position": { "x": 500, "y": 100 },
      "data": {
        "label": "Extrair Preço",
        "parameters": {
          "inputVariable": "produto_html",
          "parseMode": "custom",
          "selector": ".preco",
          "outputVariable": "preco"
        }
      }
    },
    {
      "id": "message_1",
      "type": "message",
      "position": { "x": 700, "y": 100 },
      "data": {
        "label": "Mostrar",
        "parameters": {
          "message": "Preço: {{preco}}"
        }
      }
    },
    {
      "id": "end_1",
      "type": "end",
      "position": { "x": 900, "y": 100 },
      "data": { "label": "Fim" }
    }
  ],
  "edges": [
    { "source": "start_1", "target": "variable_1" },
    { "source": "variable_1", "target": "parser_1" },
    { "source": "parser_1", "target": "message_1" },
    { "source": "message_1", "target": "end_1" }
  ]
}

Teste: Esperado: "Preço: R$ 7.999,00"

multipleSelectors (string, opcional - requer custom mode)

O que é: Múltiplos seletores no formato nome: seletor (um por linha).

Padrão: Não definido

Flow completo para testar:

{
  "name": "Teste HTML Parser - Múltiplos Seletores",
  "nodes": [
    {
      "id": "start_1",
      "type": "start",
      "position": { "x": 100, "y": 100 },
      "data": { "label": "Início" }
    },
    {
      "id": "variable_1",
      "type": "variable",
      "position": { "x": 300, "y": 100 },
      "data": {
        "label": "Artigo HTML",
        "parameters": {
          "variableName": "artigo_html",
          "variableValue": "<article><h1 class='titulo'>Notícia Importante</h1><span class='autor'>João Silva</span><time class='data'>2025-01-15</time><div class='conteudo'>Texto da notícia aqui.</div></article>"
        }
      }
    },
    {
      "id": "parser_1",
      "type": "html_parser",
      "position": { "x": 500, "y": 100 },
      "data": {
        "label": "Extrair Metadados",
        "parameters": {
          "inputVariable": "artigo_html",
          "parseMode": "custom",
          "multipleSelectors": "titulo: .titulo\nautor: .autor\ndata: .data\nconteudo: .conteudo",
          "outputVariable": "metadados"
        }
      }
    },
    {
      "id": "message_1",
      "type": "message",
      "position": { "x": 700, "y": 100 },
      "data": {
        "label": "Mostrar",
        "parameters": {
          "message": "Dados extraídos:\n{{metadados}}"
        }
      }
    },
    {
      "id": "end_1",
      "type": "end",
      "position": { "x": 900, "y": 100 },
      "data": { "label": "Fim" }
    }
  ],
  "edges": [
    { "source": "start_1", "target": "variable_1" },
    { "source": "variable_1", "target": "parser_1" },
    { "source": "parser_1", "target": "message_1" },
    { "source": "message_1", "target": "end_1" }
  ]
}

Teste: Esperado: JSON com titulo, autor, data e conteudo

Parâmetros

Campo Tipo Obrigatório Descrição
inputVariable string Sim Variável com HTML
parseMode string Sim Deve ser "custom"
selector string Condicional Seletor CSS único (ou use multipleSelectors)
multipleSelectors string Condicional Múltiplos seletores (formato: nome: seletor)
outputVariable string Não Variável para resultado (padrão: "parsed_content")
removeScripts boolean Não Remove scripts (padrão: true)
removeStyles boolean Não Remove styles (padrão: true)

Exemplo 1: Monitorar Preço de Produto

Objetivo: Extrair preço específico de página de e-commerce

JSON para Importar

{
  "name": "Monitor de Preço de Produto",
  "nodes": [
    {
      "id": "start_1",
      "type": "start",
      "position": { "x": 100, "y": 100 },
      "data": { "label": "Início" }
    },
    {
      "id": "scraper_1",
      "type": "web_scraper",
      "position": { "x": 300, "y": 100 },
      "data": {
        "label": "Buscar Página",
        "parameters": {
          "url": "https://example.com/produto/123",
          "outputVariable": "page_html"
        }
      }
    },
    {
      "id": "parser_1",
      "type": "html_parser",
      "position": { "x": 500, "y": 100 },
      "data": {
        "label": "Extrair Dados",
        "parameters": {
          "inputVariable": "page_html",
          "parseMode": "custom",
          "multipleSelectors": "nome: h1.product-title\npreco: span.price\nestoque: div.stock-status",
          "outputVariable": "produto_info"
        }
      }
    },
    {
      "id": "condition_1",
      "type": "condition",
      "position": { "x": 700, "y": 100 },
      "data": {
        "label": "Preço Baixou?",
        "parameters": {
          "condition": "{{produto_info.preco}} < 5000"
        }
      }
    },
    {
      "id": "message_1",
      "type": "message",
      "position": { "x": 900, "y": 50 },
      "data": {
        "label": "Alertar",
        "parameters": {
          "message": "🎉 Preço baixou!\n{{produto_info.nome}}: {{produto_info.preco}}"
        }
      }
    },
    {
      "id": "end_1",
      "type": "end",
      "position": { "x": 1100, "y": 100 },
      "data": { "label": "Fim" }
    }
  ],
  "edges": [
    { "source": "start_1", "target": "scraper_1" },
    { "source": "scraper_1", "target": "parser_1" },
    { "source": "parser_1", "target": "condition_1" },
    { "source": "condition_1", "target": "message_1", "label": "true" },
    { "source": "condition_1", "target": "end_1", "label": "false" },
    { "source": "message_1", "target": "end_1" }
  ]
}

Saída esperada:

Sistema: 🎉 Preço baixou!
iPhone 15: R$ 4.999,00

Exemplo 2: Extração de Metadados de Blog

Objetivo: Extrair título, autor, data e resumo de artigo

JSON para Importar

{
  "name": "Extração de Metadados Blog",
  "nodes": [
    {
      "id": "start_1",
      "type": "start",
      "position": { "x": 100, "y": 100 },
      "data": { "label": "Início" }
    },
    {
      "id": "input_1",
      "type": "input",
      "position": { "x": 300, "y": 100 },
      "data": {
        "label": "URL do Artigo",
        "parameters": {
          "message": "Digite a URL do artigo:",
          "variableName": "url"
        }
      }
    },
    {
      "id": "scraper_1",
      "type": "web_scraper",
      "position": { "x": 500, "y": 100 },
      "data": {
        "label": "Buscar Artigo",
        "parameters": {
          "url": "{{url}}",
          "outputVariable": "artigo_html"
        }
      }
    },
    {
      "id": "parser_1",
      "type": "html_parser",
      "position": { "x": 700, "y": 100 },
      "data": {
        "label": "Extrair Metadados",
        "parameters": {
          "inputVariable": "artigo_html",
          "parseMode": "custom",
          "multipleSelectors": "titulo: article h1\nautor: .author-name\ndata: time.published\nresumo: .article-excerpt",
          "outputVariable": "metadados"
        }
      }
    },
    {
      "id": "message_1",
      "type": "message",
      "position": { "x": 900, "y": 100 },
      "data": {
        "label": "Exibir",
        "parameters": {
          "message": "📰 Artigo\n\n✏️ {{metadados.titulo}}\n👤 Por {{metadados.autor}}\n📅 {{metadados.data}}\n\n📝 {{metadados.resumo}}"
        }
      }
    },
    {
      "id": "end_1",
      "type": "end",
      "position": { "x": 1100, "y": 100 },
      "data": { "label": "Fim" }
    }
  ],
  "edges": [
    { "source": "start_1", "target": "input_1" },
    { "source": "input_1", "target": "scraper_1" },
    { "source": "scraper_1", "target": "parser_1" },
    { "source": "parser_1", "target": "message_1" },
    { "source": "message_1", "target": "end_1" }
  ]
}

Saída esperada:

Sistema: 📰 Artigo

✏️ Como Usar Seletores CSS
👤 Por Maria Santos
📅 2025-01-15

📝 Aprenda a usar seletores CSS para extrair dados de HTML

Resposta do Node

{
  "success": true,
  "data": {
    "parsed_content": "{\"titulo\":\"...\",\"autor\":\"...\"}",
    "stats": {
      "originalLength": 850,
      "parsedLength": 120,
      "mode": "custom"
    }
  },
  "executionTime": 42
}

Boas Práticas

SIM:

  • Use seletores CSS específicos (.class, #id, [attribute])
  • Teste seletores no DevTools do navegador primeiro
  • Use multipleSelectors para extrair múltiplos campos de uma vez
  • Combine com web_scraper para automação completa
  • Valide se os elementos existem antes de processar

NÃO:

  • Não use seletores muito genéricos (div, span) - seja específico
  • Não confie que a estrutura HTML nunca mudará
  • Não esqueça de tratar casos onde o seletor não encontra nada
  • Não use quando não souber a estrutura HTML (use parse_structured primeiro)

Dicas

💡 Dica 1: Use seletores CSS complexos como div.product > span.price:first-child para precisão máxima

💡 Dica 2: multipleSelectors retorna JSON - fácil de acessar com {{variavel.campo}}

💡 Dica 3: Se o seletor não encontrar nada, retorna string vazia (não dá erro)

💡 Dica 4: Teste seletores usando console do navegador: document.querySelector('seu-seletor')

💡 Dica 5: Combine com SCHEDULE para monitoramento periódico de sites

Próximo Node

PARSE_TEXT - Extrai texto puro sem estrutura → PARSE_MARKDOWN - Converte HTML para Markdown → PARSE_STRUCTURED - Extrai estrutura completa do HTML → EXTRACT_LINKS - Extrai todos os links do HTML