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:
- Precisão: Extrair exatamente o que você precisa usando seletores CSS
- Flexibilidade: Definir múltiplos seletores para extrair vários elementos diferentes
- Simplicidade: Evitar processamento de HTML irrelevante
- Automação: Criar scrapers personalizados para estruturas HTML específicas
Como funciona internamente?
Quando o PARSE_CUSTOM é executado, o sistema:
- Carrega o HTML: Usa Cheerio para parsear o documento
- Limpa conteúdo: Remove scripts e estilos (se configurado)
- Aplica seletor único: Se
selectorestá definido, extrai texto do elemento - Aplica seletores múltiplos: Se
multipleSelectorsestá definido, processa linha por linha no formatonome: seletor - 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
- Web Scraping específico: "Extrair apenas o preço de produtos em uma página de e-commerce"
- Extração de metadados: "Pegar título, autor e data de artigos de blog"
- Monitoramento de sites: "Extrair contador de visitantes ou status de serviço"
- 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_textouparse_markdown - Precisa de estrutura completa: Use
parse_structured - Não sabe os seletores CSS: Use
parse_textouparse_structuredprimeiro
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