Voltar ao blogue
Guias
Mihnea-Octavian Manolache27 de janeiro de 202310 min de leitura

Como utilizar cabeçalhos HTTP com o Axios para evitar a deteção

Como utilizar cabeçalhos HTTP com o Axios para evitar a deteção

Como funciona a comunicação HTTP

Antes de nos debruçarmos sobre a definição de um cabeçalho HTTP, penso que é importante ter, pelo menos, uma visão geral de como funciona o protocolo HTTP. Como certamente já sabe, o Protocolo de Transferência de Hipertexto (HTTP) é a base sobre a qual a Web assenta atualmente. Em termos gerais, permite a transferência de informação entre um servidor e os seus clientes. O fluxo efetivo desta troca de informação é mais ou menos assim:

  • O cliente abre uma nova ligação TCP
  • Envia uma mensagem ao servidor, o que se denomina pedido HTTP
  • O servidor recebe e interpreta o pedido
  • Em seguida, envia uma mensagem de volta ao cliente, a que se denomina resposta HTTP
  • O cliente lê a mensagem e continua ou encerra a ligação
Ilustração de um pedido HTTP que mostra o método, o URL, a versão do protocolo e os cabeçalhos do pedido

O aspeto importante em que nos vamos concentrar hoje é a mensagem, em particular a mensagem enviada pelo cliente. Para que a comunicação entre o servidor e o cliente seja eficiente, as mensagens têm de ser formatadas conforme descrito pelo protocolo HTTP. No que diz respeito ao pedido HTTP, os elementos que compõem a mensagem são:

O método descreve o que pretendemos fazer com o nosso pedido (se queremos receber, enviar, atualizar informações, etc.)

  • O caminho, o endereço URL ao qual estamos a tentar aceder
  • A versão do protocolo HTTP que estamos a utilizar
  • Os cabeçalhos HTTP, que são utilizados para enviar informações adicionais e metadados juntamente com o nosso pedido
  • O corpo, caso estejamos a utilizar um método que envia informações para o servidor (como uma solicitação POST)

O que são os cabeçalhos HTTP no Axios e como funcionam?

Em termos simples, os cabeçalhos HTTP são campos que transmitem informações adicionais e metadados à mensagem. Mais uma vez, por mensagem, entendemos a solicitação quando esta é enviada pelo cliente e a resposta quando esta é enviada pelo servidor. Assim, tanto o servidor como o cliente podem passar e receber cabeçalhos. Por exemplo, digamos que queira abrir uma ligação persistente ao servidor. Por predefinição, as ligações HTTP são encerradas após cada solicitação. Para evitar isso, basta passar o cabeçalho `Keep-Alive`.

No que diz respeito aos cabeçalhos HTTP com o Axios, não há realmente nada de especial nisso. Como já discutimos, o Axios é um cliente HTTP e já estabelecemos que os clientes HTTP podem enviar e receber cabeçalhos.

Por que o Axios é um excelente cliente HTTP para JavaScript

Agora que já temos uma visão geral do funcionamento do HTTP, vamos falar dos «clientes». O JavaScript oferece algumas opções para «interagir programaticamente» com um servidor através do HTTP. Entre as opções mais populares, destacam-se o `axios`, o `node-fetch` e o `got`.

Na comunidade JavaScript, há opiniões divergentes sobre qual utilizar. É claro que cada pacote tem os seus prós e contras; no entanto, eu próprio optei pelo Axios após realizar um teste de velocidade simples entre os três.

Aqui está o script que utilizei para testar a velocidade:

// index.js

import { get_timing, array_sum } from './helpers.js'

import got from 'got'

import axios from 'axios'

const CALLS = 5

const send = async () => {

   const res = {}

  

   let start = process.hrtime()

   await got('https://httpbin.org/')

   const g = get_timing(start)

   res.got = g

   start = process.hrtime()

   await axios.get('https://httpbin.org/')

   const a = get_timing(start)

   res.axios = a

   start = process.hrtime()

   await fetch('https://httpbin.org/')

   const f = get_timing(start)

   res.fetch = f

   return res

}

let test_results = {

   got: [],

   axios: [],

   fetch: []

}

let avg = {}

console.log(`[i] Process started with ${CALLS} iterations.`)

for (let i = 0; i<=CALLS; i++) {

   let r = await send()

   Object.entries(test_results).map(([key, value]) => test_results[key].push(r[key]))

}

Object.entries(test_results).forEach(([key, value]) => {

       console.log(`\n[+] ${key}`)

       console.log(`    [i] Average: ${array_sum(value)/value.length}`)

       console.log(`    [i] Values: ${value}`)

       avg[key] = array_sum(value)/value.length

   }

)

