HTTP, Requests e Download de Arquivos em Python

Laboratório de Programação — Ciência da Computação

Protocolo HTTP, biblioteca requests, análise de respostas e download com barra de progresso — com syntax highlighting

Introdução ao HTTP

  • HTTP é o protocolo base da Web: clientes (navegadores) ↔ servidores.
  • Troca de mensagens requisiçãoresposta, com métodos, códigos de status, cabeçalhos e corpo.
  • Versões: 0.9 → 1.0 → 1.1 (persistência) → HTTP/2 (desempenho) → HTTP/3 (QUIC).

Métodos comuns

  • GET — obter recurso
  • POST — enviar dados
  • PUT — atualizar recurso
  • DELETE — remover recurso
  • HEAD, PATCH, OPTIONS

Códigos de Status

  • 2xx Sucesso (200 OK)
  • 3xx Redirecionamento (301/302)
  • 4xx Erro do cliente (404 Not Found, 401/403)
  • 5xx Erro do servidor (500/502/503)

Cabeçalhos

  • Content-Type, Content-Length, Authorization, Accept, User-Agent.
  • Controlam formato, autenticação, cache e idioma.

Cookies, Sessões e Cache

  • Cookies & Sessões preservam estado entre requisições.
  • Cache melhora desempenho (ETag, Last-Modified).

Biblioteca requests (Python)

Interface simples e “pythônica” para HTTP.

pip install requests tqdm
import requests

r = requests.get("https://httpbin.org/get", timeout=10)
print(r.status_code)   # 200
print(r.headers["Content-Type"])
print(r.text[:120])    # corpo como string

Use timeout sempre que possível.

GET com parâmetros e cabeçalhos

url = "https://httpbin.org/get"
params = {"q": "python", "page": 1}
headers = {"User-Agent": "LabCC/1.0"}

r = requests.get(url, params=params, headers=headers, timeout=10)
print(r.url)           # URL final com querystring
data = r.json()        # se JSON válido

POST (JSON / form-data)

# JSON
r = requests.post("https://httpbin.org/post",
                  json={"usuario": "ana", "ativo": True}, timeout=10)

# Form
r2 = requests.post("https://httpbin.org/post",
                   data={"login": "user", "senha": "123"}, timeout=10)

Sessões (cookies persistentes)

s = requests.Session()
s.headers.update({"User-Agent": "LabCC/1.0"})
resp = s.get("https://httpbin.org/cookies/set?session=abc", timeout=10)
print(s.cookies.get_dict())

Tratando exceções

try:
    r = requests.get("https://exemplo.invalido", timeout=5)
    r.raise_for_status()  # lança HTTPError se 4xx/5xx
except requests.exceptions.Timeout:
    print("Timeout!")
except requests.exceptions.RequestException as e:
    print(f"Erro: {e}")

Analisando Respostas (requests)

  • Status Code: sucesso/erro (response.status_code).
  • Cabeçalhos: metadados (response.headers).
  • Conteúdo: .json(), .text, .content.
  • Encoding: response.encoding (ajuste se necessário).
  • Cookies: response.cookies.
r = requests.get("https://httpbin.org/anything", timeout=10)
if r.status_code == 200:
    print(r.headers.get("Content-Type"))
    payload = r.json() if "application/json" in r.headers.get("Content-Type","") else r.text
else:
    print(f"Falha: {r.status_code}")

Download de Arquivos (HTTP)

  • Use streaming para não carregar o arquivo inteiro na memória: stream=True.
  • Leia em chunks (ex.: 1024 bytes) e grave em modo binário 'wb'.
  • Exiba barra de progresso com tqdm usando Content-Length.
  • Valide status (raise_for_status()) e verifique headers.

Extraindo nome/extensão da URL

import os
from urllib.parse import urlparse

PROTOCOLOS_SUPORTADOS = {"http", "https"}

