← Torna al blog

Proxy per contesto in Playwright invece del browser: risparmio di memoria e rotazione IP pulita

Analizziamo perché associare un proxy a BrowserContext in Playwright è più efficace che a un intero browser, con codice, benchmark e modelli di rotazione pronti.

📅21 ottobre 2026

Se stai eseguendo script di parsing o multi-accounting su Playwright e per ogni proxy avvii un'istanza separata del browser, stai sprecando memoria e CPU inutilmente. Playwright può assegnare proxy a livello di BrowserContext, e non all'intero browser, e questo cambia radicalmente l'architettura degli script: un processo del browser, decine di contesti isolati con IP, cookie e fingerprint diversi. In questo articolo, vedremo come funziona, codice in Python e Node.js, e perché è particolarmente importante quando si lavora con proxy residenziali e mobili.

Problema: proxy su browser.launch() — costoso e scomodo

L'approccio classico di molti script su Playwright è il seguente: per ogni proxy viene chiamato chromium.launch({ proxy: {...} }), viene creato un processo del browser separato, funziona, poi si chiude, e si avvia il successivo con un nuovo proxy. Se è necessario elaborare 50 indirizzi IP in parallelo per il parsing di Wildberries o Ozon, ciò significa 50 processi Chromium completi contemporaneamente — ognuno consuma da 150 a 300 MB di RAM solo all'avvio, senza contare le schede e il rendering.

Nella pratica, questo si scontra con un limite già a 15-20 browser paralleli su un normale VPS con 8 GB di memoria. Il server inizia a swapare, gli script falliscono con timeout, parte dei proxy non riesce a lavorare. Il problema non è nei proxy e nemmeno in Playwright — il problema è nell'architettura: ogni avvio del browser porta con sé l'intero motore di rendering, il processo GPU, la rete e decine di thread ausiliari, anche se in realtà hai solo bisogno di un nuovo IP e di una sessione pulita.

Playwright risolve questo problema in modo elegante: i proxy possono essere definiti non all'avvio del browser, ma alla creazione di BrowserContext — una "sandbox" leggera e isolata all'interno dello stesso processo del browser. Un processo Chromium è in grado di mantenere decine di contesti, ognuno con il proprio proxy, i propri cookie e localStorage, senza sovrapporsi l'uno con l'altro.

Browser vs BrowserContext: qual è la differenza

Browser è il processo stesso del motore (Chromium, Firefox o WebKit), che viene avviato una sola volta e vive a lungo. BrowserContext è un ambiente isolato all'interno di questo processo, simile a una finestra privata (incognito), con i propri cookie, cache, autorizzazioni e, cosa importante per noi, le proprie impostazioni di rete, inclusi i proxy.

Se confrontiamo con browser anti-detect come Dolphin Anty o AdsPower, ogni "profilo" è in effetti un contenitore isolato separato con cookie e fingerprint. Playwright consente di costruire una logica simile in modo programmatico: un browser — molti contesti, ognuno come un "profilo" separato con il proprio IP.

Parametro Proxy su Browser Proxy su BrowserContext
Memoria per un IP 150-300 MB (nuovo processo) 15-40 MB (nuovo contesto)
Velocità di cambio IP 2-5 sec (riavvio del browser) 0.1-0.3 sec (nuovo contesto)
Isolamento dei cookie Totale (processi diversi) Totale (i contesti non condividono cookie)
Max. sessioni parallele su 8 GB RAM ~20-25 ~150-200

Proxy per contesto: codice in Python

Di seguito un modello di base: un browser viene avviato una sola volta, e poi per ogni proxy viene creato un contesto separato. Questo è l'API sincrono di Playwright, ma la logica è identica per la versione async.

from playwright.sync_api import sync_playwright

proxies = [
    {"server": "http://proxy1.example.com:8000", "username": "user1", "password": "pass1"},
    {"server": "http://proxy2.example.com:8000", "username": "user2", "password": "pass2"},
    {"server": "http://proxy3.example.com:8000", "username": "user3", "password": "pass3"},
]

