Requests vs. HTTPX vs. AIOHTTP: comparação detalhada

Explore Requests, HTTPX e AIOHTTP, os clientes HTTP mais populares do Python, e encontre a solução certa para suas necessidades de coleta de dados.
13 min read
Requests vs. HTTPX vs. AIOHTTP blog image

O Python hospeda uma grande variedade de clientes HTTP. Para aqueles que não estão familiarizados com o HTTP (Hypertext Transfer Protocol), ele é a estrutura subjacente de toda a web.

Hoje, vamos comparar três dos clientes HTTP mais populares do Python: Requests, HTTPX e AIOHTTP. Se você quiser saber mais sobre alguns dos outros disponíveis, dê uma olhada em aqui.

Breve visão geral

Requests é o cliente HTTP padrão para Python. Ele utiliza operações síncronas e de bloqueio para facilitar o uso. O HTTPX é um novo cliente assíncrono projetado para velocidade e facilidade de uso. O AIOHTTP existe há mais de uma década. É um dos primeiros e mais bem suportados clientes HTTP assíncronos que o Python tem a oferecer.

Recurso Requests HTTPX AIOHTTP
Estrutura Sincronização/Bloqueio Assíncrono/sem bloqueio Assíncrono/sem bloqueio
Sessões Sim Sim Sim
Simultaneidade Não Sim Sim
Suporte HTTP/2 Não Sim Sim
Desempenho Baixo Alto Alto
Tentativas Automático Automático Manual
Suporte de tempo limite Por solicitação Suporte total Suporte total
Suporte de proxy Sim Sim Sim
Facilidade de uso Fácil Difícil Difícil
Casos de uso Projetos/prototipagem simples Alto desempenho Alto desempenho

Python Requests

Python Requests é muito intuitivo e fácil de usar. Se não for necessário um desempenho de ponta, é a melhor opção para fazer solicitações HTTP em Python. É amplamente usado, fácil de entender e o cliente HTTP Python mais bem documentado do mundo.

Você pode instalá-lo com o comando abaixo.

Instalação

pip install requests

Requests suporta o protocolo HTTP padrão e até mesmo algum gerenciamento de sessão. Com as sessões, você pode criar uma conexão persistente com um servidor. Isso permite que você recupere seus dados com muito mais rapidez e eficiência do que ao fazer solicitações únicas. Se você quer apenas fazer solicitações básicas (GET, POST, PUT e DELETE) e o alto desempenho não é uma preocupação, a biblioteca Requests pode atender a todas as suas necessidades de HTTP.

Em toda a web, você pode encontrar guias sobre integração de proxy, agentes de usuário e todo tipo de outras coisas.

Você pode ver alguns exemplos básicos de uso abaixo.

import requests

# make a simple request
response = requests.get("https://jsonplaceholder.typicode.com/posts")
print(response.status_code)

# use a session for multiple requests to the same server
with requests.Session() as client:
    for get_request in range(1000):
        response = client.get("https://jsonplaceholder.typicode.com/posts")
        print(response.status_code)

Mas Requests deixa a desejar quando se trata de operações assíncronas. Com o suporte assíncrono, você pode fazer um lote de solicitações de uma só vez. Então, você pode await (aguardar) todos eles. Com solicitações síncronas, você só pode fazer uma solicitação por vez e precisa esperar que uma resposta retorne do servidor antes de fazer outra solicitação. Se seu programa precisar fazer muitas solicitações HTTP, o uso de Requests trará algumas limitações inerentes ao seu código.

HTTPX

O HTTPX é a mais nova e moderna dessas três bibliotecas. Ele nos dá suporte total para operações assíncronas prontas para uso. Dito isso, tem ainda uma sintaxe amigável e intuitiva. Use HTTPX se Requests simplesmente não estiver funcionando e você precisar melhorar o desempenho sem uma curva de aprendizado excessiva.

Com asyncio (entrada e saída assíncronas), você pode escrever um código que aproveite totalmente as respostas assíncronas com a palavra-chave await. Isso nos permite continuar nossas operações sem bloquear todo o resto do código enquanto esperamos que as coisas aconteçam. Com essas operações assíncronas, você pode fazer grandes lotes de solicitações. Em vez de fazer uma solicitação por vez, você pode fazer 5, 50 ou até 100!

Instalação