class Util:
    def extrair_nome_extensao_url(self, url: str):
        parsed = urlparse(url)
        if parsed.scheme not in PROTOCOLOS_SUPORTADOS:
            raise ValueError(f"Protocolo não suportado: {parsed.scheme}")
        caminho = os.path.basename(parsed.path)
        if not caminho or "." not in caminho:
            raise ValueError("Arquivo não identificado na URL")
        nome, ext = caminho.split(".", 1)
        return nome, ext

tqdm: barra de progresso

from tqdm import tqdm
import time

def faz_alguma_coisa():
    time.sleep(0.1)

total_seconds = 10
with tqdm(total=total_seconds, desc="Simulando", unit="s") as pbar:
    for _ in range(total_seconds):
        faz_alguma_coisa()
        pbar.update(1)

Download simples (stream + barra)

import requests
from tqdm import tqdm

url = "https://httpbin.org/image/png"
nome_arquivo = "imagem.png"

with requests.get(url, stream=True, timeout=30) as r:
    r.raise_for_status()
    total = int(r.headers.get("content-length", 0))
    with open(nome_arquivo, "wb") as f, tqdm(
        total=total, unit="B", unit_scale=True, desc=nome_arquivo
    ) as pbar:
        for chunk in r.iter_content(chunk_size=1024):
            if chunk:
                f.write(chunk)
                pbar.update(len(chunk))
print("Download concluído!")

Classe de Download com Callback

import requests
from tqdm import tqdm

class Download:
    def __init__(self, url: str, path_arquivo: str):
        self.url = url
        self.path_arquivo = path_arquivo
        self.callback = None  # def callback(total, progresso): ...

    def set_callback(self, cb):
        self.callback = cb

    def executa(self) -> int:
        try:
            with requests.get(self.url, stream=True, timeout=60) as r:
                r.raise_for_status()
                total = int(r.headers.get("content-length", 0))
                with open(self.path_arquivo, "wb") as f, tqdm(
                    total=total, unit="B", unit_scale=True, desc=self.path_arquivo
                ) as pbar:
                    for chunk in r.iter_content(chunk_size=1024):
                        if chunk:
                            f.write(chunk)
                            pbar.update(len(chunk))
                            if self.callback:
                                self.callback(total, pbar.n)
            print(f"OK: {self.path_arquivo} ({total} bytes)")
            return total
        except requests.exceptions.MissingSchema:
            raise Exception("URL inválida. Verifique o esquema (http/https).")
        except requests.exceptions.RequestException as e:
            raise Exception(f"Erro na conexão: {e}")

Uso da classe

def on_progress(total, atual):
    if total:
        pct = (atual / total) * 100
        # aqui você pode notificar UI/log etc.
        # print(f"{pct:.1f}%")

url1 = "https://httpbin.org/image/png"
down = Download(url1, "meu_arquivo.png")
down.set_callback(on_progress)
down.executa()

Checklist de Análise da Resposta

  • Status code200 é sucesso típico; trate 4xx/5xx.
  • CabeçalhosContent-Type, Content-Length, ETag.
  • Conteúdo.json() / .text / .content.
  • Encoding → ajuste response.encoding quando necessário.
  • Exceçõestry/except RequestException + timeout.

Boas Práticas (HTTP/Requests)

  • Defina timeout e trate exceções.
  • Envie User-Agent informativo; respeite rate limits.
  • Use HTTPS sempre que possível.
  • Para APIs: autenticação (Bearer/API-Key) via headers.

Downloads Seguros

  • Valide URL, tamanho e tipo de conteúdo.
  • Salve em caminhos confiáveis; evite sobrepor sem querer.
  • Opcional: verifique hash do arquivo (integridade).

Exercícios (Lab)

  1. Faça um GET com parâmetros e imprima status, headers e os 200 primeiros caracteres do corpo.
  2. Implemente um POST com json e trate exceções (timeout, HTTPError).
  3. Baixe uma imagem (PNG/JPEG) exibindo a barra de progresso (tqdm).
  4. Transforme o download em função reutilizável e depois em classe com callback.

Conclusões

  • HTTP define como clientes e servidores se comunicam na Web.
  • requests simplifica requisições e análise de respostas em Python.
  • Com streaming + tqdm, implementamos downloads eficientes e informativos.