Configuración de proxy en Scrapy, usar IP diferente por solicitud con meta proxy
Esta guía explica cómo conectar el proxy HTTP de Socks5Proxy con meta proxy en Scrapy, cómo rotar la lista recibida de la API por solicitud con un middleware de descarga, y cómo configurar la velocidad según el sitio objetivo.
¿Cómo maneja Scrapy los proxies?
Scrapy tiene HttpProxyMiddleware activado por defecto. Agrega la dirección proxy al diccionario meta de la solicitud con la clave 'proxy', y el middleware convertirá usuario/contraseña en headers Proxy-Authorization. Las direcciones HTTPS usan túnel CONNECT.
El manejador de descargas por defecto de Scrapy soporta HTTP proxy. Para SOCKS5 necesitarías manejadores adicionales, por lo que recomendamos usar el puerto HTTP de la misma IP. El sitio destino verá la misma IP.
El ejemplo usa IP 198.51.100.23, puerto HTTP 8000, usuario spx_user, contraseña spx_pass.
pip install scrapy
scrapy startproject shop
cd shop¿Cómo configurar proxy por solicitud?
Añade proxy a meta cuando creas Request en start_requests. Haz lo mismo al solicitar la siguiente página en el callback. Para mantener la misma sesión, pasa el valor de proxy desde meta de la respuesta anterior para mantener la misma IP.
import scrapy
PROXY = "http://spx_user:spx_pass@198.51.100.23:8000"
class IpCheckSpider(scrapy.Spider):
name = "ip_check"
def start_requests(self):
yield scrapy.Request("https://api.ipify.org?format=json", meta={"proxy": PROXY})
def parse(self, response):
self.logger.info("seen as %s", response.json()["ip"])¿Cómo rotar IP por solicitud?
Un middleware de descarga que inyecta proxies rotativos evita modificar el código del spider. Este ejemplo obtiene la lista via API al inicio y respeta proxies existentes en meta para compatibilidad con sesiones fijas y rotación.
Guarda las claves API en settings.py o léelas desde variables de entorno. Regístralas con un número menor que el de HttpProxyMiddleware (750) para que el middleware base procese las direcciones que añada el middleware.
import itertools
import requests
class RotatingProxyMiddleware:
def __init__(self, key):
text = requests.get(
"https://socks5proxy.io/api/v1/proxies/download",
params={"format": "user:pass@ip:port", "protocol": "http"},
headers={"Authorization": "Bearer " + key},
timeout=30,
).text
self.pool = itertools.cycle(["http://" + l.strip() for l in text.splitlines() if l.strip()])
@classmethod
def from_crawler(cls, crawler):
return cls(crawler.settings.get("SPX_API_KEY"))
def process_request(self, request, spider):
if "proxy" not in request.meta: # keep a proxy that was set on purpose (sticky sessions)
request.meta["proxy"] = next(self.pool)SPX_API_KEY = "YOUR_API_KEY"
DOWNLOADER_MIDDLEWARES = {
"shop.middlewares.RotatingProxyMiddleware": 740,
}
CONCURRENT_REQUESTS = 32
CONCURRENT_REQUESTS_PER_DOMAIN = 16
DOWNLOAD_DELAY = 0.25
AUTOTHROTTLE_ENABLED = True
RETRY_TIMES = 3
RETRY_HTTP_CODES = [429, 500, 502, 503, 504, 522, 524, 408]
DOWNLOAD_TIMEOUT = 30¿Cómo ajustar la velocidad y los reintentos?
CONCURRENT_REQUESTS_PER_DOMAIN es el número de solicitudes simultáneas a un mismo dominio. Cuantas más IPs de proxy tengas, más puedes aumentar este valor sin sobrecargar una sola IP. Por ejemplo, con 500 IPs y 50 solicitudes simultáneas, cada IP se usará en promedio solo una vez cada 10 solicitudes.
AUTOTHROTTLE ajusta automáticamente los intervalos entre solicitudes según la velocidad de respuesta. Si aumentan las respuestas 429, usa RETRY_HTTP_CODES para reintentar, pero también puedes borrar el proxy en meta para que el middleware use el siguiente proxy en el reintento.
Incluya un paso en la canalización para verificar si los resultados recopilados son páginas reales y no de confirmación, lo que mejorará la calidad de los datos. Si falta algún elemento esencial en la respuesta, puede solicitar nuevamente con otra IP.
- Ajusta el número de solicitudes simultáneas por dominio según el número de IPs
- AUTOTHROTTLE para ajustar intervalos según velocidad de respuesta
- Para 429 y 5xx, reintenta con otra IP
- Filtrar pantallas de verificación mediante inspección de contenido de respuesta
¿Qué cambia al conectarse con autorización por IP?
Si registras la IPv4 del servidor donde se ejecuta Scrapy en el panel de control, puedes usar el proxy meta sin nombre de usuario y contraseña, como http://198.51.100.23:8000. También puedes obtener la lista en formato ip:port. Si ejecutas spiders en varios servidores, registra las IPs de todos los servidores. Puedes registrar hasta 10 IPs.
¿Cómo agrupar solicitudes que requieren sesión bajo un mismo IP?
Para flujos que requieren continuidad de cookies (como inicio de sesión o carritos de compra), usa la misma IP. Inserta meta proxy directamente en la primera solicitud y pasa el valor proxy de response.meta en las siguientes para evitar cambios por middleware. Usar cookiejar de Scrapy también separa cookies por sesión.
Empareja un proxy y un conjunto de cookies por sesión para evitar mezclas al ejecutar múltiples sesiones simultáneas.
import scrapy
PROXIES = [
"http://spx_user:spx_pass@198.51.100.23:8000",
"http://spx_user:spx_pass@198.51.100.24:8000",
]
class SessionSpider(scrapy.Spider):
name = "sessions"
def start_requests(self):
for i, proxy in enumerate(PROXIES):
yield scrapy.Request("https://example.com/", meta={"proxy": proxy, "cookiejar": i}, dont_filter=True)
def parse(self, response):
# follow-up request keeps the same proxy and the same cookie jar
yield response.follow("/account", meta={"proxy": response.meta["proxy"], "cookiejar": response.meta["cookiejar"]}, callback=self.parse_account)
def parse_account(self, response):
self.logger.info("status %s via %s", response.status, response.meta["proxy"])¿Cómo pausar temporalmente proxies fallidos?
Si recibes respuestas 403 o 429 en el middleware process_response, puedes hacer que el proxy descanse durante unos minutos y enviar la misma solicitud a otro proxy. Copia la solicitud, elimina el proxy de meta, activa dont_filter y devuélvela para que el siguiente proxy la procese.
Administrar la lista de proxies en descanso y el momento de reutilización con un diccionario es sencillo. No reutilizar la misma IP inmediatamente permite que el sitio objetivo levante las restricciones.
¿Qué configurar en Scrapy para ahorrar ancho de banda?
Scrapy por defecto solo descarga HTML, usando mucho menos ancho de banda que navegadores. HttpCompressionMiddleware activado por defecto reduce aún más el tráfico, permitiendo recolectar muchas páginas dentro del ancho de banda mensual de planes compartidos.
Activa HTTPCACHE_ENABLED durante desarrollo para evitar re-solicitudes, ahorrando llamadas al sitio y proxy. En producción, mantén el filtro de duplicados (activado por defecto) y usa dont_filter solo cuando sea necesario.
Limitar el rango de seguimiento de enlaces para evitar páginas irrelevantes también es importante. Definir claramente el alcance del scraping reduce tiempo, ancho de banda y carga en el sitio objetivo.
¿Cómo soluciono problemas frecuentes?
Si recibes una respuesta 407, verifica el nombre de usuario y contraseña en la dirección. Si la contraseña tiene caracteres especiales, debes codificarla con porcentaje. TunnelError ocurre cuando el proxy no recibe una solicitud CONNECT; verifica que el puerto sea el puerto HTTP.
Si todas las solicitudes salen por la misma IP, puede que HttpProxyMiddleware esté en un orden incorrecto en settings.py o que el spider esté estableciendo meta proxy directamente. Revisa el orden en settings.py y el código del spider.