pip install httpx

Aqui estão alguns exemplos para começar a usar o HTTPX.

import httpx
import asyncio

# synchronous response
response = httpx.get("https://jsonplaceholder.typicode.com/posts")
print(response.status_code)

# basic async session usage
async def main():
    async with httpx.AsyncClient() as client:
        for get_request in range(1000):
            response = await client.get("https://jsonplaceholder.typicode.com/posts")
            print(response.status_code)
asyncio.run(main())

O HTTPX é uma excelente opção ao escrever um novo código, mas ele vem com seu próprio conjunto de limitações. Devido à sua sintaxe, pode ser difícil analisar e substituir sua base de código de Requests existente por HTTPX. Escrever código assíncrono exige um pouco de repetição, e a menos que você esteja fazendo milhares de solicitações, geralmente não vale a pena gastar tempo extra no desenvolvimento.

Em comparação com o AIOHTTP (como você aprenderá em breve), o HTTPX não é tão rápido. Se você está procurando construir um servidor web ou uma rede complexa, o HTTPX não é uma boa escolha devido ao seu ecossistema imaturo. O HTTPX é melhor para novos aplicativos do lado do cliente com recursos modernos, como HTTP/2.

AIOHTTP

Quando se trata de programação assíncrona, o AIOHTTP tem sido amplamente usado em Python há muito tempo. Se você estiver executando um servidor, um aplicativo do lado do cliente ou uma rede distribuída, o AIOHTTP pode atender a todas essas necessidades. No entanto, dos três (Requests, HTTPX e AIOHTTP), o AIOHTTP tem a curva de aprendizado mais íngreme.

Estamos nos concentrando no uso simples do lado do cliente, então não vamos nos aprofundar muito na questão do AIOHTTP. Assim como o HTTPX, podemos fazer lotes de solicitações com AIOHTTP. No entanto, diferentemente do HTTPX, o AIOHTTP não oferece suporte para solicitações síncronas. Só não faça muitos de uma vez… você não quer ser banido pelo servidor.

Instalação

pip install aiohttp

Dê uma olhada no uso básico abaixo.

import aiohttp
import asyncio

# make a single request
async def main():
    async with aiohttp.ClientSession() as client:
        response = await client.get("https://jsonplaceholder.typicode.com/posts")
        print(response)
        
asyncio.run(main())


# basic async session usage
async def main():
    with aiohttp.ClientSession() as client:
        for response in range(1000):
            response = await client.get("https://jsonplaceholder.typicode.com/posts")
            print(response)
            
asyncio.run(main())

AIOHTTP é estritamente assíncrono. Como você pode ver no código acima, nosso exemplo de solicitação única exige muito mais código do que qualquer um dos dois primeiros exemplos. Não importa quantas solicitações precisemos fazer, precisamos configurar uma sessão assíncrona, portanto, é recomendado combinar proxies com AIOHTTP. Para uma única solicitação, isso é definitivamente um exagero.

Por mais pontos fortes que tenha, o AIOHTTP não substituirá completamente Requests do Python, a menos que você esteja lidando com toneladas de solicitações de entrada e saída ao mesmo tempo. Então, isso aumentará substancialmente seu desempenho. Use AIOHTTP quando estiver criando aplicativos complexos e exigindo comunicação ultrarrápida. Essa biblioteca é melhor para servidores, redes distribuídas e aplicativos de web scraping altamente complexos.

Comparação de desempenho

Agora, vamos criar um pequeno programa usando cada biblioteca. Os requisitos são simples: abra uma sessão de cliente e realize 1000 solicitações de API.

Primeiro, precisamos criar nossa sessão com o servidor. Em seguida, realizamos 1000 solicitações. Teremos duas matrizes: uma para respostas boas e outra para respostas ruins. Quando a execução estiver concluída, imprimimos a contagem completa de solicitações boas e solicitações ruins. Se recebermos alguma solicitação incorreta, exibimos seus códigos de status no console.

Com nossos exemplos assíncronos (HTTPX e AIOHTTP), usaremos a função chunkify(). Isso é usado para dividir uma matriz em partes. Em seguida, realizamos as solicitações em lotes. Por exemplo, se quisermos realizar nossas solicitações em lotes de 50, usaremos chunkify() para criar o lote e usaremos process_chunk() para realizar todas as 50 solicitações de uma vez.

