Torna al blog

Come configurare un proxy in Python requests per scraping, API e automazione: guida completa con esempi di codice

Guida completa per la connessione a un proxy nella libreria Python requests: dalla configurazione di base alla rotazione degli IP e al bypass delle restrizioni durante il parsing e l'automazione.

📅3 aprile 2026
```html

Se il tuo script Python restituisce un errore 403, CAPTCHA o un ban per IP, significa che il sito target ti ha già notato. Collegare un proxy alla libreria requests risolve questo problema: cambi l'indirizzo IP, aggiri le restrizioni geografiche e distribuisci il carico tra più indirizzi. In questa guida troverai tutto, dalla connessione di base alla rotazione avanzata con esempi di codice reali.

Perché sono necessari i proxy negli script Python

La maggior parte dei siti e delle API tiene traccia degli indirizzi IP delle richieste in arrivo. Se un indirizzo fa più di 100 richieste al minuto, viene bloccato. Questa è una protezione standard contro i bot, utilizzata da Wildberries, Ozon, Avito, Google, Instagram e centinaia di altre piattaforme. I proxy consentono di indirizzare la richiesta attraverso un server intermedio con un altro indirizzo IP, rendendoti invisibile ai sistemi di protezione.

Ecco i principali compiti in cui i proxy in Python sono criticamente necessari:

  • Scraping di marketplace — raccolta di prezzi da Wildberries, Ozon, Yandex.Market senza blocchi per IP
  • Monitoraggio dei concorrenti — richieste regolari ai siti dei concorrenti ogni 5-15 minuti
  • Interazione con API con limiti — distribuzione delle richieste tra più IP per non superare il rate limit
  • Test di geolocalizzazione — verifica di come appare un sito da diversi paesi e regioni
  • Automazione di moduli e registrazioni — creazione di account o compilazione di moduli da diversi IP
  • Monitoraggio SEO — raccolta di posizioni da diverse regioni della Russia e altri paesi

Senza proxy, anche un parser ben scritto si imbatterà in un blocco dopo poche ore di lavoro. Con una rotazione IP configurata correttamente, lo stesso script funziona per settimane senza interruzioni.

Configurazione di base del proxy in requests

La libreria requests supporta i proxy nativamente — non sono necessari pacchetti aggiuntivi. Il proxy viene passato tramite un dizionario proxies nei parametri della richiesta.

Il più semplice esempio è un proxy HTTP per una singola richiesta:

import requests

proxies = {
    "http": "http://123.45.67.89:8080",
    "https": "http://123.45.67.89:8080",
}

response = requests.get("https://httpbin.org/ip", proxies=proxies)
print(response.json())
# {'origin': '123.45.67.89'}
  

Nota: nel dizionario proxies è necessario specificare entrambe le chiavi — http e https. Se ne specifichi solo una, le richieste per il secondo protocollo andranno direttamente senza proxy. Questo è un errore comune tra i principianti, che causa comunque la fuga del vero IP.

Per assicurarti che il proxy funzioni, utilizza il servizio httpbin.org/ip — restituisce l'indirizzo IP da cui è arrivata la richiesta. Se nella risposta vedi l'IP del server proxy e non il tuo, tutto è configurato correttamente.

Proxy HTTP, HTTPS e SOCKS5: differenze ed esempi di codice

I proxy possono essere di diversi tipi, e ognuno è adatto per i propri compiti. Nel contesto di Python requests, è importante comprendere la differenza tra i tre protocolli principali:

Tipo Protocollo nell'URL Velocità Supporto UDP Miglior scenario
HTTP http:// Alta No Scraping di siti HTTP
HTTPS https:// Alta No Scraping di siti protetti
SOCKS5 socks5:// Media Massima anonimato, qualsiasi protocollo

Per lavorare con SOCKS5 in Python è necessario installare un pacchetto aggiuntivo:

pip install requests[socks]
# oppure separatamente:
pip install PySocks
  

Dopo l'installazione, la connessione a un proxy SOCKS5 appare così:

import requests

# Proxy SOCKS5
proxies = {
    "http": "socks5://123.45.67.89:1080",
    "https": "socks5://123.45.67.89:1080",
}

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

SOCKS5 è il protocollo preferito per compiti in cui l'anonimato è importante. A differenza dei proxy HTTP, SOCKS5 non aggiunge intestazioni X-Forwarded-For, che possono rivelare il tuo vero IP.

Proxy con autenticazione tramite username e password

La maggior parte dei servizi proxy a pagamento utilizza l'autenticazione tramite username e password. Questa è una pratica standard: senza autorizzazione, il proxy non permetterà semplicemente la tua richiesta. Nella libreria requests, i dati di autenticazione vengono passati direttamente nell'URL del proxy.

import requests

# Formato: protocollo://username:password@host:port
proxy_url = "http://myuser:[email protected]:8080"

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

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

Se nella password o nello username ci sono caratteri speciali (ad esempio, @, #, %), devono essere URL-encoded. Per questo, utilizza il modulo urllib.parse:

import requests
from urllib.parse import quote

username = "myuser"
password = "p@ss#word!"  # Caratteri speciali

# URL-encoding di username e password
encoded_user = quote(username, safe="")
encoded_pass = quote(password, safe="")

proxy_url = f"http://{encoded_user}:{encoded_pass}@123.45.67.89:8080"

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

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

💡 Consiglio di sicurezza

Non hardcodare mai username e password direttamente nel codice dello script. Utilizza variabili d'ambiente o un file .env con la libreria python-dotenv. In questo modo eviterai la fuga accidentale delle credenziali quando pubblichi il codice su GitHub.

Rotazione dei proxy: cambio automatico di IP per scraping

Un proxy è ancora un solo indirizzo IP, che può essere bloccato. La vera protezione contro i ban è la rotazione: ogni richiesta (o ogni N richieste) parte con un nuovo IP. Di seguito sono riportati alcuni approcci per implementare la rotazione.

Metodo 1: Selezione casuale da una lista

import requests
import random

# Lista di proxy
proxy_list = [
    "http://user:[email protected]:8080",
    "http://user:[email protected]:8080",
    "http://user:[email protected]:8080",
    "http://user:[email protected]:8080",
]

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

# Scraping di 10 pagine con rotazione IP
urls = [f"https://example.com/page/{i}" for i in range(1, 11)]

for url in urls:
    proxies = get_random_proxy()
    try:
        response = requests.get(url, proxies=proxies, timeout=10)
        print(f"URL: {url} | IP: {proxies['http'].split('@')[1]} | Status: {response.status_code}")
    except requests.RequestException as e:
        print(f"Errore: {e}")
  

Metodo 2: Rotazione ciclica tramite itertools

import requests
import itertools

proxy_list = [
    "http://user:[email protected]:8080",
    "http://user:[email protected]:8080",
    "http://user:[email protected]:8080",
]

# Creiamo un ciclo infinito sulla lista di proxy
proxy_cycle = itertools.cycle(proxy_list)

def get_next_proxy():
    proxy = next(proxy_cycle)
    return {"http": proxy, "https": proxy}

# Ogni richiesta utilizza il prossimo proxy in ciclo
for i in range(9):
    proxies = get_next_proxy()
    response = requests.get("https://httpbin.org/ip", proxies=proxies, timeout=10)
    print(f"Richiesta {i+1}: {response.json()['origin']}")
  

Per compiti industriali con migliaia di richieste all'ora, si consiglia di utilizzare proxy residenziali con rotazione automatica integrata: il fornitore cambia automaticamente l'IP per ogni richiesta attraverso un unico endpoint, e non è necessario gestire manualmente la lista degli indirizzi.

Proxy tramite Session: connessioni permanenti e cookie

Quando è necessario effettuare più richieste all'interno di una singola sessione (ad esempio, effettuare il login e poi fare richieste), utilizza l'oggetto requests.Session(). Questo mantiene i cookie, le intestazioni e le impostazioni del proxy tra le richieste — non è necessario passare il proxy in ogni chiamata separatamente.

import requests

# Creiamo una sessione con il proxy
session = requests.Session()
session.proxies = {
    "http": "http://user:[email protected]:8080",
    "https": "http://user:[email protected]:8080",
}

# Aggiungiamo intestazioni per imitare un browser
session.headers.update({
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
    "Accept-Language": "ru-RU,ru;q=0.9",
    "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
})

# Passo 1: Autenticazione
login_data = {"username": "myuser", "password": "mypass"}
session.post("https://example.com/login", data=login_data)

# Passo 2: Richieste già con i cookie e tramite proxy
response = session.get("https://example.com/dashboard")
print(response.status_code)

# Passo 3: Chiudiamo la sessione
session.close()
  

Utilizzare Session è anche più efficiente in termini di prestazioni: la connessione TCP viene riutilizzata, invece di essere riaperta per ogni richiesta. Durante lo scraping di oltre 1000 pagine, questo porta a un significativo aumento della velocità.

Gestione degli errori, dei timeout e ripetizioni automatiche

I server proxy possono essere non disponibili, rispondere lentamente o restituire errori di connessione. Uno script affidabile per lo scraping deve essere in grado di gestire queste situazioni e passare automaticamente a un altro proxy in caso di errore.

import requests
import random
import time

proxy_list = [
    "http://user:[email protected]:8080",
    "http://user:[email protected]:8080",
    "http://user:[email protected]:8080",
]

def fetch_with_retry(url, max_retries=3, timeout=10):
    """
    Effettua una richiesta con cambio automatico del proxy in caso di errore.
    Restituisce un oggetto Response o None al termine dei tentativi.
    """
    available_proxies = proxy_list.copy()
    random.shuffle(available_proxies)

    for attempt, proxy_url in enumerate(available_proxies[:max_retries], 1):
        proxies = {"http": proxy_url, "https": proxy_url}
        try:
            response = requests.get(
                url,
                proxies=proxies,
                timeout=timeout,
                headers={"User-Agent": "Mozilla/5.0"}
            )
            response.raise_for_status()  # Solleva un'eccezione per 4xx/5xx
            print(f"✓ Successo al tentativo {attempt}")
            return response

        except requests.exceptions.ProxyError:
            print(f"✗ Tentativo {attempt}: proxy non disponibile — {proxy_url}")
        except requests.exceptions.Timeout:
            print(f"✗ Tentativo {attempt}: timeout — {proxy_url}")
        except requests.exceptions.HTTPError as e:
            print(f"✗ Tentativo {attempt}: errore HTTP {e.response.status_code}")
            if e.response.status_code == 403:
                print("  → Ban ricevuto, proviamo il prossimo proxy...")
        except requests.exceptions.RequestException as e:
            print(f"✗ Tentativo {attempt}: errore generale — {e}")

        time.sleep(1)  # Pausa tra i tentativi

    print(f"✗ Tutti i {max_retries} tentativi esauriti per {url}")
    return None

# Utilizzo
result = fetch_with_retry("https://httpbin.org/ip")
if result:
    print(result.json())
  

Fai attenzione a raise_for_status() — questo metodo solleva automaticamente un'eccezione per gli stati HTTP 4xx e 5xx. Senza di esso, lo script considererà anche una risposta con codice 403 (ban) o 429 (limite di richieste superato) come riuscita.

Proxy tramite variabili d'ambiente: memorizzazione sicura dei dati

La libreria requests legge automaticamente le variabili d'ambiente HTTP_PROXY e HTTPS_PROXY. Questo consente di non memorizzare le credenziali nel codice e di passare facilmente tra i proxy senza modificare lo script.

Impostazione delle variabili nel terminale (Linux/macOS):

export HTTP_PROXY="http://user:[email protected]:8080"
export HTTPS_PROXY="http://user:[email protected]:8080"
export NO_PROXY="localhost,127.0.0.1"
  

Oppure tramite un file .env con la libreria python-dotenv:

# File .env (aggiungere a .gitignore!)
HTTP_PROXY=http://user:[email protected]:8080
HTTPS_PROXY=http://user:[email protected]:8080
  
# Script Python
from dotenv import load_dotenv
import requests
import os

load_dotenv()  # Carica le variabili da .env

# requests utilizza automaticamente HTTP_PROXY e HTTPS_PROXY
response = requests.get("https://httpbin.org/ip")
print(response.json())

# Oppure esplicitamente dalle variabili d'ambiente:
proxies = {
    "http": os.getenv("HTTP_PROXY"),
    "https": os.getenv("HTTPS_PROXY"),
}
response = requests.get("https://httpbin.org/ip", proxies=proxies)
print(response.json())
  

⚠️ Importante: variabile NO_PROXY

La variabile NO_PROXY consente di escludere determinati indirizzi dal proxy. Assicurati di aggiungere localhost e 127.0.0.1, affinché le richieste locali non passino attraverso il proxy.

Casi reali: scraping di marketplace, lavoro con API e automazione

Consideriamo tre scenari pratici che gli sviluppatori affrontano più frequentemente.

Scenario 1: Scraping dei prezzi da un marketplace

Quando si monitorano i prezzi su Wildberries o Ozon, è importante imitare il comportamento di un vero utente: inviare le intestazioni corrette del browser, aggiungere ritardi tra le richieste e ruotare gli IP. Per questo compito, i proxy dei data center sono molto adatti: sono veloci e economici per gestire grandi volumi di dati.

import requests
import time
import random

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": "application/json, text/plain, */*",
    "Accept-Language": "ru-RU,ru;q=0.9",
    "Referer": "https://www.wildberries.ru/",
}

PROXIES = [
    {"http": "http://user:[email protected]:8080",
     "https": "http://user:[email protected]:8080"},
    {"http": "http://user:[email protected]:8080",
     "https": "http://user:[email protected]:8080"},
]

def get_product_price(article_id: int) -> dict:
    """Ottiene il prezzo del prodotto per articolo da Wildberries."""
    url = f"https://card.wb.ru/cards/v1/detail?appType=1&curr=rub&nm={article_id}"
    proxies = random.choice(PROXIES)

    try:
        resp = requests.get(url, headers=HEADERS, proxies=proxies, timeout=15)
        resp.raise_for_status()
        data = resp.json()
        product = data["data"]["products"][0]
        return {
            "id": product["id"],
            "name": product["name"],
            "price": product["salePriceU"] / 100,  # prezzo in copechi
        }
    except (requests.RequestException, KeyError, IndexError) as e:
        return {"error": str(e)}

# Scraping di diversi articoli con ritardo
articles = [12345678, 87654321, 11223344]
for article in articles:
    result = get_product_price(article)
    print(result)
    time.sleep(random.uniform(1.5, 3.0))  # Ritardo casuale di 1.5-3 sec
  

Scenario 2: Lavoro con API tramite proxy

Alcune API limitano il numero di richieste da un singolo IP (rate limiting). Distribuire le richieste tra più proxy consente di aggirare questa limitazione:

import requests
import itertools
from typing import Optional

class ProxyAPIClient:
    """Client per lavorare con API tramite rotazione di proxy."""

    def __init__(self, api_key: str, proxy_list: list):
        self.api_key = api_key
        self.proxy_cycle = itertools.cycle(proxy_list)
        self.session = requests.Session()
        self.session.headers.update({
            "Authorization": f"Bearer {api_key}",
            "Content-Type": "application/json",
        })

    def _get_proxy(self) -> dict:
        proxy = next(self.proxy_cycle)
        return {"http": proxy, "https": proxy}

    def get(self, url: str, **kwargs) -> Optional[dict]:
        proxies = self._get_proxy()
        try:
            resp = self.session.get(url, proxies=proxies, timeout=10, **kwargs)
            resp.raise_for_status()
            return resp.json()
        except requests.RequestException as e:
            print(f"Richiesta API fallita: {e}")
            return None

# Utilizzo
proxy_list = [
    "http://user:[email protected]:8080",
    "http://user:[email protected]:8080",
]

client = ProxyAPIClient(api_key="your_api_key", proxy_list=proxy_list)
data = client.get("https://api.example.com/products")
  

Scenario 3: Test di geolocalizzazione

I marketer e gli specialisti SEO controllano spesso come appare un sito da diverse regioni. Con i proxy delle località desiderate, è possibile automatizzare questo processo:

import requests

# Proxy da diverse regioni
regional_proxies = {
    "Mosca":        "http://user:[email protected]:8080",
    "San Pietroburgo": "http://user:[email protected]:8080",
    "Novosibirsk":   "http://user:[email protected]:8080",
    "USA":           "http://user:[email protected]:8080",
}

url = "https://example.com/prices"

for region, proxy_url in regional_proxies.items():
    proxies = {"http": proxy_url, "https": proxy_url}
    try:
        resp = requests.get(url, proxies=proxies, timeout=15)
        print(f"[{region}] Status: {resp.status_code} | "
              f"Dimensione: {len(resp.content)} byte")
    except requests.RequestException as e:
        print(f"[{region}] Errore: {e}")
  

Quale tipo di proxy scegliere per il proprio compito

La scelta del tipo di proxy influisce direttamente sul successo del tuo progetto. Un proxy economico dei data center può funzionare bene per alcuni compiti e fallire completamente per altri. Ecco una guida pratica per la scelta:

Compito Tipo di proxy Perché
Scraping di marketplace (Wildberries, Ozon) Residenziali Appaiono come utenti normali, vengono bannati meno frequentemente
Scraping di dati aperti, notizie Data center Veloci, economici, abbastanza anonimi
Lavoro con API di Facebook, Instagram Mobili I social media si fidano di più degli IP mobili
Test di geolocalizzazione Residenziali con geotargeting Geolocalizzazione precisa, IP reali della regione desiderata
Scraping ad alta intensità (10k+ richieste/ora) Data center (pool) Velocità e costo per grandi volumi
Autenticazione e lavoro con account Residenziali o mobili Meno trigger per i sistemi antifrode

Per compiti in cui è massima l'affidabilità e il rischio di blocco è minimo durante il lavoro con siti protetti, gli sviluppatori scelgono più frequentemente proxy mobili — utilizzano indirizzi IP di veri operatori mobili (MTS, Beeline, MegaFon), che raramente finiscono nelle blacklist.

Checklist per il controllo dei proxy prima dell'uso

  • ✅ Controlla l'IP tramite httpbin.org/ip — è visibile il tuo vero indirizzo?
  • ✅ Controlla la velocità — il tempo di risposta non deve superare 2-3 secondi
  • ✅ Assicurati che il proxy non sia nelle blacklist tramite blocklist.de o ipqualityscore.com
  • ✅ Controlla la geolocalizzazione tramite ipinfo.io — corrisponde alla regione attesa?
  • ✅ Testa sul sito target con una sola richiesta prima di avviare l'intero script
  • ✅ Assicurati che anche il traffico HTTPS passi attraverso il proxy (entrambe le chiavi nel dizionario)

Conclusione

Configurare i proxy in Python requests non è difficile, ma richiede attenzione ai dettagli. I principi principali da ricordare sono: specifica sempre entrambe le chiavi (http e https) nel dizionario dei proxy, utilizza Session per scenari multi-passaggio, gestisci sempre gli errori e i timeout, e memorizza le credenziali nelle variabili d'ambiente, non nel codice.

Per lo scraping industriale con migliaia di richieste al giorno, una lista manuale di proxy non è sufficiente — è necessaria la rotazione. Se stai facendo scraping di marketplace protetti come Wildberries o Ozon, lavori con i social media o testi la geolocalizzazione, ti consigliamo di provare i proxy residenziali — offrono un alto livello di fiducia da parte dei sistemi anti-bot e supportano la rotazione automatica degli IP attraverso un unico endpoint, semplificando notevolmente il codice del tuo script.

```