Como construir um painel de monitoramento de backlink com Node.js


Backlinks podem mudar após serem publicados. Uma página pode retornar um erro, um editor pode atualizar o texto âncora, um link pode se tornar nofollowou o URL de destino poderá redirecionar para algum lugar inesperado.

Verificar cada posicionamento manualmente torna-se impraticável quando um projeto possui dezenas ou centenas de links. Um pequeno aplicativo de monitoramento Node.js pode automatizar as verificações repetitivas e destacar apenas os canais que precisam de atenção.

Neste tutorial, construiremos o núcleo de um painel de monitoramento de backlinks. Ele lerá os registros de posicionamento de um arquivo CSV, solicitará cada página de origem, verificará a resposta, procurará o URL de destino e produzirá um resumo simples.

O que o monitor irá verificar

Nosso aplicativo examinará cada backlink e reportará:

  • Se a página de origem está acessível

  • O URL final após redirecionamentos

  • Se o link de destino ainda existe

  • Se o texto âncora esperado está presente

  • Se o link inclui nofollow, sponsoredou ugc

  • Quanto tempo leva a solicitação

  • Quando o backlink foi verificado pela última vez

Este não substitui um rastreador de SEO completo. O objetivo é criar uma ferramenta de monitoramento focada que os desenvolvedores possam entender, personalizar e conectar a um fluxo de trabalho existente.

1. Defina uma estrutura de dados consistente

As informações do backlink geralmente vêm de várias fontes. Uma equipe pode usar uma planilha, enquanto outra importa dados de um sistema de divulgação ou plataforma de relatórios.

Quer os registros venham de divulgação manual, de exportações de agências ou de um Mercado de backlinksnormalize-os na mesma estrutura antes de monitorá-los.

Para este tutorial, crie um arquivo chamado backlinks.csv:

source_url,target_url,anchor_text
https://example.com/article-one,https://mysite.com/javascript-guide,JavaScript guide
https://example.org/resources,https://mysite.com/node-tutorial,Node.js tutorial

Cada linha contém três valores importantes:

  • source_url: a página onde o backlink deve aparecer

  • target_url: o URL para o qual o backlink deve apontar

  • anchor_text: o texto do link visível esperado

Um sistema de produção também pode armazenar o nome da campanha, o proprietário da conta, a data de publicação, o atributo do link esperado e o resultado da verificação anterior.

Instale os pacotes necessários:

npm install csv-parse cheerio

Nós usaremos csv-parse para processar o arquivo CSV e Cheerio para inspecionar o HTML retornado.

Guia do SitePoint para Nó CSV fornece exemplos adicionais de análise, transformação e processamento de dados CSV em Node.js.

2. Leia e normalize o arquivo CSV

Crie um arquivo chamado monitor.js. Comece importando os módulos necessários e carregando os registros de backlink:

import fs from "node:fs/promises";
import { parse } from "csv-parse/sync";
import * as cheerio from "cheerio";

async function loadBacklinks(filePath) {
  const csv = await fs.readFile(filePath, "utf8");

  const records = parse(csv, {
    columns: true,
    skip_empty_lines: true,
    trim: true
  });

  return records.map((record, index) => {
    const sourceUrl = record.source_url?.trim();
    const targetUrl = record.target_url?.trim();
    const anchorText = record.anchor_text?.trim();

    if (!sourceUrl || !targetUrl || !anchorText) {
      throw new Error(
        `Row ${index + 2} is missing required backlink data.`
      );
    }

    return {
      sourceUrl,
      targetUrl,
      anchorText
    };
  });
}

Usando columns: true converte cada linha CSV em um objeto com base em seus nomes de cabeçalho. Cortar os valores evita que espaços acidentais causem falhas nas comparações.

A etapa de validação é importante. Se um registro incompleto atingir a função de monitoramento, o erro resultante poderá parecer uma falha de rede, mesmo que o problema real seja a falta de entrada.

3. Busque páginas com tempo limite

Um processo de monitoramento não deve esperar indefinidamente por um site que não responde. Usar AbortSignal.timeout() para dar a cada solicitação um limite de tempo definido:

