Volver al blog

Cómo configurar un proxy para GraphQL API: rotación de IP y eludir limitaciones de tasa con ejemplos de código

Guía completa para configurar un proxy para trabajar con GraphQL API: ejemplos de código, rotación de direcciones IP, eludir limitaciones de tasa y protección contra bloqueos.

📅15 de febrero de 2026
```html

Las API GraphQL están ganando popularidad, pero junto con esto también aumentan las restricciones: rate limiting, bloqueos por IP, filtros geográficos. Si trabajas con grandes volúmenes de datos a través de GraphQL — raspando plataformas de e-commerce, recopilando analíticas de redes sociales o probando API — no puedes prescindir de un proxy. En este artículo, analizaremos cómo configurar correctamente un proxy para solicitudes GraphQL, implementar la rotación de IP y evitar bloqueos.

Mostraremos ejemplos prácticos en Python y Node.js, analizaremos errores comunes y daremos recomendaciones sobre la elección del tipo de proxy para diferentes tareas.

¿Por qué se necesitan proxies para solicitudes GraphQL?

Las API GraphQL se utilizan a menudo para obtener grandes volúmenes de datos en poco tiempo. A diferencia de las API REST, donde los datos están divididos en múltiples endpoints, GraphQL permite solicitar todo lo necesario en una sola consulta. Esto es conveniente, pero crea problemas:

  • Rate limiting — la mayoría de las API públicas de GraphQL limitan la cantidad de solicitudes desde una sola IP (por ejemplo, GitHub API: 5000 solicitudes por hora, Shopify: 2 solicitudes por segundo)
  • Bloqueos de IP — al exceder los límites o por actividad sospechosa, tu IP puede ser bloqueada durante varias horas o para siempre
  • Restricciones geográficas — algunas API solo están disponibles desde ciertos países (por ejemplo, marketplaces locales o servicios regionales)
  • Protección contra raspado — los servidores rastrean patrones de solicitudes y bloquean IP sospechosas

Los proxies resuelven estos problemas, permitiendo distribuir las solicitudes a través de múltiples direcciones IP, simular solicitudes desde diferentes regiones y evadir bloqueos. Esto es especialmente importante al trabajar con:

  • Raspado de datos de plataformas de e-commerce (Shopify, WooCommerce GraphQL API)
  • Recopilación de analíticas de redes sociales (Facebook Graph API, Instagram API)
  • Monitoreo de precios y disponibilidad de productos
  • Pruebas de API desde diferentes ubicaciones geográficas
  • Automatización de la recopilación de datos para análisis e investigaciones

¿Qué tipo de proxy elegir para trabajar con GraphQL?

La elección del tipo de proxy depende de la tarea y los requisitos de la API. Analicemos tres tipos principales y su aplicación para solicitudes GraphQL:

Tipo de proxy Velocidad Anonimato Cuándo usar
Proxies de centros de datos Muy alta (10-50 ms) Media Raspado de API públicas, pruebas, alta velocidad más importante que el anonimato
Proxies residenciales Media (100-300 ms) Muy alta Trabajo con API protegidas (Shopify, Facebook), evasión de filtros estrictos
Proxies móviles Media (150-400 ms) Máxima Instagram API, TikTok API, aplicaciones móviles con GraphQL

Recomendaciones para la elección:

  • Para API públicas (GitHub, OpenWeather) — son suficientes los proxies de centros de datos, son rápidos y económicos
  • Para e-commerce (Shopify, WooCommerce) — proxies residenciales, ya que estas plataformas filtran activamente los centros de datos
  • Para redes sociales (Facebook Graph API, Instagram) — proxies móviles o residenciales son obligatorios
  • Para raspado masivo — combinación: centros de datos para tráfico principal + residenciales para rotación en caso de bloqueos

Configuración de proxy en Python para GraphQL (requests, httpx, gql)

Python es uno de los lenguajes más populares para trabajar con API. Veamos tres formas de configurar proxies para solicitudes GraphQL.

Opción 1: Biblioteca requests (cliente HTTP simple)

La forma más sencilla es usar la biblioteca estándar requests. Es adecuada para consultas GraphQL básicas sin lógica compleja.

import requests
import json

# Configuración del proxy
proxies = {
    'http': 'http://username:password@proxy.example.com:8080',
    'https': 'http://username:password@proxy.example.com:8080'
}

# Consulta GraphQL
query = """
query {
  products(first: 10) {
    edges {
      node {
        id
        title
        priceRange {
          minVariantPrice {
            amount
          }
        }
      }
    }
  }
}
"""

# Envío de la consulta a través del 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))

Opción 2: Biblioteca httpx (consultas asíncronas)

Si necesitas enviar muchas solicitudes en paralelo, utiliza httpx con soporte para 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)'
    }
    
    # Configuración del proxy para 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()

# Uso
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))

Opción 3: Biblioteca gql (cliente especializado en GraphQL)

Para un trabajo avanzado con GraphQL, utiliza la biblioteca gql — soporta validación de esquemas, caché y un manejo conveniente de las consultas:

from gql import gql, Client
from gql.transport.requests import RequestsHTTPTransport

# Configuración del transporte 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
)

# Creación del cliente
client = Client(transport=transport, fetch_schema_from_transport=True)

# Consulta GraphQL
query = gql("""
    query GetProducts($first: Int!) {
        products(first: $first) {
            edges {
                node {
                    id
                    title
                    variants(first: 1) {
                        edges {
                            node {
                                price
                            }
                        }
                    }
                }
            }
        }
    }
""")

# Ejecución de la consulta
result = client.execute(query, variable_values={"first": 20})
print(result)

Configuración de proxy en Node.js para GraphQL (axios, apollo-client)

Node.js también se utiliza ampliamente para trabajar con API GraphQL. Analicemos dos enfoques principales.

Opción 1: Axios con proxy

Cliente HTTP simple y flexible con soporte para proxy:

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

// Configuración del proxy
const proxyUrl = 'http://username:password@proxy.example.com:8080';
const httpsAgent = new HttpsProxyAgent(proxyUrl);

// Consulta GraphQL
const query = `
  query {
    products(first: 10) {
      edges {
        node {
          id
          title
          priceRange {
            minVariantPrice {
              amount
            }
          }
        }
      }
    }
  }
