Torna al blog

Perché il Proxy Funziona nel Browser ma Non nel Codice: Analisi Completa del Problema

Proxy funziona bene nel browser, ma lo script restituisce errori? Analizziamo le cause tipiche e forniamo soluzioni pronte per Python, Node.js e cURL.

📅11 dicembre 2025
```html

Perché il proxy funziona nel browser ma non nel codice: analisi completa del problema

Situazione classica: configuri un proxy nel browser, apri un sito — tutto funziona. Avvii uno script con lo stesso proxy — errore di connessione, timeout o blocco. Vediamo perché succede e come risolverlo.

In cosa differisce una richiesta dal browser rispetto a una dal codice

Quando apri un sito nel browser tramite un proxy, succede molto di più di una semplice richiesta HTTP. Il browser esegue automaticamente:

  • L'invio di un set completo di intestazioni (User-Agent, Accept, Accept-Language, Accept-Encoding)
  • L'esecuzione dell'handshake TLS con un set di cifrari appropriato
  • La gestione di reindirizzamenti e cookie
  • L'esecuzione di JavaScript e il caricamento delle risorse dipendenti
  • La memorizzazione nella cache delle risposte DNS e dei certificati

Una richiesta minima dal codice appare molto diversa per il server: assomiglia a un robot, non a un utente umano. Anche se il proxy funziona correttamente, il sito di destinazione potrebbe bloccare specificamente il tuo script.

Problemi di autenticazione del proxy

La causa più comune è il passaggio errato di login e password. Il browser mostra una finestra pop-up per inserire le credenziali, mentre nel codice questo deve essere fatto esplicitamente.

Formato URL errato

Un errore frequente è l'omissione dello schema o la codifica errata dei caratteri speciali:

# Errato
proxy = "user:pass@proxy.example.com:8080"

# Corretto
proxy = "http://user:pass@proxy.example.com:8080"

# Se la password contiene caratteri speciali (@, :, /)
from urllib.parse import quote
password = quote("p@ss:word/123", safe="")
proxy = f"http://user:{password}@proxy.example.com:8080"

Autenticazione basata su IP vs login/password

Alcuni fornitori di proxy utilizzano una whitelist basata sull'indirizzo IP. Il browser sul tuo computer funziona perché il tuo IP è nella whitelist. Ma lo script su un server no, perché il server ha un IP diverso.

Verifica nel pannello del provider quale metodo di autenticazione viene utilizzato e quali IP sono aggiunti alla whitelist.

Incongruenza dei protocolli HTTP/HTTPS/SOCKS

Il browser spesso determina automaticamente il tipo di proxy. Nel codice, è necessario specificarlo esplicitamente, e un errore nel protocollo porta a un rifiuto silenzioso.

Tipo di Proxy Schema nell'URL Caratteristiche
Proxy HTTP http:// Funziona per HTTP e HTTPS tramite CONNECT
Proxy HTTPS https:// Connessione crittografata al proxy
SOCKS4 Proxy socks4:// Senza autenticazione, solo IPv4
SOCKS5 Proxy socks5:// Con autenticazione, UDP, IPv6
SOCKS5h Proxy socks5h:// Risoluzione DNS tramite proxy

È fondamentale: se hai un proxy SOCKS5 ma specifichi http://, la connessione non verrà stabilita. La libreria tenterà di comunicare tramite protocollo HTTP con un server SOCKS.

Intestazioni mancanti e fingerprinting

Anche se il proxy funziona correttamente, il sito di destinazione potrebbe bloccare la richiesta a causa di intestazioni sospette. Confrontiamo:

Richiesta dal browser

GET /api/data HTTP/1.1
Host: example.com
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36...
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
Upgrade-Insecure-Requests: 1
Sec-Fetch-Dest: document
Sec-Fetch-Mode: navigate
Sec-Fetch-Site: none
Sec-Fetch-User: ?1

Richiesta predefinita con requests

GET /api/data HTTP/1.1
Host: example.com
User-Agent: python-requests/2.28.0
Accept-Encoding: gzip, deflate
Accept: */*
Connection: keep-alive

La differenza è evidente. Un sito con protezione anti-bot identificherà immediatamente che la richiesta non proviene da un browser.

Set minimo di intestazioni per mascherarsi

headers = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
    "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8",
    "Accept-Language": "en-US,en;q=0.9",
    "Accept-Encoding": "gzip, deflate, br",
    "Connection": "keep-alive",
    "Upgrade-Insecure-Requests": "1",
    "Sec-Fetch-Dest": "document",
    "Sec-Fetch-Mode": "navigate",
    "Sec-Fetch-Site": "none",
    "Sec-Fetch-User": "?1",
    "Cache-Control": "max-age=0"
}

Certificati SSL e verifica

Il browser dispone di un archivio integrato di certificati root ed è in grado di gestire varie configurazioni SSL. Nel codice possono sorgere problemi:

Errore SSL: CERTIFICATE_VERIFY_FAILED

Alcuni proxy utilizzano i propri certificati per ispezionare il traffico. Il browser potrebbe avere questo certificato come attendibile, ma il tuo script no.

# Soluzione temporanea per il debug (NON per la produzione!)
import requests
response = requests.get(url, proxies=proxies, verify=False)

# Soluzione corretta — specificare il percorso del certificato
response = requests.get(url, proxies=proxies, verify="/path/to/proxy-ca.crt")

Importante: Disabilitare la verifica SSL (verify=False) rende la connessione vulnerabile agli attacchi MITM. Usare solo per il debug in un ambiente sicuro.

TLS Fingerprint

I sistemi anti-bot avanzati analizzano il TLS fingerprint — l'ordine e il set di cifrari utilizzati durante l'instaurazione della connessione. Python requests utilizza un set standard che differisce da quello del browser.

Per aggirare questo problema, utilizzare librerie con un TLS fingerprint personalizzato:

# Installazione: pip install curl-cffi
from curl_cffi import requests

response = requests.get(
    url,
    proxies={"https": proxy},
    impersonate="chrome120"  # Simula il TLS fingerprint di Chrome 120
)

Fughe di DNS e risoluzione

Un altro problema non ovvio è la risoluzione DNS. Quando si utilizza un proxy HTTP, la richiesta DNS può partire direttamente dalla tua macchina, bypassando il proxy.

Come influisce sul funzionamento

  • Il sito vede il resolver DNS reale, non il proxy
  • La geolocalizzazione viene determinata in modo errato
  • Alcuni siti bloccano l'incongruenza tra IP e regione DNS

Soluzione per SOCKS5

Utilizza lo schema socks5h:// invece di socks5:// — la "h" indica che la risoluzione DNS verrà eseguita sul lato proxy:

# DNS risolto localmente (fuga!)
proxy = "socks5://user:pass@proxy.example.com:1080"

# DNS risolto tramite proxy (corretto)
proxy = "socks5h://user:pass@proxy.example.com:1080"

Esempi funzionanti per Python, Node.js e cURL

Python con requests

import requests
from urllib.parse import quote

# Dati del proxy
proxy_host = "proxy.example.com"
proxy_port = "8080"
proxy_user = "username"
proxy_pass = quote("p@ssword!", safe="")  # Codifica i caratteri speciali

# Formazione dell'URL del proxy
proxy_url = f"http://{proxy_user}:{proxy_pass}@{proxy_host}:{proxy_port}"

proxies = {
    "http": proxy_url,
    "https": proxy_url
}

headers = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
    "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
    "Accept-Language": "en-US,en;q=0.9",
    "Accept-Encoding": "gzip, deflate, br",
}

try:
    response = requests.get(
        "https://httpbin.org/ip",
        proxies=proxies,
        headers=headers,
        timeout=30
    )
    print(f"Status: {response.status_code}")
    print(f"IP: {response.json()}")
except requests.exceptions.ProxyError as e:
    print(f"Errore proxy: {e}")
except requests.exceptions.ConnectTimeout:
    print("Timeout di connessione al proxy")

Python con aiohttp (asincrono)

import aiohttp
import asyncio

async def fetch_with_proxy():
    proxy_url = "http://user:pass@proxy.example.com:8080"
    
    async with aiohttp.ClientSession() as session:
        async with session.get(
            "https://httpbin.org/ip",
            proxy=proxy_url,
            headers={"User-Agent": "Mozilla/5.0..."}
        ) as response:
            return await response.json()

result = asyncio.run(fetch_with_proxy())
print(result)

Node.js con axios

const axios = require('axios');
const HttpsProxyAgent = require('https-proxy-agent');

const proxyUrl = 'http://user:pass@proxy.example.com:8080';
const agent = new HttpsProxyAgent(proxyUrl);

axios.get('https://httpbin.org/ip', {
    httpsAgent: agent,
    headers: {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36...'
    }
})
.then(response => console.log(response.data))
.catch(error => console.error('Error:', error.message));

Node.js con node-fetch e SOCKS

const fetch = require('node-fetch');
const { SocksProxyAgent } = require('socks-proxy-agent');

const agent = new SocksProxyAgent('socks5://user:pass@proxy.example.com:1080');

fetch('https://httpbin.org/ip', { agent })
    .then(res => res.json())
    .then(data => console.log(data));

cURL

# Proxy HTTP
curl -x "http://user:pass@proxy.example.com:8080" \
     -H "User-Agent: Mozilla/5.0..." \
     https://httpbin.org/ip

# Proxy SOCKS5 con DNS tramite proxy
curl --socks5-hostname "proxy.example.com:1080" \
     --proxy-user "user:pass" \
     https://httpbin.org/ip

# Debug - mostra l'intero processo di connessione
curl -v -x "http://user:pass@proxy.example.com:8080" \
     https://httpbin.org/ip

Checklist di Diagnosi

Se il proxy non funziona nel codice, controlla in sequenza:

  1. Formato URL del proxy — è presente lo schema (http://, socks5://)?
  2. Caratteri speciali nella password — sono codificati tramite URL-encoding?
  3. Tipo di proxy — il protocollo specificato corrisponde a quello reale?
  4. Autenticazione — tramite IP o tramite login? L'IP del server è nella whitelist?
  5. Intestazioni — sono state aggiunte le intestazioni del browser (User-Agent, ecc.)?
  6. SSL — ci sono errori di certificato?
  7. DNS — è stato utilizzato socks5h:// per la risoluzione tramite proxy?
  8. Timeout — è stato concesso abbastanza tempo per la connessione (specialmente per i proxy residenziali)?

Conclusione

La differenza tra browser e codice risiede nei dettagli: intestazioni, protocolli, SSL, DNS. Il browser nasconde questa complessità, mentre nel codice ogni aspetto deve essere configurato esplicitamente. Inizia controllando il formato dell'URL e l'autenticazione, quindi aggiungi le intestazioni del browser: questo risolve il 90% dei problemi.

Per compiti di scraping e automazione dove sono cruciali stabilità e bassa percentuale di blocco, i proxy residenziali sono una buona scelta — puoi saperne di più su proxycove.com.

```