Voltar ao blogue

Web Scraping com Node-Unblocker: Um guia prático

Web Scraping com Node-Unblocker: Um guia prático
Resumo: O Node-unblocker transforma uma aplicação Express num proxy HTTP com prefixo de URL que pode ser personalizado. Este guia sobre o Node-unblocker para web scraping explica como instalá-lo, configurar middlewares de pedidos e respostas, rodar instâncias, implementar no Docker ou no Heroku e perceber quando uma API de scraping gerida é a opção mais sensata.

Se alguma vez precisou de adicionar um salto de proxy personalizado à frente de um scraper Node.js, provavelmente deparou-se com o meio-termo incómodo entre «basta usar um endpoint SOCKS5» e «implementar uma frota de proxies real». A configuração do Node-unblocker para web scraping situa-se confortavelmente nesse meio-termo: é um proxy leve, programável e montável no Express que pode ser estendido com JavaScript.

O Node-unblocker é uma biblioteca Node.js com uma API compatível com Express. Inicia uma instância, monta-a num prefixo de rota como /proxy/, e qualquer URL anexada a esse prefixo é obtida, reescrita e transmitida de volta para o chamador. Como tudo é executado no seu próprio processo Node, pode anexar middlewares para alterar pedidos e respostas, trocar o IP por ambiente e incorporar lógica de negócio no próprio proxy.

Este artigo foi escrito para programadores Node.js de nível intermédio que procuram um proxy Node Unblocker funcional para web scraping, e não uma apresentação de marketing. Abordaremos a instalação, a configuração mínima do Express, o objeto de configuração, middlewares de solicitação e resposta, um padrão de pool de proxies rotativos, dois caminhos de implementação em produção (Docker e Heroku), as restrições legais e éticas, e o limite em que a biblioteca deixa de ser útil.

Web Scraping Node Unblocker: O que é e por que é importante

O Node-unblocker é uma biblioteca de servidor proxy Node.js que expõe uma API compatível com Express para criar um proxy personalizado com apenas algumas linhas de código. Foi originalmente construído para contornar a censura na Internet, mas é essa mesma primitiva (um proxy HTTP hackável e em processo) que torna a configuração de um proxy de desbloqueio para web scraping interessante para os autores de scrapers.

O que é invulgar é a interface. Em vez de utilizar o protocolo clássico de proxy HTTP ou SOCKS5 numa porta dedicada, o Node-unblocker expõe um prefixo de URL ao estilo REST. O utilizador faz o pedido https://your-proxy/proxy/https://target.com/pagee a biblioteca busca o alvo em seu nome e o transmite de volta. Essa mudança é o que abre caminho para a história do middleware que exploraremos mais adiante.

Quando o Node-Unblocker se adequa à sua pilha de scraping (e quando não se adequa)

Antes de escrever código, decida se um proxy Node-Unblocker para web scraping é a ferramenta certa.

Ideal para:

  • Está a fazer scraping principalmente de HTML estático ou de endpoints JSON simples.
  • Quer centralizar a modelagem de pedidos (cabeçalhos, autenticação, limpeza de cookies) para vários scrapers por trás de um único URL.
  • Precisa de contornar restrições geográficas para algumas regiões e pode executar um servidor em cada uma delas.
  • Deseja uma camada de middleware nativa do Node para que o seu código de scraping permaneça em JavaScript.

Ignore isto quando:

  • O alvo depende de pop-ups OAuth, postMessage()ou de um encaminhamento pesado do lado do cliente.
  • Precisa de IPs residenciais rotativos em escala ou de cobertura a nível nacional em dezenas de regiões.
  • Enfrenta CAPTCHAs, Cloudflare ou outras pilhas anti-bot.
  • A sua equipa não tem interesse em gerir e atualizar servidores Node.

Se duas ou mais das condições de «ignorar» se aplicarem, avance para a secção sobre alternativas geridas.

Pré-requisitos e inicialização do projeto