with sync_playwright() as p:
    # Il browser viene avviato UNA sola volta, senza proxy
    browser = p.chromium.launch(headless=True)

    for proxy in proxies:
        # Il proxy viene assegnato al contesto, non al browser
        context = browser.new_context(
            proxy={
                "server": proxy["server"],
                "username": proxy["username"],
                "password": proxy["password"],
            },
            user_agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
        )
        page = context.new_page()
        page.goto("https://httpbin.org/ip", timeout=30000)
        print(page.content())

        page.close()
        context.close()  # chiudiamo solo il contesto, il browser continua a vivere

    browser.close()

Il punto chiave è che browser.launch() viene chiamato una sola volta al di fuori del ciclo, mentre browser.new_context() — all'interno del ciclo per i proxy. Per i proxy con autenticazione tramite nome utente e password, Playwright inserisce automaticamente le intestazioni di autenticazione di base a livello di rete, non è necessario configurare nulla di aggiuntivo.

Proxy per contesto: codice in Node.js

La stessa logica in JavaScript utilizzando async/await — spesso applicata in combinazione con framework di parsing su Node.js:

const { chromium } = require('playwright');

const proxies = [
  { server: 'http://proxy1.example.com:8000', username: 'user1', password: 'pass1' },
  { server: 'http://proxy2.example.com:8000', username: 'user2', password: 'pass2' },
];

(async () => {
  const browser = await chromium.launch({ headless: true });

  for (const proxy of proxies) {
    const context = await browser.newContext({
      proxy: {
        server: proxy.server,
        username: proxy.username,
        password: proxy.password,
      },
    });

    const page = await context.newPage();
    await page.goto('https://httpbin.org/ip', { timeout: 30000 });
    console.log(await page.content());

    await page.close();
    await context.close();
  }

  await browser.close();
})();

Per l'elaborazione parallela di decine di proxy, i contesti possono essere creati tramite Promise.all, senza attendere la chiusura del precedente — questo è il principale vantaggio dell'approccio "un browser, molti contesti" rispetto all'avvio di processi separati.

Rotazione pulita dei proxy senza riavviare il browser

"Rotazione pulita" significa che quando si cambia IP non rimangono tracce dalla sessione precedente — né cookie, né cache, né service worker. Durante il riavvio dell'intero browser, questo è garantito automaticamente, ma è costoso in termini di risorse. Lavorando con i contesti, lo stesso risultato si ottiene chiudendo il vecchio contesto e creando un nuovo — l'operazione richiede frazioni di secondo.

async function rotateProxy(browser, proxyList, index) {
  const proxy = proxyList[index % proxyList.length];
  const context = await browser.newContext({ proxy });
  const page = await context.newPage();
  return { context, page };
}

// Utilizziamo così: ad ogni N-esima iterazione cambiamo IP
for (let i = 0; i < 100; i++) {
  if (i % 10 === 0) {
    const { context, page } = await rotateProxy(browser, proxies, i);
    // lavoriamo con una nuova sessione per 10 richieste
  }
}

Questo modello è particolarmente utile quando si esegue il parsing di marketplace: ad esempio, durante la raccolta dei prezzi da Wildberries o Ozon, dove la protezione contro i bot monitora il numero di richieste da un singolo IP in un'unità di tempo. La rotazione a livello di contesto consente di cambiare IP ogni 5-10 richieste, senza perdere prestazioni a causa del riavvio del browser.

Per scenari simili, i proxy residenziali sono molto adatti — forniscono IP di utenti reali, che i marketplace contrassegnano meno frequentemente come sospetti, a differenza degli intervalli chiaramente server.

Confronto di memoria e velocità

Su un VPS di test con 8 GB di RAM e 4 vCPU è stato eseguito un test di due approcci per l'operazione di scraping di 100 pagine con IP diversi. Nel primo caso, per ogni IP veniva avviato un chromium.launch() separato, nel secondo — un browser con la creazione di 100 contesti in sequenza.

Metrica 100 avvii di browser.launch() 100 contesti in 1 browser
Memoria di picco ~6.8 GB ~1.9 GB
Tempo totale di esecuzione 182 sec 97 sec
Numero di sessioni fallite per timeout 7 0

Il risparmio di memoria in questo test è stato di circa il 70%, e il tempo totale di esecuzione è stato ridotto quasi della metà grazie all'assenza di sovraccarichi per l'avvio e la chiusura del processo Chromium ogni volta. Su grandi volumi — migliaia di IP al giorno — la differenza diventa ancora più evidente, e questo influisce direttamente su quanti proxy puoi utilizzare su un singolo server senza aggiornare l'hardware.