console.log(`\n🚀🚀🚀 WINNER: ${Object.keys(avg).reduce((key, v) => avg[v] < avg[key] ? v : key)}  [${CALLS} calls sent] 🚀🚀🚀`)

E aqui estão as funções «auxiliares»:

// helpers.js

export const get_timing = (start) => {

   const NS_PER_SEC = 1e9

   const NS_TO_MS = 1e6

   const diff = process.hrtime(start)

   return (diff[0] * NS_PER_SEC + diff[1]) / NS_TO_MS

}

export const array_sum = (array) => {

   return array.reduce((accumulator, value) => {

     return accumulator + value

   }, 0)

}

Testei com 5, 10, 20 e 30 pedidos enviados por cada pacote, com 10 iterações em cada caso, e eis um resumo dos resultados:

Gráfico de barras que compara os tempos médios de resposta para diferentes clientes HTTP, como o fetch, o Axios e o Got

Por «iteração», refiro-me ao número de execuções do script, utilizando esta fórmula do Bash, que gera um ficheiro .txt com os resultados de cada iteração:

~ » for i in {1..10}

do

node got.js > "${i}.txt"

echo "${i} concluído"

done

Como poderá verificar na tabela de resultados detalhados, os tempos variam de lote para lote e, por vezes, o Axios não é o mais rápido. No geral, porém, o Axios registou uma média de 387 milissegundos, sendo meio segundo mais rápido do que os seus concorrentes. O Got e o Fetch tiveram um tempo de resposta muito semelhante, com uma média de aproximadamente 435 milissegundos. Dito isto, se a velocidade é importante para o seu projeto, o Axios é talvez o melhor cliente HTTP para si.

Como enviar cabeçalhos HTTP com o Axios

Pessoalmente, acho que aprender na prática traz resultados quase imediatos. Assim, agora que temos tanto o conhecimento como as ferramentas para enviar cabeçalhos HTTP, vamos começar a trabalhar num pequeno projeto. Nesta secção, vamos criar um novo projeto Node, instalar o Axios e utilizá-lo para enviar cabeçalhos HTTP a um servidor.

Configurar o projeto

Antes de prosseguir, certifique-se de que a sua máquina está equipada com:

Dica: Pode verificar se tem o Node.js instalado digitando o seguinte comando no seu terminal:

~ » node -v  

v19.3.0

Agora vamos criar uma nova pasta e abri-la no nosso IDE. Se estiver a utilizar um sistema semelhante ao UNIX (Mac ou Linux), pode criar um novo diretório programaticamente, a partir do terminal, digitando o seguinte comando:

~ » mkdir axios_project && cd axios_project 

~ » npm init -y

~ » npm i axios

~ » touch index.js

~ » code .

Estes comandos irão:

  • Crie um novo diretório (chamado «axios_project») e aceda a ele
  • Inicializar um novo projeto Node.js dentro do diretório
  • Instale o `axios` no seu projeto
  • Crie um novo ficheiro «index.js»
  • Abra o seu IDE no projeto atual

Código para aprender

Na verdade, existem várias formas de enviar cabeçalhos HTTP com o Axios. Por exemplo, pode utilizar um objeto de configuração, tal como descrito aqui, ou pode recorrer aos métodos de instância, que irão combinar automaticamente a configuração que passar com a configuração da instância. Também pode utilizar o objeto `axios.defaults.headers.common` para definir cabeçalhos predefinidos para todas as solicitações do Axios.

Além disso, note que o Axios é um cliente HTTP baseado em promessas. Isto significa que teremos de aguardar a resposta dentro de uma função assíncrona ou resolver a resposta.

Tendo estes dois aspetos em mente, vamos começar a programar. Vamos trabalhar no ficheiro «index.js». Por uma questão de conveniência, vamos recapitular o que precisamos de fazer antes:

  • Importar o `axios` para o nosso ficheiro
  • Defina um objeto de configuração que irá conter os nossos cabeçalhos
  • Passe a configuração para o `axios` para efetuar uma solicitação
  • Imprimir a resposta no nosso terminal

N.º 1: Enviar um pedido GET utilizando o objeto de configuração

import axios from "axios"

const config = {

   method: 'GET',

   url: 'https://httpbin.org/headers',

   headers: {

       'HTTP-Axios-Headers': 'This is my custom header.'

   }

}

axios(config)

   .then((response) => {

       console.log(response)

   })

   .catch((err) => {

       console.log(err)

   })

Enviar cabeçalhos HTTP com o Axios é extremamente simples. Para executar este script, basta executar o seguinte comando no terminal:

~ » node index.js  