`;

// Envío de la consulta
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('Error:', error.message);
});

Opción 2: Apollo Client con proxy

Apollo Client es el cliente GraphQL más popular para Node.js y el navegador. Configuración de proxy a través de fetch personalizado:

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 personalizado con proxy
const customFetch = (uri, options) => {
  return fetch(uri, {
    ...options,
    agent: agent
  });
};

// Creación del Apollo Client
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()
});

// Consulta GraphQL
const GET_REPOS = gql`
  query GetRepositories($login: String!) {
    user(login: $login) {
      repositories(first: 5) {
        nodes {
          name
          stargazerCount
        }
      }
    }
  }
`;

// Ejecución de la consulta
client.query({
  query: GET_REPOS,
  variables: { login: 'facebook' }
})
.then(result => {
  console.log(JSON.stringify(result.data, null, 2));
})
.catch(error => {
  console.error('Error:', error);
});

Implementación de rotación de proxies para evadir rate limiting

La rotación de proxies es una técnica clave para evadir las restricciones de la API. En lugar de enviar todas las solicitudes desde una sola IP, las distribuyes entre múltiples proxies. Esto permite evadir el rate limiting y evitar bloqueos.

Rotación simple en Python

Implementación básica de rotación con cambio cíclico de proxies:

import requests
import itertools
import time

# Lista de proxies
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',
]

# Creamos un iterador infinito
proxy_pool = itertools.cycle(PROXY_LIST)

def make_graphql_request(query):
    """Enviar una solicitud GraphQL con rotación de proxies"""
    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"Error con el proxy {proxy}: {e}")
        # Cambiamos al siguiente proxy
        return make_graphql_request(query)

# Ejemplo de uso
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 entre solicitudes

Rotación inteligente con seguimiento de errores

Una versión más avanzada que rastrea proxies no funcionales y los excluye automáticamente del grupo:

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):
        """Obtener un proxy activo aleatorio"""
        if not self.active_proxies:
            raise Exception("¡Todos los proxies están inactivos!")
        return random.choice(self.active_proxies)
    
    def mark_failure(self, proxy):
        """Marcar un intento fallido"""
        self.failures[proxy] += 1
        if self.failures[proxy] >= self.max_failures:
            print(f"Proxy {proxy} excluido del grupo (límite de errores excedido)")
            if proxy in self.active_proxies:
                self.active_proxies.remove(proxy)
    
    def mark_success(self, proxy):
        """Restablecer el contador de errores en caso de éxito"""
        self.failures[proxy] = 0

# Inicialización
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):
    """Solicitud GraphQL con reintentos automáticos"""
    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()
            
            # Éxito — restablecemos el contador de errores
            rotator.mark_success(proxy)
            return response.json()
            
        except Exception as e:
            print(f"Intento {attempt + 1}/{max_retries} con {proxy} fallido: {e}")
            rotator.mark_failure(proxy)
            time.sleep(2)  # Pausa antes del reintento
    
    raise Exception("No se pudo realizar la solicitud después de todos los intentos")

# Uso
query = 'query { products(first: 10) { edges { node { id title } } } }'
result = graphql_request_with_retry(query)
print(result)

Configuración de encabezados y User-Agent para solicitudes GraphQL

Los encabezados HTTP correctos son críticos para el éxito al trabajar con API GraphQL a través de proxies. Muchas API verifican no solo la IP, sino también los encabezados de la solicitud.

Encabezados obligatorios para GraphQL

headers = {
    # Tipo de contenido — siempre application/json para GraphQL
    'Content-Type': 'application/json',
    
    # Autorización (depende de la API)
    'Authorization': 'Bearer YOUR_ACCESS_TOKEN',
    # o
    'X-Shopify-Storefront-Access-Token': 'token_here',
    
    # User-Agent — simulamos un navegador real
    '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 — indicamos que aceptamos JSON
    'Accept': 'application/json',
    
    # Accept-Language — idioma del usuario
    'Accept-Language': 'en-US,en;q=0.9',
    
    # Accept-Encoding — soporte para compresión
    'Accept-Encoding': 'gzip, deflate, br',
    
    # Referer — de dónde proviene la solicitud (opcional)
    'Referer': 'https://example.com/',
    
    # Origin — para solicitudes CORS
    'Origin': 'https://example.com'
}

Rotación de User-Agent

Para mayor anonimato, se recomienda rotar el User-Agent junto con el 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):
    """Generación de encabezados aleatorios"""
    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'
    }

Manejo de errores y reintentos a través de proxies

Al trabajar con proxies, los errores son inevitables: timeouts, proxies no disponibles, bloqueos. Es importante manejar correctamente estas situaciones e implementar un mecanismo de reintentos.

Errores típicos de GraphQL a través de proxies

  • Timeouts — el proxy es lento o está sobrecargado (aumenta el timeout a 30-60 segundos)
  • HTTP 407 Proxy Authentication Required — credenciales de proxy incorrectas
  • HTTP 429 Too Many Requests — se ha excedido el límite de rate limit (se necesita rotación de proxies)
  • HTTP 403 Forbidden — IP del proxy bloqueada (cambia a proxies residenciales)
  • Connection refused — proxy no disponible (exclúyelo del grupo)

Manejo avanzado de errores

import requests
import time
from requests.exceptions import ProxyError, Timeout, ConnectionError

def graphql_request_robust(query, proxy, max_retries=3, backoff=2):
    """
    Solicitud GraphQL robusta con manejo de todos los tipos de errores
    
    Args:
        query: Consulta GraphQL
        proxy: URL del proxy
        max_retries: máximo de intentos
        backoff: multiplicador de retraso entre intentos
    """
    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
            )
            
            # Verificación de rate limiting
            if response.status_code == 429:
                retry_after = int(response.headers.get('Retry-After', 60))
                print(f"¡Rate limit! Esperando {retry_after} segundos...")
                time.sleep(retry_after)
                continue
            
            # Verificación de bloqueo de IP
            if response.status_code == 403:
                print(f"¡IP {proxy} bloqueada! Se necesita otro proxy.")
                raise Exception("IP bloqueada")
            
            # Verificación de errores de autorización del proxy
            if response.status_code == 407:
                print(f"Error de autorización del proxy {proxy}")
                raise Exception("Error de autenticación del proxy")
            
            response.raise_for_status()
            
            # Verificación de errores de GraphQL
            data = response.json()
            if 'errors' in data:
                print(f"Errores de GraphQL: {data['errors']}")
                # Algunos errores se pueden reintentar, otros no
                if is_retryable_graphql_error(data['errors']):
                    time.sleep(backoff * (attempt + 1))
                    continue
                else:
                    raise Exception(f"Error de GraphQL: {data['errors']}")
            
            return data
            
        except (ProxyError, ConnectionError) as e:
            print(f"Intento {attempt + 1}: Proxy no disponible - {e}")
            time.sleep(backoff * (attempt + 1))
            
        except Timeout as e:
            print(f"Intento {attempt + 1}: Timeout - {e}")
            time.sleep(backoff * (attempt + 1))
            
        except requests.exceptions.HTTPError as e:
            print(f"Intento {attempt + 1}: Error HTTP - {e}")
            if attempt < max_retries - 1:
                time.sleep(backoff * (attempt + 1))
            else:
                raise
    
    raise Exception(f"No se pudo realizar la solicitud después de {max_retries} intentos")

def is_retryable_graphql_error(errors):
    """Determina si se puede reintentar la solicitud en caso de error de GraphQL"""
    retryable_codes = ['THROTTLED', 'INTERNAL_ERROR', 'TIMEOUT']
    for error in errors:
        if error.get('extensions', {}).get('code') in retryable_codes:
            return True
    return False

Mejores prácticas para trabajar con GraphQL a través de proxies

Resumamos y proporcionemos recomendaciones para un trabajo efectivo con API GraphQL a través de proxies:

✓ Optimización de consultas

  • Solicita solo los campos necesarios — GraphQL permite especificar exactamente lo que necesitas
  • Utiliza paginación en lugar de solicitar todos los datos de una vez
  • Agrupa consultas relacionadas en una sola (GraphQL admite múltiples consultas)
  • Cachéa resultados en el lado del cliente para reducir la cantidad de solicitudes

✓ Gestión de proxies

  • Utiliza un grupo de al menos 5-10 proxies para rotación
  • Verifica regularmente la operatividad de los proxies (health check)
  • Excluye automáticamente proxies no funcionales del grupo
  • Para tareas críticas, mantén proxies de reserva de otro tipo

✓ Cumplimiento de límites

  • Estudia la documentación de la API — allí se indican los límites exactos
  • Agrega retrasos entre solicitudes (1-2 segundos como mínimo)
  • Rastrea los encabezados X-RateLimit-Remaining y X-RateLimit-Reset
  • Al recibir un error 429, aumenta el retraso exponencialmente

✓ Seguridad y anonimato

  • Siempre utiliza proxies HTTPS para proteger los tokens de autorización
  • Rota el User-Agent junto con el proxy
  • No almacenes tokens en el código — utiliza variables de entorno
  • Registra solo la información mínima necesaria

Arquitectura recomendada para proyectos a gran escala

Si trabajas con grandes volúmenes de datos, recomendamos la siguiente arquitectura:

  1. Cola de tareas (Redis, RabbitMQ) — para distribuir solicitudes entre trabajadores
  2. Piscina de trabajadores — cada trabajador utiliza su propio proxy
  3. Gestor de proxies — rastrea el estado de los proxies y los distribuye entre los trabajadores
  4. Base de datos — para almacenar resultados y estado de tareas
  5. Monitoreo — seguimiento de errores, velocidad, uso de proxies

Conclusión

Trabajar con API GraphQL a través de proxies no es solo agregar el parámetro proxies en la solicitud. Para un funcionamiento confiable y efectivo, es necesario implementar la rotación de proxies, un manejo adecuado de errores, configurar encabezados y cumplir con los límites de la API. Hemos revisado ejemplos prácticos en Python y Node.js que puedes utilizar de inmediato en tus proyectos.

Conclusiones clave: utiliza proxies residenciales para API protegidas (Shopify, Facebook), proxies de centros de datos para API públicas y raspado masivo, implementa rotación automática excluyendo proxies no funcionales, agrega retrasos y maneja todos los tipos de errores. Esto permitirá trabajar de manera estable con cualquier API GraphQL sin bloqueos.

Si planeas trabajar con API GraphQL en producción, recomendamos utilizar proxies residenciales — ofrecen la máxima estabilidad y el mínimo riesgo de bloqueos. Para pruebas y desarrollo, son adecuados los proxies de centros de datos — son más rápidos y económicos.

```