Réponse rapide
Comment utiliser un proxy rotatif en Node.js ?
Avec fetch, créez un undici ProxyAgent pour http://gw.crawlrelay.com:7777 et passez-le en dispatcher. Avec axios ou got, passez un agent proxy comme https-proxy-agent ou hpagent, et définissez proxy: false dans axios. CrawlRelay proxies résidentiels lisent le pays et la session dans le nom d’utilisateur, via 0,50 $US/GB. Payez en crypto, sans KYC.
Installation rapide Node.js
| fetch / undici | new ProxyAgent({ uri, token }), puis fetch(url, { dispatcher }) |
|---|---|
| axios | httpsAgent: new HttpsProxyAgent(url) et proxy: false |
| got | agent: { https: new HttpsProxyAgent({ proxy }) } depuis hpagent |
| SOCKS5 | socks-proxy-agent avec une URL socks5h:// sur le port 7778 |
| Nouvelle IP à chaque requête | Un nouvel agent ou un nouvel ID de session par requête ; les connexions en pool gardent leur sortie |
| Format de module | Exemples : modules ES (.mjs ou "type": "module") avec await de niveau supérieur |
Comment utiliser un proxy avec fetch de Node ?
Le fetch global de Node fetch est basé sur undici mais ne lit pas HTTP_PROXY ou HTTPS_PROXY par défaut. Installez undici et passez un ProxyAgent comme dispatcher. Le champ token envoie les identifiants en tant qu’en-tête Proxy-Authorization, donc aucun mot de passe n’apparaît dans une URL potentiellement loguée.
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();Comment utiliser un proxy avec axios ?
Ne comptez pas sur l’option proxy native d’axios pour les sites HTTPS : elle envoie la requête au proxy sans tunnel CONNECT, ce que beaucoup de proxies rejettent. Désactivez-la avec proxy: false et passez un agent qui ouvre un tunnel correct.
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);Comment utiliser un proxy avec got ?
got prend un agent par protocole. hpagent suit le http.Agent de Node : keep-alive désactivé sauf si vous passez keepAlive: true. Laissez-le désactivé ou activez keepAlive: false comme ci-dessous, quand vous voulez chaque requête sur une nouvelle connexion et donc généralement sur une nouvelle sortie.
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);Comment utiliser SOCKS5 dans Node.js ?
Utilisez socks-proxy-agent avec le schéma socks5h:// pour que le nom d’hôte soit résolu à la sortie. Ça marche avec les modules http et https de Node, ainsi qu’avec toute librairie acceptant 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));Comment limiter la concurrence par hôte sans bibliothèque ?
Promise.all sur 10 000 URLs ouvre 10 000 requêtes en même temps. Un petit limiteur par nom d’hôte maintient chaque site à un niveau raisonnable tandis que le crawl entier tourne en parallèle. La version ci-dessous n’a aucune dépendance et fonctionne avec n’importe quel client.
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();Pourquoi ai-je la même IP deux fois, ou ECONNRESET ?
Les agents mettent les connexions en pool, et une connexion en pool garde la sortie avec laquelle elle a été ouverte. Pour une nouvelle IP à chaque requête, créez un nouvel agent par requête et fermez-le ensuite, désactivez keep-alive dans l’agent, ou mettez un -session-<id> unique dans le nom d’utilisateur de chaque requête.
ECONNRESET et socket hang up viennent habituellement de la réutilisation d’un socket en pool que l’autre côté a déjà fermé, ou d’une sortie qui a été coupée. Retentez les requêtes GET une fois sur une nouvelle connexion. La page sur la réinitialisation de connexion explique les détails.
Node.js et proxies : questions
Node.js fetch supporte-t-il HTTP_PROXY ?
Pas par défaut dans les versions utilisées aujourd’hui : le fetch global ignore les variables d’environnement proxy à moins que vous ne passiez un dispatcher. Utilisez un ProxyAgent undici comme montré ci-dessus, ou définissez un dispatcher global avec setGlobalDispatcher() d’undici si chaque requête dans le processus doit utiliser le proxy.
Pourquoi axios échoue-t-il avec les sites HTTPS derrière un proxy ?
L’option proxy intégrée d’axios envoie les requêtes HTTPS au proxy sous une forme que beaucoup de proxies refusent, au lieu d’ouvrir un tunnel CONNECT. Mettez proxy: false et passez un HttpsProxyAgent comme httpsAgent. La requête passe alors par un tunnel correct, et TLS reste entre votre code et le site.
Comment envoyer des pays différents depuis un seul processus Node.js ?
Créez un agent par pays, chacun avec son propre nom d’utilisateur tel que USERNAME-country-de ou USERNAME-country-jp, et choisissez l’agent par requête. Les agents sont peu coûteux, et les garder séparés garde aussi leurs pools de connexion, donc leurs sorties, séparées.
Quel timeout dois-je définir dans Node.js ?
Fixez-en toujours un : AbortSignal.timeout(30000) pour fetch, timeout: 30000 pour axios, timeout: { request: 30000 } pour got. Trente secondes conviennent aux pages HTML ; donnez aux cibles lentes et sorties mobiles jusqu’à 60 secondes, et retentez une fois sur une nouvelle connexion plutôt que d’attendre plus longtemps.
Connectez votre crawler Node.js
5,94 $US pour 10 GB, 0,50 $US/GB depuis 50 GB.