Le API GraphQL stanno diventando sempre più popolari, ma con esse crescono anche le limitazioni: rate limiting, blocchi IP, filtri geografici. Se lavori con grandi volumi di dati tramite GraphQL — estraendo dati da piattaforme di e-commerce, raccogliendo analisi dai social media o testando API — non puoi fare a meno dei proxy. In questo articolo vedremo come configurare correttamente un proxy per le richieste GraphQL, implementare la rotazione IP e evitare i blocchi.
Mostreremo esempi pratici in Python e Node.js, analizzeremo errori comuni e daremo consigli sulla scelta del tipo di proxy per diverse esigenze.
Perché sono necessari i proxy per le richieste GraphQL
Le API GraphQL vengono spesso utilizzate per ottenere grandi volumi di dati in breve tempo. A differenza delle API REST, dove i dati sono suddivisi in molti endpoint, GraphQL consente di richiedere tutto il necessario con una sola richiesta. Questo è comodo, ma crea problemi:
- Rate limiting — la maggior parte delle API GraphQL pubbliche limita il numero di richieste da un singolo IP (ad esempio, GitHub API: 5000 richieste all'ora, Shopify: 2 richieste al secondo)
- Blocco IP — superando i limiti o in caso di attività sospette, il tuo IP può essere bloccato per alcune ore o per sempre
- Limitazioni geografiche — alcune API sono disponibili solo da determinati paesi (ad esempio, marketplace locali o servizi regionali)
- Protezione contro il parsing — i server monitorano i modelli di richiesta e bloccano IP sospetti
I proxy risolvono questi problemi, consentendo di distribuire le richieste tramite molti indirizzi IP, simulare richieste da diverse regioni e bypassare i blocchi. Questo è particolarmente importante quando si lavora con:
- Estrazione di dati da piattaforme di e-commerce (Shopify, WooCommerce GraphQL API)
- Raccolta di analisi dai social media (Facebook Graph API, Instagram API)
- Monitoraggio dei prezzi e disponibilità dei prodotti
- Test di API da diverse località geografiche
- Automazione della raccolta di dati per analisi e ricerche
Quale tipo di proxy scegliere per lavorare con GraphQL
La scelta del tipo di proxy dipende dal compito e dai requisiti dell'API. Analizziamo tre tipi principali e il loro utilizzo per le richieste GraphQL:
| Tipo di proxy | Velocità | Anonimato | Quando utilizzare |
|---|---|---|---|
| Proxy di data center | Molto alta (10-50 ms) | Media | Estrazione da API pubbliche, test, alta velocità più importante dell'anonimato |
| Proxy residenziali | Media (100-300 ms) | Molto alta | Lavorare con API protette (Shopify, Facebook), bypassare filtri rigorosi |
| Proxy mobili | Media (150-400 ms) | Massima | Instagram API, TikTok API, applicazioni mobili con GraphQL |
Raccomandazioni per la scelta:
- Per API pubbliche (GitHub, OpenWeather) — basta un proxy di data center, sono veloci ed economici
- Per e-commerce (Shopify, WooCommerce) — proxy residenziali, poiché queste piattaforme filtrano attivamente i data center
- Per social media (Facebook Graph API, Instagram) — proxy mobili o residenziali sono obbligatori
- Per estrazioni di massa — combinazione: data center per il traffico principale + residenziali per la rotazione in caso di blocchi
Configurazione del proxy in Python per GraphQL (requests, httpx, gql)
Python è uno dei linguaggi più popolari per lavorare con API. Esaminiamo tre modi per configurare un proxy per le richieste GraphQL.
Opzione 1: Libreria requests (client HTTP semplice)
Il modo più semplice è utilizzare la libreria standard requests. Adatta per richieste GraphQL di base senza logica complessa.
import requests
import json
# Configurazione del proxy
proxies = {
'http': 'http://username:password@proxy.example.com:8080',
'https': 'http://username:password@proxy.example.com:8080'
}
# Richiesta GraphQL
query = """
query {
products(first: 10) {
edges {
node {
id
title
priceRange {
minVariantPrice {
amount
}
}
}
}
}
}
"""
# Invio della richiesta tramite proxy
url = "https://your-shop.myshopify.com/api/2024-01/graphql.json"
headers = {
'Content-Type': 'application/json',
'X-Shopify-Storefront-Access-Token': 'your_token_here',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
}
response = requests.post(
url,
json={'query': query},
headers=headers,
proxies=proxies,
timeout=30
)
data = response.json()
print(json.dumps(data, indent=2))
Opzione 2: Libreria httpx (richieste asincrone)
Se è necessario inviare molte richieste in parallelo, utilizza httpx con supporto per async/await:
import httpx
import asyncio
import json
async def fetch_graphql(query, proxy_url):
url = "https://api.example.com/graphql"
headers = {
'Content-Type': 'application/json',
'Authorization': 'Bearer YOUR_TOKEN',
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)'
}
# Configurazione del proxy per httpx
proxies = {
"http://": proxy_url,
"https://": proxy_url
}
async with httpx.AsyncClient(proxies=proxies, timeout=30.0) as client:
response = await client.post(
url,
json={'query': query},
headers=headers
)
return response.json()
# Utilizzo
query = """
query {
viewer {
login
repositories(first: 5) {
nodes {
name
stargazerCount
}
}
}
}
"""
proxy = "http://user:pass@proxy.example.com:8080"
result = asyncio.run(fetch_graphql(query, proxy))
print(json.dumps(result, indent=2))
Opzione 3: Libreria gql (client GraphQL specializzato)
Per un lavoro avanzato con GraphQL utilizza la libreria gql — supporta la validazione degli schemi, la memorizzazione nella cache e un lavoro comodo con le richieste:
from gql import gql, Client
from gql.transport.requests import RequestsHTTPTransport
# Configurazione del trasporto con proxy
transport = RequestsHTTPTransport(
url='https://api.example.com/graphql',
headers={
'Authorization': 'Bearer YOUR_TOKEN',
'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64)'
},
proxies={
'http': 'http://user:pass@proxy.example.com:8080',
'https': 'http://user:pass@proxy.example.com:8080'
},
timeout=30
)
# Creazione del client
client = Client(transport=transport, fetch_schema_from_transport=True)
# Richiesta GraphQL
query = gql("""
query GetProducts($first: Int!) {
products(first: $first) {
edges {
node {
id
title
variants(first: 1) {
edges {
node {
price
}
}
}
}
}
}
}
""")
# Esecuzione della richiesta
result = client.execute(query, variable_values={"first": 20})
print(result)
Configurazione del proxy in Node.js per GraphQL (axios, apollo-client)
Node.js è anche ampiamente utilizzato per lavorare con le API GraphQL. Esaminiamo due approcci principali.
Opzione 1: Axios con proxy
Client HTTP semplice e flessibile con supporto per proxy:
const axios = require('axios');
const HttpsProxyAgent = require('https-proxy-agent');
// Configurazione del proxy
const proxyUrl = 'http://username:password@proxy.example.com:8080';
const httpsAgent = new HttpsProxyAgent(proxyUrl);
// Richiesta GraphQL
const query = `
query {
products(first: 10) {
edges {
node {
id
title
priceRange {
minVariantPrice {
amount
}
}
}
}
}
}
`;
// Invio della richiesta
axios.post('https://your-shop.myshopify.com/api/2024-01/graphql.json',
{ query },
{
headers: {
'Content-Type': 'application/json',
'X-Shopify-Storefront-Access-Token': 'your_token_here',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)'
},
httpsAgent: httpsAgent,
timeout: 30000
}
)
.then(response => {
console.log(JSON.stringify(response.data, null, 2));
})
.catch(error => {
console.error('Errore:', error.message);
});
Opzione 2: Apollo Client con proxy
Apollo Client è il client GraphQL più popolare per Node.js e il browser. Configurazione del proxy tramite fetch personalizzato:
const { ApolloClient, InMemoryCache, HttpLink, gql } = require('@apollo/client');
const fetch = require('cross-fetch');
const HttpsProxyAgent = require('https-proxy-agent');
// Agente proxy
const proxyUrl = 'http://user:pass@proxy.example.com:8080';
const agent = new HttpsProxyAgent(proxyUrl);
// Fetch personalizzato con proxy
const customFetch = (uri, options) => {
return fetch(uri, {
...options,
agent: agent
});
};
// Creazione del client Apollo
const client = new ApolloClient({
link: new HttpLink({
uri: 'https://api.example.com/graphql',
fetch: customFetch,
headers: {
'Authorization': 'Bearer YOUR_TOKEN',
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)'
}
}),
cache: new InMemoryCache()
});
// Richiesta GraphQL
const GET_REPOS = gql`
query GetRepositories($login: String!) {
user(login: $login) {
repositories(first: 5) {
nodes {
name
stargazerCount
}
}
}
}
`;
// Esecuzione della richiesta
client.query({
query: GET_REPOS,
variables: { login: 'facebook' }
})
.then(result => {
console.log(JSON.stringify(result.data, null, 2));
})
.catch(error => {
console.error('Errore:', error);
});
Implementazione della rotazione del proxy per bypassare il rate limiting
La rotazione dei proxy è una tecnica chiave per bypassare le limitazioni delle API. Invece di inviare tutte le richieste da un singolo IP, le distribuisci tra molti proxy. Questo consente di bypassare il rate limiting e di evitare i blocchi.
Rotazione semplice in Python
Implementazione di base della rotazione con cambio ciclico dei proxy:
import requests
import itertools
import time
# Lista dei proxy
PROXY_LIST = [
'http://user:pass@proxy1.example.com:8080',
'http://user:pass@proxy2.example.com:8080',
'http://user:pass@proxy3.example.com:8080',
'http://user:pass@proxy4.example.com:8080',
]
# Creiamo un iteratore infinito
proxy_pool = itertools.cycle(PROXY_LIST)
def make_graphql_request(query):
"""Invio di una richiesta GraphQL con rotazione dei proxy"""
proxy = next(proxy_pool)
proxies = {'http': proxy, 'https': proxy}
url = "https://api.example.com/graphql"
headers = {
'Content-Type': 'application/json',
'Authorization': 'Bearer YOUR_TOKEN',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)'
}
try:
response = requests.post(
url,
json={'query': query},
headers=headers,
proxies=proxies,
timeout=30
)
response.raise_for_status()
return response.json()
except requests.exceptions.RequestException as e:
print(f"Errore con il proxy {proxy}: {e}")
# Passiamo al prossimo proxy
return make_graphql_request(query)
# Esempio di utilizzo
queries = [
'query { products(first: 10) { edges { node { id title } } } }',
'query { collections(first: 5) { edges { node { id title } } } }',
'query { shop { name email } }'
]
for query in queries:
result = make_graphql_request(query)
print(result)
time.sleep(1) # Pausa tra le richieste
Rotazione intelligente con monitoraggio degli errori
Versione più avanzata che tiene traccia dei proxy non funzionanti ed esclude automaticamente quelli dal pool:
import requests
import random
from collections import defaultdict
import time
class ProxyRotator:
def __init__(self, proxy_list, max_failures=3):
self.proxy_list = proxy_list.copy()
self.max_failures = max_failures
self.failures = defaultdict(int)
self.active_proxies = proxy_list.copy()
def get_proxy(self):
"""Ottenere un proxy attivo casuale"""
if not self.active_proxies:
raise Exception("Tutti i proxy sono non disponibili!")
return random.choice(self.active_proxies)
def mark_failure(self, proxy):
"""Contrassegnare un tentativo fallito"""
self.failures[proxy] += 1
if self.failures[proxy] >= self.max_failures:
print(f"Proxy {proxy} escluso dal pool (superato il limite di errori)")
if proxy in self.active_proxies:
self.active_proxies.remove(proxy)
def mark_success(self, proxy):
"""Reimpostare il contatore degli errori in caso di successo"""
self.failures[proxy] = 0
# Inizializzazione
proxies = [
'http://user:pass@proxy1.example.com:8080',
'http://user:pass@proxy2.example.com:8080',
'http://user:pass@proxy3.example.com:8080',
]
rotator = ProxyRotator(proxies)
def graphql_request_with_retry(query, max_retries=3):
"""Richiesta GraphQL con tentativi automatici"""
for attempt in range(max_retries):
proxy = rotator.get_proxy()
proxies_dict = {'http': proxy, 'https': proxy}
try:
response = requests.post(
'https://api.example.com/graphql',
json={'query': query},
headers={
'Content-Type': 'application/json',
'Authorization': 'Bearer TOKEN',
'User-Agent': 'Mozilla/5.0'
},
proxies=proxies_dict,
timeout=30
)
response.raise_for_status()
# Successo — reimpostiamo il contatore degli errori
rotator.mark_success(proxy)
return response.json()
except Exception as e:
print(f"Tentativo {attempt + 1}/{max_retries} con {proxy} fallito: {e}")
rotator.mark_failure(proxy)
time.sleep(2) # Pausa prima del ripristino
raise Exception("Impossibile eseguire la richiesta dopo tutti i tentativi")
# Utilizzo
query = 'query { products(first: 10) { edges { node { id title } } } }'
result = graphql_request_with_retry(query)
print(result)
Configurazione degli header e User-Agent per le richieste GraphQL
Gli header HTTP corretti sono fondamentali per il successo del lavoro con le API GraphQL tramite proxy. Molte API controllano non solo l'IP, ma anche gli header della richiesta.
Header obbligatori per GraphQL
headers = {
# Tipo di contenuto — sempre application/json per GraphQL
'Content-Type': 'application/json',
# Autenticazione (dipende dall'API)
'Authorization': 'Bearer YOUR_ACCESS_TOKEN',
# oppure
'X-Shopify-Storefront-Access-Token': 'token_here',
# User-Agent — simuliamo un vero browser
'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 — indichiamo che accettiamo JSON
'Accept': 'application/json',
# Accept-Language — lingua dell'utente
'Accept-Language': 'en-US,en;q=0.9',
# Accept-Encoding — supporto per la compressione
'Accept-Encoding': 'gzip, deflate, br',
# Referer — da dove è arrivata la richiesta (opzionale)
'Referer': 'https://example.com/',
# Origin — per richieste CORS
'Origin': 'https://example.com'
}
Rotazione User-Agent
Per una maggiore anonimato è consigliabile ruotare il User-Agent insieme ai proxy:
import random
USER_AGENTS = [
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:121.0) Gecko/20100101 Firefox/121.0',
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.1 Safari/605.1.15'
]
def get_random_headers(token):
"""Generazione di header casuali"""
return {
'Content-Type': 'application/json',
'Authorization': f'Bearer {token}',
'User-Agent': random.choice(USER_AGENTS),
'Accept': 'application/json',
'Accept-Language': 'en-US,en;q=0.9',
'Accept-Encoding': 'gzip, deflate, br'
}
Gestione degli errori e tentativi ripetuti tramite proxy
Quando si lavora con i proxy, gli errori sono inevitabili: timeout, proxy non disponibili, blocchi. È importante gestire correttamente queste situazioni e implementare un meccanismo di tentativi ripetuti.
Errori comuni di GraphQL tramite proxy
- Timeout — il proxy è lento o sovraccarico (aumenta il timeout a 30-60 secondi)
- HTTP 407 Proxy Authentication Required — credenziali proxy errate
- HTTP 429 Too Many Requests — superato il rate limit (è necessaria la rotazione dei proxy)
- HTTP 403 Forbidden — IP del proxy bloccato (cambia il tipo di proxy in residenziali)
- Connection refused — proxy non disponibile (escludilo dal pool)
Gestione avanzata degli errori
import requests
import time
from requests.exceptions import ProxyError, Timeout, ConnectionError
def graphql_request_robust(query, proxy, max_retries=3, backoff=2):
"""
Richiesta GraphQL robusta con gestione di tutti i tipi di errori
Args:
query: Richiesta GraphQL
proxy: URL del proxy
max_retries: numero massimo di tentativi
backoff: moltiplicatore di ritardo tra i tentativi
"""
url = "https://api.example.com/graphql"
headers = {
'Content-Type': 'application/json',
'Authorization': 'Bearer TOKEN',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)'
}
proxies = {'http': proxy, 'https': proxy}
for attempt in range(max_retries):
try:
response = requests.post(
url,
json={'query': query},
headers=headers,
proxies=proxies,
timeout=30
)
# Controllo per il rate limiting
if response.status_code == 429:
retry_after = int(response.headers.get('Retry-After', 60))
print(f"Rate limit! Attesa di {retry_after} secondi...")
time.sleep(retry_after)
continue
# Controllo per il blocco IP
if response.status_code == 403:
print(f"IP {proxy} bloccato! Necessita di un altro proxy.")
raise Exception("IP bloccato")
# Controllo per errori di autenticazione del proxy
if response.status_code == 407:
print(f"Errore di autenticazione del proxy {proxy}")
raise Exception("Autenticazione proxy fallita")
response.raise_for_status()
# Controllo per errori GraphQL
data = response.json()
if 'errors' in data:
print(f"Errori GraphQL: {data['errors']}")
# Alcuni errori possono essere ripetuti, altri no
if is_retryable_graphql_error(data['errors']):
time.sleep(backoff * (attempt + 1))
continue
else:
raise Exception(f"Errore GraphQL: {data['errors']}")
return data
except (ProxyError, ConnectionError) as e:
print(f"Tentativo {attempt + 1}: Proxy non disponibile - {e}")
time.sleep(backoff * (attempt + 1))
except Timeout as e:
print(f"Tentativo {attempt + 1}: Timeout - {e}")
time.sleep(backoff * (attempt + 1))
except requests.exceptions.HTTPError as e:
print(f"Tentativo {attempt + 1}: Errore HTTP - {e}")
if attempt < max_retries - 1:
time.sleep(backoff * (attempt + 1))
else:
raise
raise Exception(f"Impossibile eseguire la richiesta dopo {max_retries} tentativi")
def is_retryable_graphql_error(errors):
"""Determina se è possibile ripetere la richiesta in caso di errore GraphQL"""
retryable_codes = ['THROTTLED', 'INTERNAL_ERROR', 'TIMEOUT']
for error in errors:
if error.get('extensions', {}).get('code') in retryable_codes:
return True
return False
Migliori pratiche per lavorare con GraphQL tramite proxy
Riassumiamo e diamo raccomandazioni per un lavoro efficace con le API GraphQL tramite proxy:
✓ Ottimizzazione delle richieste
- Richiedi solo i campi necessari — GraphQL consente di specificare esattamente ciò di cui hai bisogno
- Utilizza la paginazione invece di richiedere tutti i dati contemporaneamente
- Raggruppa richieste correlate in una sola (GraphQL supporta richieste multiple)
- Memorizza i risultati sul lato client per ridurre il numero di richieste
✓ Gestione dei proxy
- Utilizza un pool di almeno 5-10 proxy per la rotazione
- Controlla regolarmente la funzionalità dei proxy (health check)
- Escludi automaticamente i proxy non funzionanti dal pool
- Per compiti critici, mantieni proxy di riserva di un altro tipo
✓ Rispetto dei limiti
- Studia la documentazione API — lì sono indicati i limiti esatti
- Aggiungi ritardi tra le richieste (1-2 secondi almeno)
- Monitora gli header X-RateLimit-Remaining e X-RateLimit-Reset
- In caso di errore 429, aumenta il ritardo in modo esponenziale
✓ Sicurezza e anonimato
- Utilizza sempre proxy HTTPS per proteggere i token di autorizzazione
- Ruota il User-Agent insieme ai proxy
- Non memorizzare i token nel codice — utilizza variabili d'ambiente
- Registra solo le informazioni minime necessarie
Architettura consigliata per progetti su larga scala
Se lavori con grandi volumi di dati, ti consigliamo la seguente architettura:
- Queue di lavoro (Redis, RabbitMQ) — per distribuire le richieste tra i worker
- Pool di worker — ogni worker utilizza il proprio proxy
- Manager dei proxy — monitora lo stato dei proxy e li distribuisce tra i worker
- Database — per memorizzare i risultati e lo stato delle richieste
- Monitoraggio — monitoraggio degli errori, velocità, utilizzo dei proxy
Conclusione
Lavorare con le API GraphQL tramite proxy non è solo aggiungere il parametro proxies nella richiesta. Per un lavoro affidabile ed efficace è necessario implementare la rotazione dei proxy, una corretta gestione degli errori, configurare gli header e rispettare i limiti delle API. Abbiamo esaminato esempi pratici in Python e Node.js che possono essere utilizzati immediatamente nei tuoi progetti.
Le principali conclusioni: utilizza proxy residenziali per API protette (Shopify, Facebook), data center per API pubbliche e per l'estrazione di massa, implementa una rotazione automatica escludendo i proxy non funzionanti, aggiungi ritardi e gestisci tutti i tipi di errori. Questo ti permetterà di lavorare stabilmente con qualsiasi API GraphQL senza blocchi.
Se prevedi di lavorare con API GraphQL in produzione, ti consigliamo di utilizzare proxy residenziali — offrono la massima stabilità e il minimo rischio di blocchi. Per test e sviluppo, puoi utilizzare proxy di data center — sono più veloci ed economici.