Respuesta rápida
¿Cómo usar un proxy rotativo en Node.js?
Con fetch, crea un undici ProxyAgent para http://gw.crawlrelay.com:7777 y pásalo como dispatcher. Con axios o got, pasa un agente proxy como https-proxy-agent o hpagent, y configura proxy: false en axios. CrawlRelay proxies residenciales leen el país y la sesión desde el usuario, desde 0,50 US$/GB. Pagados con criptomonedas, sin KYC.
Configuración de Node.js de un vistazo
| fetch / undici | new ProxyAgent({ uri, token }), luego fetch(url, { dispatcher }) |
|---|---|
| axios | httpsAgent: new HttpsProxyAgent(url) y proxy: false |
| got | agent: { https: new HttpsProxyAgent({ proxy }) } desde hpagent |
| SOCKS5 | socks-proxy-agent con una URL socks5h:// en el puerto 7778 |
| Nueva IP por solicitud | Un nuevo agente o un nuevo ID de sesión por solicitud; las conexiones agrupadas mantienen su salida |
| Formato de módulo | Los ejemplos son módulos ES (.mjs o "type": "module") con await a nivel superior |
¿Cómo uso un proxy con fetch en Node?
El fetch global de Node está basado en undici pero no lee HTTP_PROXY ni HTTPS_PROXY por defecto. Instala undici y pasa un ProxyAgent como dispatcher. El campo token envía las credenciales como un encabezado Proxy-Authorization, de modo que nunca aparece la contraseña en una URL que podría ser registrada.
import { ProxyAgent, fetch } from "undici";
const credentials = Buffer.from("USERNAME-country-us:PASSWORD").toString("base64");
const dispatcher = new ProxyAgent({
uri: "http://gw.crawlrelay.com:7777",
token: `Basic ${credentials}`,
});
const res = await fetch("https://api.ipify.org?format=json", {
dispatcher,
signal: AbortSignal.timeout(30000),
});
console.log(res.status, await res.json());
await dispatcher.close();¿Cómo uso un proxy con axios?
No confíes en la opción proxy propia de axios para sitios HTTPS: envía la solicitud al proxy sin un túnel CONNECT, que muchos proxies rechazan. Desactívalo con proxy: false y pasa un agente que abra un túnel adecuado.
import axios from "axios";
import { HttpsProxyAgent } from "https-proxy-agent";
const agent = new HttpsProxyAgent("http://USERNAME-country-de:[email protected]:7777");
const client = axios.create({ httpsAgent: agent, httpAgent: agent, proxy: false, timeout: 30000 });
const { data } = await client.get("https://api.ipify.org?format=json");
console.log(data.ip);¿Cómo uso un proxy con got?
got usa un agente por protocolo. hpagent sigue el http.Agent de Node: keep-alive está desactivado a menos que pases keepAlive: true. Déjalo desactivado o configura keepAlive: false como abajo cuando quieres cada solicitud en una conexión nueva, y por lo general en una salida nueva.
import got from "got";
import { HttpsProxyAgent } from "hpagent";
const proxy = "http://USERNAME-country-fr:[email protected]:7777";
const body = await got("https://api.ipify.org", {
agent: { https: new HttpsProxyAgent({ proxy, keepAlive: false }) },
timeout: { request: 30000 },
retry: { limit: 2, statusCodes: [429, 502, 503, 504] },
}).text();
console.log(body);¿Cómo uso SOCKS5 en Node.js?
Usa socks-proxy-agent con el esquema socks5h:// para que el nombre de host se resuelva en la salida. Funciona con los módulos http y https de Node y con cualquier biblioteca que acepte un agente.
import https from "node:https";
import { SocksProxyAgent } from "socks-proxy-agent";
const agent = new SocksProxyAgent("socks5h://USERNAME-country-gb:[email protected]:7778");
const req = https.get("https://api.ipify.org", { agent, timeout: 30000 }, (res) => {
let body = "";
res.on("data", (chunk) => (body += chunk));
res.on("end", () => console.log(res.statusCode, body));
});
req.on("timeout", () => req.destroy(new Error("timeout after 30 s")));
req.on("error", (err) => console.error(err.code, err.message));¿Cómo limito la concurrencia por host sin una biblioteca?
Promise.all sobre 10,000 URLs abre 10,000 solicitudes a la vez. Un limitador pequeño por hostname mantiene cada sitio en un nivel respetuoso mientras el rastreo entero corre en paralelo. La versión abajo no tiene dependencia y funciona con cualquier cliente superior.
import { ProxyAgent, fetch } from "undici";
const PER_HOST = 4;
const active = new Map();
const waiting = new Map();
const dispatcher = new ProxyAgent("http://USERNAME-country-us:[email protected]:7777");
async function withHostSlot(url, task) {
const host = new URL(url).hostname;
while ((active.get(host) ?? 0) >= PER_HOST) {
await new Promise((resolve) => {
if (!waiting.has(host)) waiting.set(host, []);
waiting.get(host).push(resolve);
});
}
active.set(host, (active.get(host) ?? 0) + 1);
try {
return await task();
} finally {
active.set(host, active.get(host) - 1);
waiting.get(host)?.shift()?.();
}
}
const urls = ["https://example.com/", "https://example.org/", "https://example.net/"];
const results = await Promise.all(
urls.map((url) =>
withHostSlot(url, async () => {
const res = await fetch(url, { dispatcher, signal: AbortSignal.timeout(30000) });
return [url, res.status, (await res.arrayBuffer()).byteLength];
}).catch((err) => [url, err.name, 0])
)
);
console.table(results);
await dispatcher.close();¿Por qué obtengo la misma IP dos veces o ECONNRESET?
Los agentes agrupan conexiones, y una conexión agrupada mantiene la salida con la que se abrió. Para una IP nueva en cada solicitud, crea un agente nuevo por solicitud y ciérralo después, desactiva keep-alive en el agente, o pon un -session-<id> único en el nombre de usuario de cada solicitud.
ECONNRESET y socket hang up suelen venir de reutilizar un socket agrupado que el otro lado ya cerró, o de una salida que se cayó. Reintenta solicitudes GET una vez en una conexión nueva. La página sobre reinicios de conexión cubre los detalles.
Node.js y proxies: preguntas
¿fetch de Node.js soporta HTTP_PROXY?
No por defecto en las versiones que la mayoría de proyectos usan hoy: el fetch global ignora variables de entorno de proxy a menos que pases un dispatcher. Usa un ProxyAgent de undici como se mostró arriba, o define un dispatcher global con el setGlobalDispatcher() de undici si todas las solicitudes del proceso deben usar el proxy.
¿Por qué falla axios con sitios HTTPS detrás de un proxy?
La opción proxy integrada de axios envía solicitudes HTTPS al proxy en un formato que muchos proxies rechazan, en lugar de abrir un túnel CONNECT. Configura proxy: false y pasa un HttpsProxyAgent como httpsAgent. La solicitud entonces viaja por un túnel adecuado, y TLS permanece entre tu código y el sitio.
¿Cómo envío diferentes países desde un proceso Node.js?
Crea un agente por país, cada uno con su propio nombre de usuario como USERNAME-country-de o USERNAME-country-jp, y escoge el agente por solicitud. Los agentes son baratos, y mantenerlos separados también mantiene sus grupos de conexión, y así sus salidas, separados.
¿Qué timeout debo configurar en Node.js?
Siempre configura uno: AbortSignal.timeout(30000) para fetch, timeout: 30000 para axios, timeout: { request: 30000 } para got. Treinta segundos son adecuados para páginas HTML; da hasta 60 segundos para objetivos lentos y salidas móviles, y reintenta una vez en una conexión nueva en lugar de esperar más.
Conecta tu rastreador Node.js
5,94 US$ para 10 GB, 0,50 US$/GB de 50 GB.