Precisa de uma versão LTS recente do Node.js e do npm na sua máquina. No momento da redação deste artigo, fixe a linha LTS atual; exemplos mais antigos têm como alvo o Node 16, mas confirme nos downloads oficiais do Node.js antes de fixar qualquer coisa package.json. Se alternar entre versões, instale o nvm e execute nvm use --lts.

Inicie um novo projeto:

mkdir node-unblocker-proxy && cd node-unblocker-proxy
npm init -y
npm install unblocker express

Construa o servidor proxy com o Express e o Unblocker

Com as dependências instaladas, crie index.js. O servidor minimalista de web scraping e desbloqueio do Node é pequeno o suficiente para caber num ecrã:

// index.js
const express = require("express");
const Unblocker = require("unblocker");

const app = express();
const unblocker = new Unblocker({ prefix: "/proxy/" });

app.use(unblocker);

app
  .listen(process.env.PORT || 8080, () => {
    console.log("Proxy listening on", process.env.PORT || 8080);
  })
  .on("upgrade", unblocker.onUpgrade);

Vale a pena destacar algumas coisas. new Unblocker({...}) retorna um middleware compatível com o Express, razão pela qual uma única app.use(unblocker) chamada é suficiente para montar todo o proxy. A porta padrão é 8080, substituível através da PORT variável de ambiente, para que o mesmo ficheiro funcione no Docker, Heroku e outros hosts em contentores.

A .on("upgrade", unblocker.onUpgrade) linha é a parte fácil de ignorar. Sem ela, as ligações WebSocket encaminhadas através do prefixo de URL nunca concluirão a mudança de protocolo, e qualquer site de destino que utilize atualizações em tempo real deixará de funcionar. Configure-a mesmo que ache que não precisa dela hoje, uma vez que a maioria dos sites utiliza WebSockets discretamente para telemetria.

Configurar a instância do Unblocker: prefixo, WebSockets e depuração

A maior parte do comportamento do node-unblocker é controlada através do objeto de opções passado ao seu construtor. Três parâmetros são importantes no início:

  • prefix define o caminho da URL sob o qual o proxy é montado. Com prefix: "/proxy/", cada pedido para /proxy/<encoded-url> é obtida em nome do chamador.
  • onUpgrade é o manipulador que se vincula ao evento upgrade para que o tráfego WebSocket seja encaminhado corretamente.
  • DEBUG=unblocker:* é uma variável de ambiente, não um campo de configuração, mas é a forma mais rápida de ver o que a biblioteca está realmente a fazer numa solicitação com comportamento anómalo.

Existem mais opções no README do projeto no GitHub, mas estas três cobrem quase todos os casos de utilização do Web Scraping Node Unblocker antes de começar a adicionar middlewares.

Execute e teste o proxy localmente

Inicie o servidor:

node index.js

Em seguida, aceda a partir de um shell separado ou do seu navegador:

curl -i http://localhost:8080/proxy/https://example.com/

Deve ver um HTTP 200 e o corpo HTML reescrito. No navegador, abra o DevTools e observe o separador Rede: os pedidos de sub-recursos também devem passar por /proxy/. Se algo parecer errado, reinicie o servidor com registo detalhado:

DEBUG=unblocker:* node index.js

Sinais comuns: ECONNRESET no handshake TLS geralmente significa que o servidor upstream bloqueou o seu IP, enquanto uma página em branco com um código de estado 200 é quase sempre JavaScript que o node-unblocker não conseguiu reescrever. Ambos são modos de falha normais para uma configuração do node-unblocker de web scraping.

Modifique o tráfego com middlewares de solicitação e resposta

Os middlewares são onde um proxy do node-unblocker para web scraping começa a parecer uma camada de abstração em vez de apenas um redirecionamento. Entregas ao construtor um requestMiddleware array e um responseMiddleware array, e cada função pode alterar o data antes de este ser encaminhado.