{

  status: 200,

  statusText: 'OK',

  headers: ...,

  config: ...,

  request: ...,

  data: {

    headers: {

      'Accept': 'application/json, text/plain, */*',

      'Accept-Encoding': 'gzip, compress, deflate, br',

      'Host': 'httpbin.org',

      'Http-Axios-Headers': 'This is my custom header.',

      'User-Agent': 'axios/1.2.2',

      'X-Amzn-Trace-Id': 'Root=1-63b54d94-7656f02113483dfa036c476c'

    }

  }

}

A resposta completa é bastante extensa e segue este esquema. No entanto, o que mais nos interessa é o `data`, que contém a resposta efetiva que recebemos do servidor. Agora, observe a resposta acima. Lembre-se de que enviámos um cabeçalho personalizado `Http-Axios-Headers` ao servidor e, como pode ver, o servidor recebeu-o.

N.º 2: Enviar um pedido POST utilizando o alias do método

import axios from "axios"

const data = {

   'foo':'bar'

}

const config = {

   headers: {

       'HTTP-Axios-Headers': 'This is my custom header.'

   }

}

axios.post('http://httpbin.org/post', data, config)

   .then(response => console.log(response.data))

   .catch(err => console.log(err))

Repare que, para enviar um pedido POST, adicionei um novo objeto `data` ao nosso script e também alterei o URL. Agora, se executar o script, verá que estes são os dados recebidos do servidor:

{

  args: {},

  data: '{"foo":"bar"}',

  files: {},

  form: {},

  headers: {

    Accept: 'application/json, text/plain, */*',

    'Accept-Encoding': 'gzip, compress, deflate, br',

    'Content-Length': '13',

    'Content-Type': 'application/json',

    Host: 'httpbin.org',

    'Http-Axios-Headers': 'This is my custom header.',

    'User-Agent': 'axios/1.2.2',

    'X-Amzn-Trace-Id': 'Root=1-63b5508a-3a86493f087662d3169e80ee'

  },

  json: { foo: 'bar' },

  origin: '49.12.221.20',

  url: 'http://httpbin.org/post'

}

Como utilizar cabeçalhos HTTP no Axios para a extração de dados da Web

Se tenciona utilizar o Axios para a extração de dados da Web, tenha em atenção que a maioria dos sites possui regras de proteção que bloqueiam os pedidos provenientes de software automatizado (incluindo programas de extração de dados).

A utilização de cabeçalhos HTTP, em particular o cabeçalho `User-Agent`, pode ser uma técnica útil para evitar a deteção durante a extração de dados da Web. O cabeçalho User-Agent identifica o navegador do cliente e o sistema operativo junto do servidor, e os servidores Web podem apresentar conteúdos diferentes ou bloquear pedidos com base nessas informações. Ao definir o cabeçalho User-Agent, é possível simular um navegador Web comum, aumentando assim as hipóteses de contornar alguns mecanismos de deteção.

Eis um exemplo de como utilizar o cabeçalho User-Agent com o Axios para evitar ser detetado ao fazer web scraping:

import axios from "axios"

axios.defaults.headers.common['User-Agent'] = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3'

axios({

   method: 'GET',

   url: 'https://httpbin.org/get',

}).then(response => {

   console.log(response.data)

});

Repare que, desta vez, utilizei a opção «config defaults» do Axios, que aplica o cabeçalho a todas as solicitações futuras. Neste exemplo, o cabeçalho User-Agent está definido para imitar o navegador Chrome num sistema operativo Windows 10. Pode experimentar utilizar diferentes valores de User-Agent ou uma variedade de cabeçalhos diferentes para ver o que funciona melhor para o seu caso de utilização específico.

Vale a pena referir que, embora alterar o cabeçalho User-Agent possa ajudar a evitar a deteção em alguns casos, não se trata de um método infalível, e os servidores web podem continuar a identificar que está a utilizar um scraper. Por isso, é aconselhável utilizar uma combinação de técnicas para evitar a deteção e respeitar os termos de serviço do site.

Conclusões

A utilização de cabeçalhos HTTP com o Axios (ou com qualquer outro cliente HTTP, aliás) pode aumentar a eficiência da comunicação entre um servidor e um cliente. Além disso, pode até ajudar a evitar a deteção quando se está a criar um scraper web. Na verdade, na WebScrapingAPI, utilizamos vários agentes de utilizador como uma das técnicas básicas de evasão.

É claro que a deteção não se limita aos agentes de utilizador, mas é um bom ponto de partida. Aqui está um bom tutorial sobre como evitar que o seu endereço IP seja bloqueado ao fazer web scraping, que o ajudará a compreender melhor como funcionam as técnicas de evasão.

A propósito, sabia que a API de Web Scraping permite definir cabeçalhos personalizados nas suas solicitações? Se não, saiba mais aqui.

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.