Dê uma olhada nessas funções abaixo.

def chunkify(iterable, size):
    iterator = iter(iterable)
    while chunk := list(islice(iterator, size)):
        yield chunk
        
        
async def process_chunk(client, urls, retries=3):
    tasks = [fetch(client, url, retries) for url in urls]
    return await asyncio.gather(*tasks)

Requests

Aqui está nosso código usando Requests. É muito simples em comparação com os dois exemplos assíncronos que usamos posteriormente. Abrimos uma sessão e usamos um loop for para iterar as solicitações.

import requests
import json
from datetime import datetime

start_time = datetime.now()
good_responses = []
bad_responses = []

with requests.Session() as client:

    for get_request in range(1000):
        response = client.get("https://jsonplaceholder.typicode.com/posts")
        status_code = response.status_code
        if status_code  == 200:
            good_responses.append(status_code)
        else:
            bad_responses.append(status_code)

end_time = datetime.now()

print("----------------Requests------------------")
print(f"Time elapsed: {end_time - start_time}")
print(f"Good Responses: {len(good_responses)}")
print(f"Bad Responses: {len(bad_responses)}")

for status_code in set(bad_responses):
    print(status_code)
Resultados do Python Requests

Requests concluiu o trabalho para nós em pouco mais de 51 segundos. Isso resulta em cerca de 20 solicitações por segundo. Sem usar uma sessão, você pode esperar 2 segundos por solicitação. Esse é um desempenho muito bom.

HTTPX

Aqui está o código para HTTPX. Utilizamos chunkify() e process_chunk() como mencionamos anteriormente.

import httpx
import asyncio
from datetime import datetime
from itertools import islice

def chunkify(iterable, size):
    iterator = iter(iterable)
    while chunk := list(islice(iterator, size)):
        yield chunk

async def fetch(client, url, retries=3):
    """Fetch a URL with retries."""
    for attempt in range(retries):
        try:
            response = await client.get(url)
            return response.status_code
        except httpx.RequestError as e:
            if attempt < retries - 1:
                await asyncio.sleep(1)
            else:
                return f"Error: {e}"

async def process_chunk(client, urls, retries=3):
    tasks = [fetch(client, url, retries) for url in urls]
    return await asyncio.gather(*tasks)

async def main():
    url = "https://jsonplaceholder.typicode.com/posts"
    total_requests = 1000
    chunk_size = 50

    good_responses = []
    bad_responses = []

    async with httpx.AsyncClient(timeout=10) as client:
        start_time = datetime.now()

        urls = [url] * total_requests
        for chunk in chunkify(urls, chunk_size):
            results = await process_chunk(client, chunk)
            for status in results:
                if isinstance(status, int) and status == 200:
                    good_responses.append(status)
                else:
                    bad_responses.append(status)

        end_time = datetime.now()

        print("----------------HTTPX------------------")
        print(f"Time elapsed: {end_time - start_time}")
        print(f"Good Responses: {len(good_responses)}")
        print(f"Bad Responses: {len(bad_responses)}")

        if bad_responses:
            print("Bad Status Codes or Errors:")
            for error in set(bad_responses):
                print(error)

asyncio.run(main())

Aqui está nosso resultado ao usar HTTPX. Comparado a Requests, é impressionante. O tempo total foi de pouco mais de 7 segundos. Como resultado são 139,47 solicitações por segundo. O HTTPX nos deu aproximadamente 7 vezes o desempenho do Requests.

Resultados HTTPX

AIOHTTP

Agora, faremos o mesmo exercício usando AIOHTTP. Seguimos a mesma estrutura básica que usamos com o exemplo HTTPX. A única grande diferença aqui é onde o cliente AIOHTTP substitui o cliente HTTPX.

import aiohttp
import asyncio
from datetime import datetime
from itertools import islice

def chunkify(iterable, size):
    iterator = iter(iterable)
    while chunk := list(islice(iterator, size)):
        yield chunk

async def fetch(session, url, retries=3):
    for attempt in range(retries):
        try:
            async with session.get(url) as response:
                return response.status
        except aiohttp.ClientError as e:
            if attempt < retries - 1:
                await asyncio.sleep(1)
            else:
                return f"Error: {e}"