async function fetchPage(url, timeoutMs = 10_000) {
  const startedAt = performance.now();

  try {
    const response = await fetch(url, {
      redirect: "follow",
      signal: AbortSignal.timeout(timeoutMs),
      headers: {
        "User-Agent": "BacklinkMonitor/1.0"
      }
    });

    const durationMs = Math.round(
      performance.now() - startedAt
    );

    if (!response.ok) {
      return {
        accessible: false,
        status: response.status,
        finalUrl: response.url,
        durationMs,
        html: null,
        error: `HTTP ${response.status}`
      };
    }

    return {
      accessible: true,
      status: response.status,
      finalUrl: response.url,
      durationMs,
      html: await response.text(),
      error: null
    };
  } catch (error) {
    return {
      accessible: false,
      status: null,
      finalUrl: url,
      durationMs: Math.round(
        performance.now() - startedAt
      ),
      html: null,
      error: error.name === "TimeoutError"
        ? "Request timed out"
        : error.message
    };
  }
}

A função retorna um resultado consistente para respostas bem-sucedidas, erros HTTP, tempos limite e outras falhas de rede.

Seguir redirecionamentos é útil porque um artigo de origem pode ser movido para um novo URL. No entanto, o painel deve registrar a URL final para que a equipe possa decidir se o endereço de origem armazenado precisa ser atualizado.

Use um agente de usuário claro e honesto. Os proprietários de sites podem bloquear solicitações automatizadas e seu rastreador não deve fingir ser um navegador normal.

Assim que o HTML estiver disponível, carregue-o no Cheerio e inspecione cada link:

function normalizeUrl(value) {
  const url = new URL(value);
  url.hash = "";

  if (url.pathname !== "/") {
    url.pathname = url.pathname.replace(/\/+$/, "");
  }

  return url.toString();
}

function inspectBacklink(html, backlink, sourceUrl) {
  const $ = cheerio.load(html);
  const expectedTarget = normalizeUrl(backlink.targetUrl);

  let result = null;

  $("a(href)").each((_, element) => {
    if (result) {
      return;
    }

    const href = $(element).attr("href");
    const text = $(element).text()
      .replace(/\s+/g, " ")
      .trim();

    try {
      const resolvedUrl = normalizeUrl(
        new URL(href, sourceUrl).toString()
      );

      if (resolvedUrl !== expectedTarget) {
        return;
      }

      const relValues = (
        $(element).attr("rel") || ""
      )
        .toLowerCase()
        .split(/\s+/)
        .filter(Boolean);

      result = {
        linkFound: true,
        anchorText: text,
        anchorMatches:
          text.toLowerCase() ===
          backlink.anchorText.toLowerCase(),
        nofollow: relValues.includes("nofollow"),
        sponsored: relValues.includes("sponsored"),
        ugc: relValues.includes("ugc")
      };
    } catch {
      
    }
  });

  return result || {
    linkFound: false,
    anchorText: null,
    anchorMatches: false,
    nofollow: false,
    sponsored: false,
    ugc: false
  };
}

Links relativos requerem tratamento especial. Chamando new URL(href, sourceUrl) converte um caminho como /guides/javascript em um URL absoluto antes da comparação.

A função de normalização remove fragmentos e barras finais. Dependendo dos seus requisitos, você também pode querer normalizar parâmetros de rastreamento comuns. Tenha cuidado para não remover parâmetros de consulta que alterem o destino real.

5. Execute a auditoria completa

Conecte o carregador CSV, a função de solicitação e a função de inspeção:

async function auditBacklinks(filePath) {
  const backlinks = await loadBacklinks(filePath);
  const results = ();

  for (const backlink of backlinks) {
    const page = await fetchPage(backlink.sourceUrl);

    if (!page.accessible) {
      results.push({
        ...backlink,
        checkedAt: new Date().toISOString(),
        status: "unreachable",
        responseStatus: page.status,
        finalSourceUrl: page.finalUrl,
        durationMs: page.durationMs,
        error: page.error
      });

      continue;
    }

    const inspection = inspectBacklink(
      page.html,
      backlink,
      page.finalUrl
    );

    let status = "healthy";

    if (!inspection.linkFound) {
      status = "missing";
    } else if (!inspection.anchorMatches) {
      status = "anchor_changed";
    } else if (
      inspection.nofollow ||
      inspection.sponsored ||
      inspection.ugc
    ) {
      status = "attribute_changed";
    }

    results.push({
      ...backlink,
      ...inspection,
      checkedAt: new Date().toISOString(),
      status,
      responseStatus: page.status,
      finalSourceUrl: page.finalUrl,
      durationMs: page.durationMs,
      error: null
    });
  }

  return results;
}

