Base64 em Python: codificar, decodificar e o erro de bytes
O módulo base64 do Python trabalha com bytes, não com str. Entender essa distinção resolve de uma vez o erro mais comum de quem está começando.
O erro de bytes contra str
b64encode recebe bytes e devolve bytes. Passar uma str direto levanta TypeError, e esquecer o decode no fim deixa um valor com o prefixo b na frente ao imprimir.
import base64
# ✗ TypeError: a bytes-like object is required
base64.b64encode("ação")
# ✓ codifica para bytes na ida e volta para str no fim
codificado = base64.b64encode("ação".encode("utf-8")).decode("ascii")
# 'YcOnw6Nv'
decodificado = base64.b64decode(codificado).decode("utf-8")
# 'ação'Base64 seguro para URL
urlsafe_b64encode troca + e / por - e _. O preenchimento com = continua presente; JWT e outros formatos costumam removê-lo, e aí é preciso recolocá-lo antes de decodificar.
import base64
seguro = base64.urlsafe_b64encode(b"dados").decode("ascii").rstrip("=")
def decodificar_sem_padding(valor: str) -> bytes:
# b64decode exige que o tamanho seja múltiplo de 4
faltando = (-len(valor)) % 4
return base64.urlsafe_b64decode(valor + "=" * faltando)Arquivos
import base64
with open("imagem.png", "rb") as arquivo:
conteudo = base64.b64encode(arquivo.read()).decode("ascii")
data_uri = f"data:image/png;base64,{conteudo}"
# de volta para arquivo
with open("saida.png", "wb") as arquivo:
arquivo.write(base64.b64decode(conteudo))Validação estrita
Por padrão, b64decode ignora caracteres inválidos em silêncio. Com validate=True ele levanta erro — o que é preferível quando o dado vem de fora.
import base64
import binascii
try:
base64.b64decode(entrada, validate=True)
except binascii.Error:
print("Base64 inválido")Perguntas frequentes
- Por que aparece b'...' quando eu imprimo o resultado?
- Porque b64encode devolve bytes, e o b é a forma como o Python representa um objeto bytes. Chame .decode('ascii') para obter uma str limpa.
- Qual a diferença entre b64encode e urlsafe_b64encode?
- O alfabeto. A versão urlsafe usa - e _ no lugar de + e /, que precisariam de escape em URL. O resto do funcionamento é idêntico.