← Voltar ao blog

Python requests: ProxyError, SSLError WRONG_VERSION_NUMBER e 407 — como corrigir na prática

Análise detalhada dos erros comuns ao trabalhar com proxies na biblioteca Python requests: ProxyError, SSLError WRONG_VERSION_NUMBER, 407 Proxy Authentication Required. Exemplos de código funcionais para cada situação.

📅11 de novembro de 2026

Se você está fazendo scraping de sites ou automatizando requisições através de proxies em Python, mais cedo ou mais tarde você encontrará três erros clássicos: ProxyError, SSLError: WRONG_VERSION_NUMBER e HTTP 407 Proxy Authentication Required. Neste artigo, vamos analisar a causa de cada um deles e mostrar um código funcional para correção.

Como requests trabalha com proxies: sintaxe básica

A biblioteca requests aceita proxies através de um dicionário proxies, onde as chaves são os esquemas de requisição (http e https), e os valores são URLs do servidor proxy com autorização opcional.

import requests

proxies = {
    "http": "http://user:password@proxy_host:port",
    "https": "http://user:password@proxy_host:port",
}

response = requests.get("https://httpbin.org/ip", proxies=proxies, timeout=10)
print(response.json())

Observe: mesmo para requisições HTTPS, o esquema do proxy geralmente é especificado como http://, porque a maioria dos servidores proxy aceita um túnel CONNECT através do protocolo HTTP, e não o encapsula em SSL. Se você especificar https:// para um proxy que não suporta isso — você receberá exatamente um SSLError, cuja análise será feita a seguir.

Se você estiver trabalhando com proxies SOCKS5, será necessário um pacote adicional:

pip install requests[socks]

# E a sintaxe de proxies muda:
proxies = {
    "http": "socks5://user:password@proxy_host:port",
    "https": "socks5://user:password@proxy_host:port",
}

ProxyError: causas e soluções

requests.exceptions.ProxyError é um wrapper para exceções de rede de baixo nível que ocorrem ao tentar estabelecer uma conexão com o servidor proxy. Quatro cenários são mais comuns.

1. Proxy indisponível ou endereço/porta incorretos

requests.exceptions.ProxyError: HTTPSConnectionPool(host='example.com', port=443):
Max retries exceeded with url: / (Caused by ProxyError('Cannot connect to proxy.',
ConnectionResetError(104, 'Connection reset by peer')))

Verifique se o host e a porta estão corretos e se o servidor proxy está realmente ativo. A maneira mais rápida de diagnosticar é tentar conectar através do curl:

curl -x http://user:password@proxy_host:port https://httpbin.org/ip -v

2. Proxy bloqueou sua requisição (ban por IP ou User-Agent)

Proxies de data center frequentemente são banidos por sites-alvo porque seus intervalos de IP são conhecidos por sistemas antifraude. Se o erro aparece consistentemente ao acessar um site específico (por exemplo, Wildberries, Ozon ou redes sociais), e não em todos os sites ao mesmo tempo — o problema não está no proxy, mas em sua reputação. Nesse caso, mudar para proxies residenciais pode ajudar — eles usam IPs de usuários reais e são menos propensos a serem bloqueados por sistemas antifraude.

3. Limite de conexões simultâneas excedido

Se você está executando scraping multithread e abrindo centenas de conexões através do mesmo proxy, o servidor pode começar a descartar conexões extras. A solução é usar um pool de conexões através de requests.adapters.HTTPAdapter com limites de pool_maxsize e max_retries:

from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry

session = requests.Session()
retries = Retry(total=3, backoff_factor=1, status_forcelist=[502, 503, 504])
adapter = HTTPAdapter(max_retries=retries, pool_connections=20, pool_maxsize=20)

session.mount("http://", adapter)
session.mount("https://", adapter)

response = session.get("https://httpbin.org/ip", proxies=proxies, timeout=10)

4. Timeout do lado do servidor proxy

Se o proxy "pendura" por mais tempo do que o timeout estabelecido, você verá ProxyError, encapsulado em ReadTimeoutError. Aumente o timeout para um valor razoável (geralmente 15-30 segundos é suficiente) e adicione o tratamento de exceção separadamente:

try:
    response = requests.get(url, proxies=proxies, timeout=20)
except requests.exceptions.ProxyError as e:
    print(f"Problema com o proxy: {e}")
except requests.exceptions.Timeout:
    print("O proxy não respondeu no tempo determinado")

SSLError WRONG_VERSION_NUMBER: análise do problema

Este erro é um dos mais incompreensíveis à primeira vista, mas na verdade tem quase sempre uma única causa.