Casi pratici: parsing e multi-accounting

Parsing di marketplace. Durante la raccolta dei prezzi da Wildberries, Ozon o Avito, lo stesso browser mantiene aperti decine di contesti, ognuno con un IP unico e il proprio archivio cookie. Questo riduce il rischio di blocco a causa del pattern delle richieste e consente di raccogliere dati più velocemente, senza attendere il riavvio del processo tra IP.

Multi-accounting e farming di account. Per testare campagne pubblicitarie su Facebook Ads o TikTok Ads tramite script Playwright, è logico mantenere ogni account in un contesto separato con il proprio proxy e user-agent — questo simula il comportamento dei browser anti-detect come Multilogin o GoLogin, solo senza la licenza per l'anti-detect stesso, completamente in modo programmatico.

Test pubblicitari geografici. I marketer che devono verificare come appare un creatore in diversi paesi possono utilizzare contesti con proxy diversi per "visitare" i regioni necessarie in una sola sessione del browser, senza aprire manualmente decine di finestre separate.

Per scenari in cui è importante simulare il traffico mobile — ad esempio, verificare la versione mobile di un sito o la pubblicità in TikTok Ads — è consigliabile considerare i proxy mobili, che forniscono IP da veri operatori di telefonia mobile e suscitano meno sospetti nei sistemi anti-frode.

Se l'obiettivo è un parsing rapido e stabile senza necessità di alta anonimato (ad esempio, raccogliere dati pubblici da siti senza una rigorosa protezione anti-bot), i proxy dei data center offrono il miglior rapporto tra velocità e costo su grandi volumi di richieste.

Errori comuni e come evitarli

1. I proxy vengono impostati in launch(), non in new_context(). Questo è l'errore più comune tra i principianti: il proxy specificato all'avvio del browser si applica a tutti i contesti contemporaneamente e non può essere sovrascritto individualmente. Assicurati sempre di passare il proxy a new_context(), se hai bisogno di flessibilità con l'IP.

2. I vecchi contesti non vengono chiusi. Se crei centinaia di contesti e non chiami context.close(), la memoria del browser crescerà linearmente fino a quando il processo non si fermerà per OOM. Chiudi sempre il contesto dopo aver completato il compito per questo IP.

3. Un user-agent per tutti i contesti. Se il proxy cambia, ma il fingerprint del browser rimane lo stesso (user-agent, lingua, fuso orario), i sistemi anti-bot dei marketplace e dei social media possono comunque collegare le sessioni tra loro. Cambia user-agent e viewport insieme al proxy per ogni contesto.

4. Ignorare i timeout dei proxy. I proxy residenziali e mobili a volte rispondono più lentamente rispetto a quelli dei data center a causa della reale infrastruttura di rete. Imposta un timeout ragionevole (20-40 secondi) quando chiami page.goto(), altrimenti lo script considererà il proxy funzionante "morto".

5. Troppi contesti in un solo browser contemporaneamente. Nonostante il risparmio di memoria, la creazione incontrollata di 500+ contesti attivi contemporaneamente si scontrerà comunque con i limiti del processo. Un equilibrio ragionevole è di 30-80 contesti attivi contemporaneamente per un processo del browser, a seconda della quantità di RAM del server.

Conclusione

Assegnare proxy a livello di BrowserContext, e non all'intero browser — è una soluzione architetturale che consente di risparmiare fino al 70% di memoria, accelera la rotazione degli IP di decine di volte e offre un'isolamento pulito dei cookie tra le sessioni senza continui riavvii di Chromium. Per il parsing di marketplace, il testing pubblicitario in diverse regioni e il multi-accounting, questo è un modo diretto per aumentare il numero di sessioni parallele sullo stesso server senza aggiornare l'hardware.

Se stai costruendo uno script su Playwright per raccogliere dati da Wildberries, Ozon o per lavorare con le campagne pubblicitarie di Facebook Ads e TikTok Ads, la qualità stessa del pool di proxy è altrettanto importante quanto l'architettura del codice. Per compiti in cui l'affidabilità dell'IP e la resistenza ai sistemi anti-bot sono critiche, è consigliabile iniziare con proxy residenziali — si abbinano bene all'approccio "un browser, molti contesti" descritto sopra.