Aqui está um par que injeta um cabeçalho de autenticação interno e remove cabeçalhos de terceiros Set-Cookie da resposta:

function injectAuth(data) {
  data.headers["x-internal-auth"] = process.env.SCRAPER_TOKEN;
  data.headers["user-agent"] = "MyCompanyScraper/1.0 (+https://mycompany.example/bot)";
}

function stripCookies(data) {
  delete data.headers["set-cookie"];
}

const unblocker = new Unblocker({
  prefix: "/proxy/",
  requestMiddleware: [injectAuth],
  responseMiddleware: [stripCookies],
});

Dois padrões ganham o seu lugar aqui. Tudo o que, de outra forma, teria de repetir em cada scraper (alterar user agents, anexar tokens internos, normalizar Accept-Language) deve estar em requestMiddleware. Tudo o que quiseres limpar antes da análise (cookies de terceiros, cabeçalhos de rastreamento, corpos de grande dimensão) fica em responseMiddleware. Centralizar isso atrás de um único URL significa que todos os scrapers a jusante, em qualquer linguagem, recebem o mesmo tratamento sem copiar e colar, e as auditorias tornam-se uma pesquisa grep num único ficheiro quando o departamento jurídico perguntar como identifica o seu bot. Para auxiliares de recuperação mais avançados com reconhecimento de proxy, os nossos guias sobre como usar um proxy com node-fetch e sobre a configuração de proxy do Axios combinam bem com este padrão.

Escalabilidade horizontal: Crie um conjunto de proxies rotativos com várias instâncias

Uma instância do node-unblocker corresponde a um IP. Para distribuir a carga e contornar os limites de taxa por IP, implemente várias instâncias (idealmente em regiões diferentes) e escolha uma aleatoriamente para cada chamada. Um helper mínimo fica assim:

const PROXIES = [
  "https://proxy-us-1.example.com/proxy/",
  "https://proxy-us-2.example.com/proxy/",
  "https://proxy-eu-1.example.com/proxy/",
];

function pickProxy() {
  return PROXIES[Math.floor(Math.random() * PROXIES.length)];
}

async function scrape(targetUrl) {
  const proxy = pickProxy();
  const res = await fetch(proxy + encodeURI(targetUrl));
  return res.text();
}

Isto é suficiente para alguns milhares de pedidos por dia. Adicione uma camada de «retry-with-different-proxy» em respostas 4xx e 5xx, além de um disjuntor que retira um host PROXIES após N falhas consecutivas. Para um rendimento significativo, está a reinventar a gestão de proxies, e é aí que as ferramentas dedicadas de gestão de proxies e os proxies residenciais rotativos começam a compensar o investimento.

Implantação em produção: comparação entre Docker e Heroku

Existem duas vias de implementação fiáveis para um proxy desbloqueador de nós de web scraping.

O Docker funciona em qualquer lugar onde um contentor funcione e é a aposta mais segura a longo prazo. Um Dockerfile mínimo:

FROM node:lts-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --omit=dev
COPY . .
EXPOSE 8080
CMD ["node", "index.js"]

Compile com docker build -t my-unblocker . e envie a imagem para o Fly.io, Render, AWS ECS, GCP Cloud Run ou qualquer outro host de contentores. Fixe explicitamente a tag Node em produção.

O Heroku é mais rápido para protótipos se já tiver uma conta. Adicione um engines bloco e um start script para package.json (use a versão LTS principal atual; não copie cegamente "16.x" ), depois:

heroku login
heroku apps:create my-unblocker
git init && heroku git:remote -a my-unblocker
git add . && git commit -am "Initial commit"
git push heroku main

Após a conclusão da compilação, o seu proxy estará ativo em https://my-unblocker.herokuapp.com/proxy/<url>. O plano gratuito do Heroku já não existe, por isso tenha em conta o custo do dyno; se os preços ou as políticas mudarem, a sua imagem Docker muda para outro host sem alterações no código.