requests.exceptions.SSLError: HTTPSConnectionPool(host='example.com', port=443):
Max retries exceeded with url: / (Caused by SSLError(SSLError(1, '[SSL:
WRONG_VERSION_NUMBER] wrong version number (_ssl.c:1123)')))

WRONG_VERSION_NUMBER significa que o cliente tentou realizar o handshake SSL/TLS onde o servidor espera tráfego HTTP normal (sem criptografia). A causa mais comum está em um esquema de proxy incorretamente especificado no dicionário proxies.

Erro comum: especificar https:// em vez de http:// no endereço do servidor proxy. A maioria dos proxies HTTP(S) aceita a conexão via HTTP normal, mesmo quando proxyando tráfego HTTPS através do mecanismo CONNECT.

# INCORRETO — causará WRONG_VERSION_NUMBER
proxies = {
    "http": "https://user:password@proxy_host:port",
    "https": "https://user:password@proxy_host:port",
}

# CORRETO
proxies = {
    "http": "http://user:password@proxy_host:port",
    "https": "http://user:password@proxy_host:port",
}

A segunda causa comum é uma porta que fisicamente não suporta TLS. Por exemplo, se o provedor de proxy designou a porta 8080 apenas para tráfego HTTP, e você tenta estabelecer uma conexão TLS diretamente (pulando o CONNECT), o servidor responderá com texto simples em vez de um handshake TLS, e a biblioteca cliente OpenSSL gerará exatamente esse erro. Verifique na documentação do seu provedor de proxy quais portas e protocolos (HTTP/HTTPS/SOCKS5) estão disponíveis em cada porta específica.

A terceira opção é que você está usando socket ou bibliotecas de terceiros para uma conexão TCP direta com o proxy, pulando o mecanismo padrão do requests. Nesse caso, certifique-se de que a camada TLS é aplicada apenas ao site de destino real, e não à própria conexão com o proxy.

407 Proxy Authentication Required: autorização

O código de resposta 407 é análogo ao padrão 401, mas para servidores proxy. Isso significa que o servidor requer autorização, e você não a forneceu ou a forneceu em um formato incorreto.

Método 1: login e senha diretamente na URL

proxies = {
    "http": "http://login:password@proxy_host:port",
    "https": "http://login:password@proxy_host:port",
}

response = requests.get("https://httpbin.org/ip", proxies=proxies)

Este método é o mais simples, mas se o login ou a senha contiverem caracteres especiais (por exemplo, @, :, /), eles precisam ser escapados através de urllib.parse.quote:

from urllib.parse import quote

login = quote("user@domain")
password = quote("p@ssw:ord!")

proxy_url = f"http://{login}:{password}@proxy_host:port"
proxies = {"http": proxy_url, "https": proxy_url}

Método 2: cabeçalho Proxy-Authorization manualmente

Se o provedor de proxy usar um esquema de autorização não padrão ou se você precisar de mais controle, pode montar o cabeçalho manualmente através da codificação base64:

import base64
import requests

login = "user"
password = "password"
credentials = base64.b64encode(f"{login}:{password}".encode()).decode()

headers = {
    "Proxy-Authorization": f"Basic {credentials}"
}

proxies = {
    "http": "http://proxy_host:port",
    "https": "http://proxy_host:port",
}

response = requests.get(
    "https://httpbin.org/ip",
    proxies=proxies,
    headers=headers,
    timeout=10
)

Importante: alguns provedores de proxy vinculam a autorização não ao login/senha, mas a um IP estático específico do cliente (whitelist). Se você mudar de IP (por exemplo, trabalhar através de VPN ou IP dinâmico do provedor), o erro 407 pode aparecer mesmo com credenciais corretas — porque seu IP externo atual não está na lista de permissões do proxy. A solução é acessar o painel do provedor e atualizar a lista de IPs permitidos, ou mudar para autorização por login/senha em vez de whitelist de IP.

Lógica de Retry e tratamento de exceções

Na prática, erros de proxy raramente são únicos — especialmente durante scraping em massa. A arquitetura correta do código deve prever tentativas de repetição com atraso e registro de cada erro separadamente.

import time
import requests
import logging

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

def fetch_with_retry(url, proxies, max_retries=3, backoff=2):
    for attempt in range(1, max_retries + 1):
        try:
            response = requests.get(url, proxies=proxies, timeout=15)
            response.raise_for_status()
            return response
        except requests.exceptions.ProxyError as e:
            logger.warning(f"[Tentativa {attempt}] ProxyError: {e}")
        except requests.exceptions.SSLError as e:
            logger.warning(f"[Tentativa {attempt}] SSLError: {e}")
        except requests.exceptions.HTTPError as e:
            if response.status_code == 407:
                logger.error("407: verifique login/senha ou whitelist de IP do proxy")
                break
            logger.warning(f"[Tentativa {attempt}] HTTPError: {e}")
        except requests.exceptions.Timeout:
            logger.warning(f"[Tentativa {attempt}] Timeout de conexão")

        time.sleep(backoff * attempt)

    raise RuntimeError(f"Não foi possível obter {url} após {max_retries} tentativas")

Essa abordagem economiza horas de depuração: em vez de o script falhar na primeira falha de rede, você obtém um log claro indicando o tipo específico de erro em cada tentativa.

Rotação de proxies e combate a bans

Se ProxyError e 407 estão frequentemente relacionados às configurações do código, bans em massa e falhas de conexão estáveis em domínios específicos quase sempre indicam um problema com a qualidade do próprio pool de IPs. Para tarefas como scraping de marketplaces (Wildberries, Ozon, Avito) ou trabalho com redes sociais, recomenda-se a rotação de IP a cada requisição ou através de um intervalo determinado.

import random

proxy_pool = [
    "http://user:[email protected]:8000",
    "http://user:[email protected]:8000",
    "http://user:[email protected]:8000",
]

def get_random_proxy():
    proxy = random.choice(proxy_pool)
    return {"http": proxy, "https": proxy}

response = requests.get(url, proxies=get_random_proxy(), timeout=15)

Para parsers em produção, geralmente é mais conveniente usar proxies com rotação automática do lado do provedor — assim não é necessário manter uma lista de IPs, a rotação ocorre de forma transparente através de um único endpoint. Nesse caso, proxies residenciais com rotação são especialmente adequados para contornar proteções anti-bot em sites com sistemas de detecção rigorosos, enquanto proxies de data center são uma boa escolha se a velocidade das requisições é importante e o site alvo não bloqueia agressivamente intervalos de data center.

Tipo de proxy Velocidade Risco de ban Tarefas
Data center Alta Médio-alto Scraping rápido de APIs abertas
Residenciais Média Baixo Scraping de marketplaces, redes sociais
Móveis Média-baixa Mínimo Trabalho com sistemas anti-bot rigorosos

Session, timeouts e verificação de SSL

Para scripts de longa duração (por exemplo, parsers cíclicos), é recomendável usar requests.Session() em vez de chamadas separadas requests.get(). A Session reutiliza conexões TCP, o que reduz a carga no servidor proxy e diminui o número de ProxyErrors em grandes volumes de requisições.

session = requests.Session()
session.proxies.update({
    "http": "http://user:password@proxy_host:port",
    "https": "http://user:password@proxy_host:port",
})

for url in urls_list:
    try:
        resp = session.get(url, timeout=15)
        print(resp.status_code, url)
    except requests.exceptions.RequestException as e:
        print(f"Erro em {url}: {e}")

Vale mencionar separadamente o parâmetro verify. Se você estiver trabalhando com um proxy que altera o certificado SSL (proxy MITM para depuração ou alguns proxies corporativos), o requests pode reclamar sobre a discrepância do certificado. Desativar a verificação completamente (verify=False) deve ser feito apenas em um ambiente de teste — em produção isso cria risco de ataques "homem no meio":

# Apenas para depuração local!
response = requests.get(url, proxies=proxies, verify=False, timeout=15)

# A maneira correta — especificar o caminho para o certificado confiável do proxy
response = requests.get(url, proxies=proxies, verify="/path/to/proxy_cert.pem")

Checklist de diagnóstico de erros

Se o script falhar com um erro de proxy, passe por esta lista de cima para baixo — em 90% dos casos a causa será encontrada nos primeiros três itens.

  1. Verifique o esquema no dicionário proxies — quase sempre deve ser http://, mesmo para requisições HTTPS.
  2. Teste o proxy diretamente através de curl -x, para excluir problemas do lado do código.
  3. Certifique-se de que o login e a senha não contenham caracteres especiais não escapados na URL.
  4. Verifique se o proxy não está vinculado a um IP específico (whitelist) em vez de autorização por login/senha.
  5. Aumente o timeout para 15-30 segundos antes de considerar o proxy inoperante.
  6. Se o erro aparecer apenas em um site específico — o problema está na reputação do IP, e não no código.
  7. Adicione lógica de retry com atraso exponencial em vez de tentativas únicas.
  8. Durante scraping em massa, use rotação de IP, e não um único proxy estático para todas as requisições.

Conclusão

A maioria dos erros de proxy em Python requests se resume a três coisas: esquema incorreto na URL do proxy (http em vez de https), falta ou formato incorreto de autorização, e qualidade do próprio pool de IPs. ProxyError geralmente indica um problema de conexão ou banimento do IP, SSLError WRONG_VERSION_NUMBER quase sempre aponta para um esquema de proxy incorreto, e 407 — para um problema com login/senha ou whitelist.

Se você frequentemente enfrenta bans e erros 407 ao fazer scraping de marketplaces ou redes sociais, é hora de reconsiderar a fonte do proxy, e não apenas o código. Para scraping estável com baixa taxa de bloqueios, recomendamos experimentar proxies residenciais — eles usam IPs reais e raramente causam ProxyError em sites protegidos. Se a prioridade é a velocidade e o volume de requisições, e não contornar sistemas anti-bot complexos, considere proxies de data center — eles são mais baratos e mais rápidos para tarefas simples de scraping.