Voltar ao blogue
Guias
Mihnea-Octavian Manolache24 de abril de 20238 min de leitura

Como usar um proxy com o Node Fetch e criar um Web Scraper

Como usar um proxy com o Node Fetch e criar um Web Scraper

O que é um proxy e porquê utilizá-lo para a recolha de dados da Web?

Nas redes informáticas, os proxies actuam como "middlewares" entre um cliente e um servidor. A arquitetura de um servidor proxy é bastante complexa, mas, em termos gerais, é isto que acontece quando se utiliza um proxy:

  • O utilizador "toca" no servidor proxy e especifica o destino (servidor) que está a tentar alcançar (scrape)
  • O servidor proxy liga-se ao seu destino e obtém os resultados (os ficheiros HTML de um sítio Web, por exemplo)
  • Em seguida, o servidor proxy devolve-lhe a resposta que obteve do servidor de destino
Diagrama que mostra um scraper a encaminhar pedidos através de um proxy para um site de destino

Nesta cadeia, o seu IP permanece oculto do servidor de destino, uma vez que nunca se liga realmente a ele. E essa é a principal razão pela qual os proxies são uma parte tão importante do web scraping. Eles "escondem" o endereço IP do web scraper, para que este não seja bloqueado pelos sistemas antibot.

Porquê utilizar o node-fetch para a recolha de dados da Web?

Se JavaScript é a sua linguagem de programação favorita, existem muitos clientes HTTP que pode utilizar para construir um web scraper. Entre os mais populares, estão axios, got e mais alguns listados aqui. Mas o node-fetch continua sendo um dos pacotes npm mais baixados, e há uma razão para isso.

Primeiro, é o primeiro pacote a implementar a API Fetch no Node JS. Depois, a partir da versão 17.5.0, a equipa do Node JS adicionou a API Fetch, para que não fosse necessária uma dependência de terceiros. Até hoje, na versão 19.3.0 do Node JS, o fetch ainda está marcado como experimental. Portanto, o node-fetch continua sendo a solução mais estável.

Especificamente para o scraping, o node-fetch é uma óptima ferramenta porque, como o nome indica, é utilizado para obter recursos de várias fontes. E essa é talvez a definição mais básica de scraping.

Como usar o node-fetch com proxies?

Resumindo, não há nenhum método embutido para usar um proxy com node-fetch. Por isso, se quiser construir um web scraper, mas a sua infraestrutura depende do node-fetch, pode correr o risco de expor o seu IP real. Isto significa que corre o risco de ser bloqueado por software antibot.

Felizmente, porém, existem soluções alternativas para isso. Uma delas nos foi oferecida por Nathan Rajlich, que construiu um módulo que implementa o http.Agent e é chamado de https-proxy-agent. A instalação está disponível via npm. Além disso, implementá-lo com node-fetch é bastante simples:

import fetch from 'node-fetch';

import HttpsProxyAgent from "https-proxy-agent";

const fetch_proxy = async () => {

   	const proxy = new HttpsProxyAgent('http://1.255.134.136:3128');

   	const response = await fetch('https://httpbin.org/ip', { agent: proxy});

   	const data = await response.text();

   	console.log(data);

}

fetch_proxy()

Para efeitos deste teste, utilizei um proxy gratuito do Proxy Scrape. Como esperado, a resposta indica que o pedido teve origem no IP do proxy, e não no meu IP local:

"origem": "1.255.134.136"

Outra opção é usar node-fetch-with-proxy. Este pacote usa o proxy-agent como uma dependência própria em cima do node-fetch. Para que isso funcione, tudo o que você precisa fazer é definir a variável de ambiente 'HTTP_PROXY'. Ela recebe o endereço IP do seu servidor proxy e o número da porta como um valor. Então você pode usar a sintaxe regular do node-fetch para fazer suas chamadas, que serão automaticamente encaminhadas para o servidor proxy. Aqui está um exemplo:

import fetch de "node-fetch-with-proxy";

fetch('http://httpbin.org/ip')

.then(res => res.json())

.then(json => console.log(json));

Como construir um web scraper usando um proxy com node-fetch?

Para terminar, já construímos um web scraper. Os exemplos de código acima fazem exatamente o que qualquer web scraper faz, ou seja, recolhem dados de um sítio Web. No entanto, num cenário da vida real, um web scraper é um pouco mais complexo. Por exemplo, os dados brutos precisam de ser processados, ou precisamos de verificar e analisar os cabeçalhos ou cookies recolhidos. Por isso, vamos aprofundar um pouco mais e transformar a nossa primeira amostra num verdadeiro raspador. Vamos definir algumas expectativas:

  • Devemos ser capazes de devolver o HTML em bruto
  • Devemos ser capazes de devolver toda a resposta como um objeto JSON
  • Devemos ser capazes de extrair elementos com base em selectores específicos

Assumindo que já instalou o node-fetch e o https-proxy-agent, vamos precisar de mais uma coisa: um analisador HTML. Eu sempre escolho o cheerio para raspagem da web. Por isso, certifique-se de que o instala no seu projeto. Dito isto, vamos começar:

#1: Importar dependências

A primeira coisa que queremos fazer é importar os pacotes que discutimos acima. Acho que esta parte não precisa de mais explicações:

import fetch de 'node-fetch';

import HttpsProxyAgent de "https-proxy-agent";

import * como cheerio de 'cheerio';

