Risposta rapida
Come uso un proxy rotante in Node.js?
Con fetch, crea un undici ProxyAgent per http://gw.crawlrelay.com:7777 e passalo come dispatcher. Con axios o got, passa un agente proxy come https-proxy-agent o hpagent, e imposta proxy: false in axios. CrawlRelay proxy residenziali leggono il paese e la sessione dallo username, da 0,50 USD/GB. Pagati in crypto, senza KYC.
Configurazione Node.js in breve
| fetch / undici | new ProxyAgent({ uri, token }), poi fetch(url, { dispatcher }) |
|---|---|
| axios | httpsAgent: new HttpsProxyAgent(url) e proxy: false |
| got | agent: { https: new HttpsProxyAgent({ proxy }) } da hpagent |
| SOCKS5 | socks-proxy-agent con un URL socks5h:// sulla porta 7778 |
| Nuovo IP per richiesta | Un nuovo agente o un nuovo ID sessione per richiesta; le connessioni in pool mantengono la loro uscita |
| Formato modulo | Gli esempi sono moduli ES (.mjs o "type": "module") con await a livello superiore |
Come uso un proxy con fetch di Node?
Il global fetch di Node si basa su undici ma di default non legge HTTP_PROXY o HTTPS_PROXY. Installa undici e passa un ProxyAgent come dispatcher. Il campo token invia le credenziali come header Proxy-Authorization, quindi nessuna password appare mai in un URL che potrebbe essere loggato.
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();Come uso un proxy con axios?
Non affidarti all’opzione proxy di axios per siti HTTPS: manda la richiesta al proxy senza un tunnel CONNECT, che molti proxy rifiutano. Disabilitala con proxy: false e usa un agent che apra un tunnel corretto.
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);Come uso un proxy con got?
got usa un solo agent per protocollo. hpagent segue il http.Agent di Node: keep-alive è disattivato a meno che non passi keepAlive: true. Lascialo disattivato o imposta keepAlive: false come sotto se vuoi che ogni richiesta usi una nuova connessione, e quindi di solito una nuova uscita.
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);Come uso SOCKS5 in Node.js?
Usa socks-proxy-agent con lo schema socks5h:// così il nome host viene risolto all’uscita. Funziona con i moduli http e https di Node e con qualsiasi libreria che accetta un agent.
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));Come limito la concorrenza per host senza una libreria?
Promise.all su 10.000 URL apre 10.000 richieste contemporaneamente. Un piccolo limitatore per hostname mantiene ogni sito a un livello educato mentre il crawl complessivo gira in parallelo. La versione sotto non ha dipendenze e funziona con qualunque client sopra.
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();Perché ottengo lo stesso IP due volte o ECONNRESET?
Gli agent usano pool di connessioni e una connessione in pool mantiene l’uscita con cui è stata aperta. Per un IP nuovo a ogni richiesta, crea un nuovo agent per richiesta e chiudilo dopo, disattiva keep-alive nell’agent, o inserisci un unico -session-<id> nell’username di ogni richiesta.
ECONNRESET e socket hang up di solito derivano dal riutilizzo di un socket in pool che l’altra parte ha già chiuso, o da un’uscita caduta. Riprova le richieste GET una volta su una connessione nuova. La pagina sul reset di connessione spiega i dettagli.
Node.js e proxy: domande
Node.js fetch supporta HTTP_PROXY?
Non di default nelle versioni usate dalla maggior parte dei progetti oggi: il fetch globale ignora le variabili d’ambiente proxy a meno che non passi un dispatcher. Usa un ProxyAgent di undici come mostrato sopra, o imposta un dispatcher globale con il setGlobalDispatcher() di undici se ogni richiesta nel processo deve usare il proxy.
Perché axios fallisce con siti HTTPS dietro un proxy?
L’opzione integrata proxy di axios manda le richieste HTTPS al proxy in una forma che molti proxy rifiutano, invece di aprire un tunnel CONNECT. Imposta proxy: false e passa un HttpsProxyAgent come httpsAgent. La richiesta viaggia così attraverso un tunnel corretto, e TLS rimane tra il tuo codice e il sito.
Come invio paesi diversi da un unico processo Node.js?
Crea un agente per ogni paese, ognuno con un suo username tipo USERNAME-country-de o USERNAME-country-jp, e scegli l’agent per richiesta. Gli agent sono economici, e tenerli separati mantiene separate anche le loro pool di connessioni e quindi le loro uscite.
Quale timeout devo impostare in Node.js?
Imposta sempre un timeout: AbortSignal.timeout(30000) per fetch, timeout: 30000 per axios, timeout: { request: 30000 } per got. Trenta secondi vanno bene per pagine HTML; concedi fino a 60 secondi per destinazioni lente e uscite mobili 4G, e riprova una volta su una connessione nuova piuttosto che aspettare oltre.
Collega il tuo crawler Node.js
5,94 USD per 10 GB, 0,50 USD/GB da 50 GB.