Voltar ao blogue
Guias
Mihnea-Octavian ManolacheLast updated on Mar 31, 20267 min read

Como utilizar um proxy com o Node Fetch e criar um scraper web

Como utilizar um proxy com o Node Fetch e criar um scraper web

Em primeiro lugar, ao criar um scraper da Web, os proxies são, sem dúvida, muito importantes. Em segundo lugar, o node-fetch é um dos clientes HTTP em JavaScript mais populares. Por isso, faz todo o sentido combinar os dois e criar um scraper da Web.

É por isso que hoje vamos discutir como usar um proxy com o node-fetch. E, como bónus, vamos criar um web scraper com base nesta infraestrutura.

Assim, no final deste artigo:

  • Terá uma compreensão sólida de como os proxies funcionam na extração de dados da web
  • Vais aprender a integrar um proxy com o node-fetch
  • Terá um projeto adicionado ao seu portfólio pessoal

O que é um proxy e por que razão usá-lo para web scraping?

Nas redes informáticas, os proxies atuam como «middlewares» entre um cliente e um servidor. A arquitetura de um servidor proxy é bastante complexa, mas, a um nível geral, eis o que acontece quando se utiliza um proxy:

  • Ligas-te ao servidor proxy e especificas o destino (servidor) que pretendes alcançar (extrair)
  • O servidor proxy liga-se ao seu destino e recupera os resultados (os ficheiros HTML de um site, por exemplo)
  • O servidor proxy, então, devolve-lhe a resposta que obteve do servidor de destino

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

Porquê usar o node-fetch para web scraping?

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

Em primeiro lugar, é 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 como dependência de terceiros. Até hoje, na versão 19.3.0 do Node.js, o fetch continua marcado como experimental. Por isso, o node-fetch continua a ser a solução mais estável.

Especificamente para scraping, o node-fetch é uma excelente 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 utilizar o node-fetch com proxies?

Resumindo, não existe um método integrado para utilizar um proxy com o node-fetch. Portanto, se quiser criar um web scraper, mas a sua infraestrutura depende do node-fetch, corre 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. Uma delas é-nos oferecida por Nathan Rajlich, que criou um módulo que implementa o http.Agent e se chama https-proxy-agent. A instalação está disponível via npm. Além disso, implementá-lo com o 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:

"origin": "1.255.134.136"

Outra opção é utilizar o node-fetch-with-proxy. Este pacote utiliza o proxy-agent como uma dependência própria, além do node-fetch. Para que isto funcione, basta definir a variável de ambiente «HTTP_PROXY». Ela recebe o endereço IP e o número da porta do seu servidor proxy como valor. Depois, pode utilizar a sintaxe normal do node-fetch para efetuar as suas chamadas, que serão automaticamente encaminhadas para o servidor proxy. Aqui está um exemplo:

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

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

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

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

Como criar um web scraper utilizando um proxy com o node-fetch?

Como nota positiva, já criámos um web scraper. Os exemplos de código acima fazem exatamente o que qualquer web scraper faz, ou seja, recolhem dados de um site. No entanto, num cenário 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. Vamos, portanto, aprofundar um pouco mais e transformar o nosso primeiro exemplo num verdadeiro scraper. Vamos definir algumas expectativas:

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

Partindo do princípio de que já instalou o node-fetch e o https-proxy-agent, precisamos de mais uma coisa: um analisador de HTML. Eu opto sempre pelo cheerio para web scraping. 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 from 'node-fetch';

import HttpsProxyAgent from "https-proxy-agent";

import * as cheerio from 'cheerio';

#2: Lógica do scraper

Precisamos que o nosso scraper seja capaz de realizar três açõ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 anteriormente. 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 do terminal para distinguir entre as três opções que implementámos no nosso scraper. Existem opções que pode usar para analisar argumentos do terminal no Node, mas gosto de manter as coisas simples. É por isso que vamos usar process.argv, que gera uma matriz de argumentos. Note que os dois primeiros itens desta matriz são «node» e o nome do seu script. Por exemplo, se executar `node scraper.js raw_html`, a matriz de argumentos ficará assim:

[

  '/usr/local/bin/node',

  'path_to_directory/scraper.js',

  'raw_html'

]

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

  • o primeiro argumento especificará a função que queremos executar;
  • o segundo apontará para o nosso alvo (o site que queremos rastrear);
  • o terceiro apontará para o servidor proxy;
  • e o quarto apontará para o seletor CSS.

Assim, o comando para executar o nosso scraper deve ficar assim:

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

Isto traduz-se simplesmente em extrair o HTML bruto da página inicial da WebScrapingAPI e utilizar http://1.255.134.136 como middleware de proxy. Agora, a parte final consiste em codificar a lógica para estes argumentos, de modo a que o nosso código compreenda o comando de execução:

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! Criou com sucesso um scraper web totalmente funcional utilizando um proxy com o node-fetch. Desafio-o agora a adicionar mais funcionalidades a este scraper, criar a sua própria versão e utilizá-la como um recurso no seu portfólio pessoal.

Usar um proxy com o node-fetch pode não ser suficiente para o web scraping

Como gosto de dizer, há mais no scraping discreto do que apenas ocultar o seu endereço IP. Na realidade, usar um servidor proxy para o seu scraper web é apenas uma camada de proteção contra software antibot. Outra camada consiste em 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 chegam ao ponto de modificar os valores predefinidos do navegador headless para evitar a identificação.

Além disso, como os sites modernos apresentam o conteúdo dinamicamente utilizando JavaScript, um cliente HTTP simples, como o node-fetch, pode não ser suficiente. Poderá querer explorar a utilização de um navegador web real. O selenium do Python ou o puppeteer do Node são apenas duas opções que poderá considerar nesse sentido.

Conclusões

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

Criar um scraper furtivo é, no entanto, mais difícil e terá de conceber técnicas de evasão mais complexas. Mas gosto de ver uma oportunidade em tudo. Porque não pegar no que aprendeu hoje e ir acrescentando? Espero que, no final, consiga criar o melhor scraper web escrito com o node-fetch e proxies. Como sempre, o meu conselho para si é que continue a aprender!

Sobre o autor
Mihnea-Octavian Manolache, Desenvolvedor Full Stack @ 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.