Respeite as políticas de uso aceitável do host e o robots.txt

Executar um proxy público na infraestrutura de terceiros é um campo minado de políticas. A Política de Uso Aceitável do Heroku, por exemplo, historicamente restringiu proxies públicos e scraping agressivo; verifique a AUP atual antes de fazer a implantação, já que o texto muda. De qualquer forma, defina um user-agent único e identificável, cumpra robots.txt conforme a RFC 9309, limite a taxa do seu scraper e ignore alvos que proíbam explicitamente a automação nos seus termos de serviço.

Limitações e modos de falha comuns

Advertências honestas poupam tempo de depuração. Um proxy desbloqueador de nós de web scraping provavelmente terá dificuldades nestes casos:

  • OAuth e postMessage() fluxos. Janelas pop-up que trocam tokens via window.postMessage raramente sobrevivem à reescrita de URL. Sintoma: janela pop-up de login em branco que nunca fecha.
  • SPAs com uso intensivo de JS. Relatórios públicos sinalizam sites como YouTube, Twitter/X, Discord e Instagram como causando falhas no node-unblocker; verifique nas issues do GitHub do projeto, já que a lista muda. Sintoma: página em branco com status 200.
  • Interfaces de utilizador baseadas em WebSocket quando onUpgrade está em falta. Sintoma: falha na atualização no DevTools.
  • Sem rotação de IP integrada, resolução de CAPTCHA ou contorno do Cloudflare. Cada um requer um sistema externo.
  • Custo operacional. Aplicar patches no Node, rodar instâncias e cumprir as políticas dos fornecedores de nuvem é um custo real contínuo.

Quando mudar de uma solução auto-hospedada para uma API de scraping gerida

Assim que qualquer uma das seguintes situações se verificar, a balança pende para uma API de scraping gerida:

  • Os alvos estão protegidos por Cloudflare, DataDome ou PerimeterX.
  • Precisa de IPs residenciais reais em vários países, e não de três instâncias de centro de dados.
  • O seu scraper tem de renderizar JavaScript, percorrer, clicar ou resolver CAPTCHAs.
  • O volume está a ultrapassar alguns milhares de pedidos por dia e as páginas de alerta estão a começar a aparecer.

Nessa altura, trocar o URL do proxy no seu fetch helper por um endpoint de scraper gerido mantém o resto do código intacto: a mesma análise do lado do Node, o mesmo pipeline a jusante, apenas um URL que trata do desbloqueio, rotação e renderização por si.

Pontos-chave

  • O Node-unblocker é um middleware Express personalizável, não um proxy de rede.
  • Wire onUpgrade e um prefix, e depois sobreponha middlewares para lógica partilhada.
  • Alterne instâncias para diversidade de IP; Docker para portabilidade, Heroku para protótipos.
  • Respeite robots.txt, as políticas de uso aceitável (AUPs) do host e um user-agent único.
  • Mude para uma API gerida assim que o anti-bot ou a renderização JS entrarem em cena.

Perguntas frequentes

O node-unblocker é gratuito para web scraping comercial?

Sim. O Node-unblocker é de código aberto e tem uma licença permissiva, pelo que a utilização comercial da biblioteca em si é permitida. Os custos residem noutro lado: a sua fatura de alojamento, a situação legal dos sites que extrai e as políticas de utilização aceitável do fornecedor de nuvem que gere as suas instâncias. Leia sempre o ficheiro de licença no repositório GitHub e os termos de serviço do site de destino antes de implementar em grande escala.

O node-unblocker alterna endereços IP automaticamente?

Não. Um único processo do Node-unblocker apresenta sempre o IP público do host em que é executado. Se pretender rotação, terá de implementar várias instâncias (idealmente em diferentes regiões ou fornecedores) e escolher entre elas no lado do cliente, tal como faz o auxiliar de pool rotativo mencionado anteriormente neste guia. A rotação integrada é uma das razões mais evidentes pelas quais as pessoas optam por um serviço de proxy gerido.