async def process_chunk(session, urls):
    tasks = [fetch(session, url) for url in urls]
    return await asyncio.gather(*tasks)

async def main():
    url = "https://jsonplaceholder.typicode.com/posts"
    total_requests = 1000
    chunk_size = 50

    good_responses = []
    bad_responses = []

    async with aiohttp.ClientSession() as session:
        start_time = datetime.now()

        urls = [url] * total_requests
        for chunk in chunkify(urls, chunk_size):
            results = await process_chunk(session, chunk)
            for status in results:
                if isinstance(status, int) and status == 200:
                    good_responses.append(status)
                else:
                    bad_responses.append(status)

        end_time = datetime.now()

        print("----------------AIOHTTP------------------")
        print(f"Time elapsed: {end_time - start_time}")
        print(f"Good Responses: {len(good_responses)}")
        print(f"Bad Responses: {len(bad_responses)}")

        if bad_responses:
            print("Bad Status Codes or Errors:")
            for error in set(bad_responses):
                print(error)

asyncio.run(main())

O AIOHTTP chegou muito rápido em pouco mais de 4 segundos. Esse cliente HTTP rendeu mais de 241 solicitações por segundo! O AIOHTTP é aproximadamente 10 vezes mais rápido que Requests e quase 50% mais rápido que o HTTPX. Em Python, o AIOHTTP está em uma categoria própria quando se trata de desempenho.

Resultados AIOHTTP

Como os produtos da Bright Data podem ajudar

A Bright Data oferece uma variedade de soluções que podem aprimorar seus fluxos de trabalho baseados em clientes HTTP, especialmente para operações com muitos dados, como web scraping, solicitações de API e integrações de alto desempenho. Veja como cada produto se encaixa:

  • Proxies residenciais — Os proxies residenciais da Bright Data ajudam a evitar bloqueios e proibições enquanto copiam sites usando clientes HTTP Python, como AIOHTTP ou HTTPX. Esses proxies imitam o comportamento do usuário real, fornecendo acesso a conteúdo dinâmico ou com restrição geográfica com facilidade.
  • APIs de Web Scraper — Em vez de criar e manter sua própria infraestrutura de raspagem, as APIs de Web Scraper da Bright Data fornecem acesso pré-configurado a centenas de sites populares. Isso permite que você se concentre na análise de dados em vez de lidar com solicitações, novas tentativas ou proibições. Basta usar uma chamada de API para obter dados estruturados diretamente.
  • Conjuntos de dados prontos — Para quem precisa de pontos de dados específicos, mas quer evitar completamente a coleta, a Bright Data oferece conjuntos de dados prontos, adaptados às suas necessidades. Esses conjuntos de dados incluem detalhes de produtos, preços e avaliações, e podem ser usados instantaneamente para análise de comércio eletrônico ou pesquisa de mercado.
  • Web Unlocker — O Web Unlocker lida automaticamente com desafios como CAPTCHAs, mecanismos anti-bot e padrões de solicitação complexos. Combine-o com bibliotecas como HTTPX ou AIOHTTP para agilizar o processo de captura de sites de difícil acesso.
  • API SERP — Se você estiver extraindo dados de mecanismos de pesquisa, a API SERP da Bright Data simplifica o processo, oferecendo acesso confiável e em tempo real aos resultados de pesquisa, anúncios e classificações sem se preocupar com infraestrutura ou bloqueio.

Ao integrar as ferramentas da Bright Data aos clientes HTTP Python, você pode criar sistemas robustos e de alto desempenho que simplificam a coleta de dados e, ao mesmo tempo, superam os desafios típicos de captura e aquisição de dados na web.

Conclusão

No mundo dos clientes HTTP, Requests é o padrão simplesmente por causa de sua facilidade de uso. Comparado a Requests, o HTTPX é mais parecido com a mudança de uma carruagem puxada por cavalos para um carro moderno. Oferece um equilíbrio entre alto desempenho e facilidade de uso. O AIOHTTP é como um foguete. Você não quer usá-lo a menos que seja absolutamente necessário, mas ele ainda é, de longe, o cliente HTTP mais rápido que existe.

Inscreva-se hoje mesmo na Bright Data para desbloquear soluções de dados poderosas e obter a vantagem competitiva de que sua empresa precisa. Todos os produtos vêm com um teste gratuito!

Não é necessário cartão de crédito