Dev Tools

Como Parsear Arquivos CNAB em Node.js e Python

Aprenda a ler, fatiar e validar arquivos de remessa e retorno CNAB 240 e 400 em Node.js e Python com exemplos de código prontos.

22 de julho de 20266 min de leituraDevThru

Integrar sistemas com arquivos bancários CNAB 240 e CNAB 400 (FEBRABAN) costuma ser um desafio para desenvolvedores. Por se tratar de um formato posicional de colunas fixas sem delimitadores como vírgula ou ponto e vírgula, qualquer erro no fatiamento da string pode corromper dados financeiros importantes, como valores pagos, datas de liquidação ou códigos de ocorrência.

Neste artigo prático, vamos mostrar como estruturar um parser robusto em Node.js (TypeScript) e Python para ler arquivos de Remessa (.rem) e Retorno (.ret), extrair registros com segurança e validar a integridade do arquivo.

O Conceito de Slicing Posicional

No padrão CNAB, cada linha representa um registro e cada campo ocupa posições específicas (1-indexed na documentação da FEBRABAN). Em linguagens de programação (0-indexed), devemos converter essas posições para índices de substring:

Campo FEBRABAN Posição Manual (FEBRABAN) Índices em Código (0-indexed) Tamanho
Código do Banco 001 a 003 slice(0, 3) 3 caracteres
Lote de Serviço 004 a 007 slice(3, 7) 4 caracteres
Tipo de Registro 008 a 008 slice(7, 8) 1 caractere
💡 Dica de Ouro: Antes de processar um arquivo CNAB em produção, certifique-se de que cada linha possède exatamente 240 caracteres (para CNAB 240) ou 400 caracteres (para CNAB 400). Se a linha tiver comprimento diferente, trate como um arquivo inválido.

Exemplo 1: Parser CNAB em Node.js / TypeScript

Abaixo está um exemplo limpo utilizando TypeScript para parsear o Header e os Detalhes de um arquivo CNAB 240 de Retorno Bancário:

import * as fs from 'fs';
import * as path from 'path';

interface CNAB240Header {
  codigoBanco: string;
  lote: string;
  tipoInscricao: string;
  numeroInscricao: string;
  nomeEmpresa: string;
}

interface CNAB240SegmentoP {
  nossoNumero: string;
  vencimento: string;
  valorTitulo: number;
}

export function parseCNAB240(conteudoArquivo: string) {
  const linhas = conteudoArquivo.split(/
?
/).filter(l => l.length > 0);

  const titulos: CNAB240SegmentoP[] = [];

  for (const linha of linhas) {
    // Validação de comprimento da linha
    if (linha.length !== 240) {
      console.warn(`Linha ignorada: tamanho ${linha.length} é diferente de 240.`);
      continue;
    }

    const tipoRegistro = linha.slice(7, 8); // Posição 8

    // Registro Tipo 0: Header de Arquivo
    if (tipoRegistro === '0') {
      const banco = linha.slice(0, 3);
      const empresa = linha.slice(72, 102).trim();
      console.log(`Processando arquivo do banco ${banco} para ${empresa}`);
    }

    // Registro Tipo 3: Segmento de Detalhe
    if (tipoRegistro === '3') {
      const codigoSegmento = linha.slice(13, 14); // Posição 14
      
      // Segmento P (Dados do Título)
      if (codigoSegmento === 'P') {
        const nossoNumero = linha.slice(37, 57).trim();
        const dataVenc = linha.slice(77, 85); // DDMMAAAA
        const valorEmCents = parseInt(linha.slice(85, 100), 10);
        
        titulos.push({
          nossoNumero,
          vencimento: `${dataVenc.slice(0,2)}/${dataVenc.slice(2,4)}/${dataVenc.slice(4,8)}`,
          valorTitulo: valorEmCents / 100
        });
      }
    }
  }

  return titulos;
}

Exemplo 2: Parser CNAB em Python

Em Python, podemos utilizar a sintaxe nativa de fatiamento de strings (string[start:end]) para ler um arquivo CNAB 400 de cobrança:

def parse_cnab_400(filepath: str):
    registros_pagos = []

    with open(filepath, 'r', encoding='latin1') as f:
        for index, line in enumerate(f, start=1):
            line = line.rstrip('
')
            
            if len(line) != 400:
                print(f"Alerta Linha {index}: Comprimento incorreto ({len(line)} caracteres)")
                continue

            tipo_registro = line[0:1]

            # Registro Detalhe Tipo 1 (Cobrança)
            if tipo_registro == '1':
                nosso_numero = line[62:70].strip()
                carteira = line[107:108]
                ocorrencia = line[108:110] # 06 = Liquidação/Pago
                data_ocorrencia = line[110:116] # DDMMAA
                valor_pago_cents = int(line[253:266] or '0')

                # Ocorrência 06 indica título pago
                if ocorrencia == '06':
                    registros_pagos.append({
                        "nosso_numero": nosso_numero,
                        "carteira": carteira,
                        "data_pagamento": f"{data_ocorrencia[0:2]}/{data_ocorrencia[2:4]}/20{data_ocorrencia[4:6]}",
                        "valor_pago": valor_pago_cents / 100.0
                    })

    return registros_pagos

# Exemplo de execução
# pagamentos = parse_cnab_400('retorno_itau.ret')
# print(pagamentos)

Boas Práticas de Engenharia ao Tratar CNAB

  1. Encoding de Caracteres: Muitos bancos legados enviam arquivos CNAB em encoding ISO-8859-1 (Latin1) ou ASCII em vez de UTF-8. Sempre trate a codificação do arquivo ao ler o buffer.
  2. Tratamento de Valores Monetários: Nunca converta diretamente os dígitos inteiros sem dividir por 100.0 (ex: 000000015050 representa R$ 150,50).
  3. Idempotência na Processamento de Retorno: Arquivos de retorno bancários podem ser baixados mais de uma vez. Sempre utilize a combinação de Banco + Nosso Número + Data de Ocorrência como chave de idempotência no banco de dados.

Testando e Inspecionando Arquivos CNAB

Quer verificar se o seu arquivo CNAB está configurado corretamente com as posições certas antes de colocar o código em produção? Utilize a ferramenta Leitor e Decodificador de CNAB do DevThru para visualizar os campos fatiados com syntax highlighting instantâneo!

🛠️ Experimente na prática

Use nossas ferramentas online gratuitas — sem cadastro, direto no navegador.

CNABNode.jsPythonparsingFEBRABANboletosfintech

Esse artigo foi útil para você?