O node-unblocker consegue contornar o Cloudflare, CAPTCHAs ou outros sistemas anti-bot?

Não. O Node-unblocker é um proxy HTTP transparente com reescrita de cabeçalhos, não uma pilha de evasão anti-bot. Não resolve CAPTCHAs, não gera impressões digitais TLS do navegador e não lida com o desafio JavaScript do Cloudflare. Se o seu alvo utiliza qualquer uma dessas defesas, necessita de um navegador headless, um conjunto de IPs residenciais e lógica de resolução de desafios, o que está fora do âmbito da biblioteca.

Em que é que o Node-unblocker difere de um proxy HTTP ou SOCKS5 tradicional?

Um proxy HTTP ou SOCKS5 tradicional escuta numa porta e aceita ligações que seguem o protocolo de proxy. Em vez disso, o node-unblocker expõe um ponto final HTTP onde o URL de destino é codificado no caminho, como /proxy/https://example.com/. Isso significa que qualquer cliente HTTP pode utilizá-lo sem configuração específica para proxy, e pode anexar middleware JavaScript a cada pedido e resposta.

Por que é que o node-unblocker falha em sites que usam OAuth ou postMessage?

Ambos dependem de funcionalidades do navegador que a camada de reescrita de URL não consegue reproduzir na totalidade. As janelas pop-up do OAuth trocam tokens com uma janela pai através de window.postMessage(), e a origem reescrita já não corresponde ao que o site de destino espera, pelo que o handshake falha silenciosamente. O mesmo se aplica a qualquer widget incorporado que utilize mensagens entre origens. Os logins padrão baseados em formulários e a maioria dos pontos finais AJAX simples continuam a funcionar normalmente.

Conclusão

Um proxy de desbloqueio de nós para web scraping é uma das ferramentas mais subestimadas na caixa de ferramentas de scraping do Node.js. Permite-lhe criar um proxy HTTP programável em uma dúzia de linhas de código, anexar middleware que transforma a lógica dispersa do scraper numa camada de abstração limpa e enviar tudo como uma imagem Docker para qualquer host que se encaixe no seu orçamento este ano. Para sites estáticos, bypass geográfico simples e modelagem de pedidos partilhada, isso é realmente tudo o que precisa.

Tem também um limite claro. No momento em que os teus alvos estiverem protegidos pelo Cloudflare, exigirem IPs residenciais ou transmitirem os seus dados importantes através de postMessage() e SPAs renderizadas em JavaScript, estará fora do território do node-unblocker. A atitude honesta não é sobrepor hack em hack, mas manter o seu código de análise e trocar a camada de rede subjacente.

Se os seus scrapers estão a começar a bater nessas barreiras, a nossa equipa criou a WebScrapingAPI exatamente para essa transição: um endpoint que lida com rotação de proxy, renderização de JavaScript, contorno anti-bot e resolução de CAPTCHA, enquanto os seus auxiliares de fetch existentes continuam a funcionar. Considere o node-unblocker como a resposta certa para a parte simples do problema e recorra a uma API gerida quando a parte difícil surgir. Seja como for, agora tem um plano de trabalho, um caminho de implementação e uma lista de sinais de alerta a ter em conta, que é tudo o que uma estratégia de proxy auto-hospedada precisa para começar.

Sobre o autor
Sorin-Gabriel Marica, Desenvolvedor Full-Stack @ WebScrapingAPI
Sorin-Gabriel MaricaDesenvolvedor Full-Stack

Sorin Marica é engenheiro Full Stack e DevOps na WebScrapingAPI, onde desenvolve funcionalidades do produto e mantém a infraestrutura que garante o bom funcionamento da plataforma.

Comece a construir

Pronto para expandir a sua recolha de dados?

Junte-se a mais de 2.000 empresas que utilizam a WebScrapingAPI para extrair dados da Web à escala empresarial, sem quaisquer custos de infraestrutura.