#2: Lógica do raspador

Precisamos que o nosso raspador seja capaz de executar três acções: devolver o HTML da linha, devolver a resposta completa e devolver um elemento com base no seu seletor CSS. Uma delas já foi parcialmente implementada antes. Mas vamos dividir tudo em três funções:

const raw_html = async (proxyServer, targetURL) => {

   const proxy = new HttpsProxyAgent(proxyServer);

   const response = await fetch(targetURL, { agent: proxy});

   const data = await response.text();

   return data;

}

const json_response = async (proxyServer, targetURL) => {

   const proxy = new HttpsProxyAgent(proxyServer);

   const response = await fetch(targetURL, { agent: proxy});

   const data = {

       url: response.url,

       status: response.status,

       Headers: response.headers,

       body: await response.text()

   }

   return data;

}

const select_css = async (proxyServer, targetURL, cssSelector) => {

   const proxy = new HttpsProxyAgent(proxyServer);

   const response = await fetch(targetURL, { agent: proxy});

   const html = await response.text();

   const $ = cheerio.load(html);

   return $(cssSelector).text();

}

#3: Analisador de argumentos

Podemos usar argumentos de terminal para distinguir entre as três opções que implementámos no nosso raspador. Existem opções que podem ser usadas para analisar argumentos de terminal no Node, mas eu gosto de manter as coisas simples. É por isso que vamos usar process.argv, que gera um array de argumentos. Note que os dois primeiros itens deste array são 'node' e o nome do seu script. Por exemplo, se estivermos executando `node scraper.js raw_html`, o array de argumentos será parecido com este:

[

  '/usr/local/bin/node',

  'caminho_para_o_diretório/scraper.js',

  'html_bruto'

]

Ignorando os dois primeiros elementos, utilizaremos a seguinte lógica:

  • o primeiro argumento especificará a função que queremos executar;
  • o segundo apontará para o nosso alvo (o sítio Web que queremos recolher);
  • o terceiro apontará para o servidor proxy;
  • e um quarto apontará para o seletor css.

Assim, o comando para executar o nosso raspador deve ter o seguinte aspeto:

~ " node scraper.js raw_html https://webscrapingapi.com http://1.255.134.136:3128 

Isso se traduz simplesmente em extrair o html bruto da página inicial do WebScrapingAPI e usar o http://1.255.134.136 como um middleware proxy. Agora a parte final é codificar a lógica para esses argumentos, de modo que nosso código entenda o comando run:

const ACTION = process.argv[2]

const TARGET = process.argv[3]

const PROXY = process.argv[4]

const SELECTOR = process.argv[5]
switch (ACTION) {

   case 'raw_html':

console.log(await raw_html(PROXY, TARGET))

break

   case 'json_response':

console.log(await json_response(PROXY, TARGET))

break

   case 'select_css':

SELECTOR ? console.log(await select_css(PROXY, TARGET, SELECTOR)) : console.log('Please specify a CSS selector!')

break

   default:

conssole.log('Please choose between `raw_html`, `json_response` and `select_css`')

}

E é basicamente isso. Parabéns! Você criou com sucesso um web scraper totalmente funcional usando um proxy com node-fetch. Desafio-o agora a adicionar mais funcionalidades a este scraper, a fazer a sua própria versão e a usá-la como um ativo no seu portfólio pessoal.

Utilizar um proxy com node-fetch pode não ser suficiente para a recolha de dados da Web

Como gosto de dizer, a recolha furtiva de dados é mais do que esconder o seu endereço IP. Na realidade, utilizar um servidor proxy para o seu raspador da Web é apenas uma camada de proteção contra o software antibot. Outra camada é alterar o seu agente de utilizador [definindo cabeçalhos personalizados para o seu pedido] (LINK https://trello.com/c/n8xZswSI/14-2-8-january-article-13-http-headers-with-axios).

Na Web Scraping API, por exemplo, temos uma equipa dedicada que trabalha em técnicas de evasão personalizadas. Algumas delas vão até ao ponto de modificar os valores predefinidos do navegador sem cabeça para evitar a recolha de impressões digitais.

Além disso, como os sítios modernos processam o conteúdo dinamicamente utilizando JavaScript, um simples cliente HTTP como o node-fetch pode não ser suficiente. Você pode querer explorar o uso de um navegador da Web real. O selenium do Python ou o puppeteer do Node são apenas duas opções que você pode analisar nesse sentido.

Conclusões

Usar um proxy com node-fetch é um ótimo ponto de partida para construir um web scraper. No entanto, tem de ter em conta o facto de os dois não serem "diretamente compatíveis" e terá de utilizar uma solução de terceiros para os ligar. Felizmente, existem muitas possibilidades e a comunidade JavaScript está sempre disposta a ajudar os recém-chegados.

Construir um raspador furtivo é, no entanto, mais difícil e terás de inventar técnicas de evasão mais complexas. Mas eu gosto de ver uma oportunidade em tudo. Por que não pegar no que aprendeste hoje e acrescentar-lhe algo? Com sorte, no final, terás o melhor web scraper escrito com node-fetch e proxies. Como sempre, meu conselho é continuar aprendendo!

Sobre o autor
Mihnea-Octavian Manolache, Desenvolvedor Full Stack na WebScrapingAPI
Mihnea-Octavian ManolacheDesenvolvedor Full Stack

Mihnea-Octavian Manolache é 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.