const results = await auditBacklinks("./backlinks.csv");

console.table(
  results.map(result => ({
    source: result.sourceUrl,
    status: result.status,
    http: result.responseStatus,
    time: `${result.durationMs}ms`
  }))
);

await fs.writeFile(
  "./backlink-report.json",
  JSON.stringify(results, null, 2)
);

Esta versão processa backlinks sequencialmente. Isso é mais lento do que enviar todas as solicitações simultaneamente, mas é mais fácil em sites externos e mais simples de depurar.

Para um conjunto de dados maior, use um limitador de simultaneidade em vez de um irrestrito Promise.all(). A execução de centenas de solicitações de uma só vez pode consumir memória desnecessária, acionar limites de taxa e fazer com que o tráfego de monitoramento se assemelhe a um rastreador abusivo.

6. Transforme resultados em status úteis

Os dados brutos do rastreador nem sempre são úteis para a pessoa que analisa o relatório. Converta condições técnicas em status claros:

  • healthy: a página carrega e o backlink esperado está presente

  • missing: o URL de destino não está mais vinculado

  • anchor_changed: o link existe, mas usa texto diferente

  • attribute_changed: o link ganhou um monitoramento rel valor

  • unreachable: a página expirou ou retornou uma resposta malsucedida

Evite relatar um backlink como perdido permanentemente após uma solicitação com falha. Problemas temporários de servidor, limites de taxa e falhas de rede podem produzir alarmes falsos.

Uma política mais segura é exigir duas ou três falhas consecutivas antes de criar um alerta. Armazene os resultados anteriores em um banco de dados para que o monitor possa distinguir um erro temporário de uma alteração duradoura.

7. Adicione um pequeno painel

O JSON gerado pode alimentar um painel de front-end simples. Componentes úteis incluem:

  • Um resumo mostrando links saudáveis ​​e problemáticos

  • Filtros para projeto, status e data de verificação

  • Uma tabela com URL de origem, âncora esperada, âncora real e código de resposta

  • Uma visualização do histórico mostrando quando cada status foi alterado

  • Um botão de nova tentativa para verificações com falha

  • Opções de exportação para CSV e JSON

Os gráficos podem ajudar os usuários a ver tendências, como a porcentagem de links íntegros ao longo do tempo. Visão geral do SitePoint de Bibliotecas de gráficos JavaScript pode ajudá-lo a comparar opções de visualização adequadas.

Mantenha a tabela como interface principal. Um gráfico pode mostrar o padrão geral, mas os desenvolvedores e gerentes de campanha ainda precisam dos registros individuais para investigar um problema.

Considerações de produção

Antes de implantar o monitor, adicione controles para segurança e confiabilidade.

Valide cada URL antes de solicitá-lo. Se os usuários puderem enviar URLs de origem arbitrários, o monitor poderá se tornar vulnerável à falsificação de solicitações do servidor. Bloqueie intervalos de IP privados, nomes de host locais, protocolos não suportados e endpoints de metadados em nuvem.

Você também deve:

  • Limite o número de verificações que cada usuário pode agendar

  • Aplicar atrasos nas solicitações por domínio

  • Armazenar em cache as respostas recentes

  • Defina tamanhos máximos de resposta

  • Armazene apenas as informações HTML que você precisa

  • Proteja o acesso ao painel com autenticação

  • Registrar alterações de status em um log de auditoria

  • Respeite as políticas do site e as restrições de rastreamento aplicáveis

O monitoramento deve permanecer leve. O aplicativo precisa de informações suficientes para confirmar o link, e não de uma cópia completa de cada página visitada.

Considerações finais

Um monitor de backlink é um projeto Node.js gerenciável que combina processamento CSV, solicitações HTTP, análise de HTML, normalização de URL e relatórios de status.

A primeira versão pode permanecer simples: importar registros, solicitar cada página de origem, encontrar o destino esperado e salvar o resultado. A partir daí, você pode adicionar verificações agendadas, dados históricos, alertas, autenticação e um painel visual.

A escolha de design mais importante é a consistência. Normalize os registros recebidos, classifique os resultados com status previsíveis e aguarde falhas repetidas antes de emitir um alerta. Isso produz dados de monitoramento úteis sem sobrecarregar os usuários com alarmes falsos.



Source link