Si vous scrapez sérieusement en Node.js, vous avez probablement rencontré got-scraping, le client HTTP d'Apify basé sur got et conçu spécifiquement pour le web scraping. Ce guide pratique explique comment configurer got-scraping dans Node.js avec des proxies résidentiels, exploiter le header generator pour émettre des en-têtes cohérents, et déployer des patterns de production robustes. Avant d'aller plus loin, une mise au point : ne scrapez que des données publiques, respectez le robots.txt, les conditions d'utilisation des sites, et le RGPD/CCPA. Préférez toujours une API officielle quand elle existe.
Pourquoi got-scraping dans Node.js change la donne
Les requêtes HTTP brutes avec got ou axios finissent presque toujours par être bloquées sur les sites protégés. La raison tient à trois signaux que les systèmes anti-bot modernes — Cloudflare, Datadome, PerimeterX — analysent en quelques millisecondes :
- Empreinte TLS/JA3 : Node.js utilise OpenSSL, dont la négociation TLS diffère de celle de Chrome ou Firefox. Un bot peut envoyer un
User-AgentChrome, mais son JA3 reste celui de Node. - Cohérence des en-têtes : un vrai navigateur envoie
sec-ch-ua,sec-fetch-dest,accept-languagedans un ordre précis. Un client HTTP générique les omet ou les désordonne. - Support HTTP/2 : de nombreux sites servent le HTTP/2 uniquement aux clients ALPN-négociés ; un client HTTP/1.1 pur est immédiatement suspect.
got-scraping adresse ces points. Il s'appuie sur header-generator, une librairie open-source d'Apify qui génère des ensembles d'en-têtes cohérents pour un navigateur, un appareil et un OS donnés — y compris les sec-ch-ua et l'ordre des en-têtes. De plus, il supporte nativement le HTTP/2 via http2-wrapper, ce qui rapproche l'empreinte réseau de celle d'un vrai navigateur. Voir la documentation officielle de got-scraping pour les détails.
Le contexte technique : pourquoi les en-têtes comptent autant que l'IP
Beaucoup de développeurs pensent qu'un proxy résidentiel suffit à passer les filtres. C'est faux. Un proxy résidentiel change votre IP source, mais si vos en-têtes et votre TLS trahissent Node.js, le système anti-bot vous classe comme bot avant même de regarder l'IP. La défense en profondeur exige :
- Des en-têtes navigateur cohérents (header-generator).
- Une empreinte TLS plausible (HTTP/2, ALPN, ordre des cipher suites).
- Une IP résidentielle ou mobile qui correspond à la géolocalisation déclarée dans
accept-language.
Sans les deux premiers, le troisième ne sert à rien. C'est exactement le créneau de got scraping header generator : produire un ensemble d'en-têtes qui, combiné à un proxy résidentiel, rend votre trafic indiscernable d'un visiteur réel. Les benchmarks publics montrent que les sites protégés par Cloudflare bloquent 40 à 60 % des requêtes HTTP/1.1 avec en-têtes génériques, même derrière une IP résidentielle — contre moins de 10 % avec des en-têtes cohérents et HTTP/2.
Surface idiomatique de got-scraping
got-scraping expose une API compatible got. On l'étend via got.extend() avec un middleware qui injecte les en-têtes générés à chaque requête. Voici les points d'extension clés :
got.extend et useHeaderGenerator
La fonction useHeaderGenerator active le générateur d'en-têtes. On configure headerGeneratorOptions avec trois dimensions :
- browsers :
['chrome', 'firefox']— le navigateur à imiter. - devices :
['desktop']ou['mobile']— desktop produit des en-têtes tablette/laptop, mobile ajoutesec-ch-ua-mobile. - operatingSystems :
['windows', 'macos', 'linux', 'android', 'ios']— influence lessec-ch-ua-platformetuser-agent.
Le générateur garantit la cohérence interne : si vous demandez Chrome sur macOS, vous obtenez un user-agent Chrome/macOS, un sec-ch-ua-platform macOS, et un accept-language plausible. L'ordre des en-têtes suit celui de Chrome réel.
proxyUrl : HTTP/1 et HTTP/2
got-scraping accepte une option proxyUrl pour HTTP/1.1 et HTTP/2. Pour HTTP/2 via proxy, got-scraping utilise http2-wrapper avec support CONNECT. Le format est l'URL standard :
http://user-country-US:password@gate.proxyhat.com:8080
socks5://user-country-DE:password@gate.proxyhat.com:1080
Routing via proxies résidentiels ProxyHat
Une fois les en-têtes et le TLS maîtrisés, l'IP source devient le facteur discriminant. Les proxies datacenter sont dans des plages ASN identifiées (OVH, DigitalOcean, AWS) que les anti-bots filtrent agressivement. Les proxies résidentiels utilisent des IPs attribuées par des FAI à de vrais foyers — leur réputation est celle d'un utilisateur normal.
Avec ProxyHat, le gateway est gate.proxyhat.com, port 8080 pour HTTP, 1080 pour SOCKS5. Le pays et la session se passent dans le nom d'utilisateur, ce qui permet une rotation par requête sans réauthentification :
user-country-US— IP résidentielle aux États-Unis.user-country-DE-city-berlin— ciblage ville.user-session-abc123— session sticky (même IP pendant la durée de la session).user-country-US-session-abc123— combinaison pays + session.
Consultez la documentation ProxyHat et la page des locations pour la liste complète des géos disponibles.
Exemple Node.js : rotation résidentielle avec retry hooks
Voici un exemple complet et exécutable. Il crée une instance got-scraping étendue, génère un nom d'utilisateur par requête avec rotation de pays et de session, et implémente un hook de retry sur les erreurs 429/503.
import gotScraping from 'got-scraping';
import { HttpsProxyAgent } from 'https-proxy-agent';
import { SocksProxyAgent } from 'socks-proxy-agent';
const PROXYHAT_HOST = 'gate.proxyhat.com';
const PROXYHAT_HTTP_PORT = 8080;
const PROXYHAT_SOCKS_PORT = 1080;
const PROXY_USER = 'youruser';
const PROXY_PASS = 'yourpass';
// Génère un nom d'utilisateur avec pays + session uniques par requête
function buildUsername({ country = 'US', sessionId = null } = {}) {
const parts = [`country-${country}`];
if (sessionId) parts.push(`session-${sessionId}`);
return `${PROXY_USER}-${parts.join('-')}`;
}
function buildProxyUrl({ country, sessionId, socks5 = false }) {
const username = buildUsername({ country, sessionId });
const scheme = socks5 ? 'socks5' : 'http';
const port = socks5 ? PROXYHAT_SOCKS_PORT : PROXYHAT_HTTP_PORT;
return `${scheme}://${username}:${PROXY_PASS}@${PROXYHAT_HOST}:${port}`;
}
const client = gotScraping.extend({
headerGeneratorOptions: {
browsers: [{ name: 'chrome', minVersion: 120 }],
devices: ['desktop'],
operatingSystems: ['windows', 'macos'],
},
retry: {
limit: 4,
statusCodes: [429, 503, 504],
backoffLimit: 8000,
},
hooks: {
beforeRequest: [
(options) => {
const sessionId = Math.random().toString(36).slice(2, 10);
const proxyUrl = buildProxyUrl({
country: 'US',
sessionId,
socks5: false,
});
options.proxyUrl = proxyUrl;
},
],
afterResponse: [
(response, retryWithMergedOptions) => {
if (response.statusCode === 403) {
// Rotation de session et retry
return retryWithMergedOptions({
hooks: {
beforeRequest: [
(opts) => {
opts.proxyUrl = buildProxyUrl({
country: 'US',
sessionId: Math.random().toString(36).slice(2, 10),
});
},
],
},
});
}
return response;
},
],
},
});
// Utilisation
const res = await client('https://httpbin.org/headers', {
timeout: { request: 15000 },
});
console.log(res.body);
Ce pattern est idiomatique : got.extend crée un client réutilisable, beforeRequest injecte le proxy par requête, et afterResponse gère les retries avec rotation. La session change à chaque retry, ce qui évite de retomber sur la même IP bloquée.
Variante SOCKS5
Pour SOCKS5, changez le port vers 1080 et le schéma vers socks5 :
const proxyUrl = buildProxyUrl({
country: 'DE',
sessionId: 'order-9871',
socks5: true,
});
// => socks5://youruser-country-DE-session-order-9871:yourpass@gate.proxyhat.com:1080
SOCKS5 est utile quand le site cible bloque les proxies HTTP transparents ou quand vous avez besoin d'un tunnel TCP de bout en bout (par exemple pour des websockets scraping).
Patterns de production
Retry et afterResponse hooks
got fournit un système de retry intégré configurable via retry.limit, retry.statusCodes, et retry.backoffLimit. Pour le scraping, on étend généralement les statusCodes à [429, 503, 504] et on ajoute un backoff exponentiel avec jitter. Le hook afterResponse permet de détecter les CAPTCHAs (souvent renvoyés en 200 avec un body spécifique) et de déclencher une rotation de proxy + retry :
hooks: {
afterResponse: [
(response, retryWithMergedOptions) => {
const isCaptcha = response.statusCode === 200
&& response.body.includes('cf-challenge-running');
if (isCaptcha) {
return retryWithMergedOptions({
proxyUrl: buildProxyUrl({
country: 'US',
sessionId: Math.random().toString(36).slice(2, 10),
}),
});
}
return response;
},
],
},
Concurrency bornée avec p-limit
Lancer 10 000 requêtes en parallèle saturera votre bande passante, déclenchera des rate limits, et fera flagger votre trafic. Utilisez p-limit pour borner la concurrence :
import pLimit from 'p-limit';
const limit = pLimit(20); // 20 requêtes simultanées max
const urls = ['https://example.com/page/1', /* ... */];
const results = await Promise.all(
urls.map((url) => limit(() => client(url, { timeout: { request: 15000 } })))
);
20 connexions concurrentes est un bon point de départ pour un proxy résidentiel. Au-delà, augmentez progressivement en surveillant le taux de succès. ProxyHat supporte 100 sessions concurrentes par plan standard — adaptez en conséquence.
Cookie jars
Les sites e-commerce et les plateformes social utilisent des cookies de session pour valider la séquence de navigation. got-scraping supporte tough-cookie via l'option cookieJar. Pour les sessions stickies avec proxy résidentiel, associez un cookie jar par session :
import { CookieJar } from 'tough-cookie';
const sessionJar = new CookieJar();
const res = await client('https://example.com/login', {
cookieJar: sessionJar,
proxyUrl: buildProxyUrl({ country: 'US', sessionId: 'sess-001' }),
});
// Requête suivante avec même session => même IP + mêmes cookies
const res2 = await client('https://example.com/dashboard', {
cookieJar: sessionJar,
proxyUrl: buildProxyUrl({ country: 'US', sessionId: 'sess-001' }),
});
Migration vers Crawlee (CheerioCrawler)
Quand votre pipeline grandit au-delà de quelques centaines d'URLs, orchestrez avec Crawlee, le framework d'Apify qui enveloppe got-scraping. CheerioCrawler parse le HTML avec cheerio et gère automatiquement la rotation, les retries, et la file d'attente :
import { CheerioCrawler } from 'crawlee';
const crawler = new CheerioCrawler({
requestHandler: async ({ $, request }) => {
const title = $('title').text();
console.log(request.url, title);
},
maxRequestsPerCrawl: 5000,
maxConcurrency: 20,
proxyConfiguration: {
newUrlFunction: () => buildProxyUrl({
country: 'US',
sessionId: Math.random().toString(36).slice(2, 10),
}),
},
});
await crawler.run(['https://example.com/page/1', 'https://example.com/page/2']);
Crawlee s'intègre nativement avec les proxies ProxyHat via proxyConfiguration. Pour des cas d'usage spécifiques, consultez web scraping et SERP tracking.
Quand un navigateur headless devient inévitable
got-scraping suffit pour 80 à 90 % des sites. Mais certains flux exigent une exécution JavaScript réelle : SPA rendues côté client, challenges Cloudflare Turnstile interactifs, ou pages qui chargent les données via XHR après le DOM initial. Dans ces cas, passez à PlaywrightCrawler dans Crawlee, ou à Playwright directement avec un proxy résidentiel.
Le coût est réel : un headless Chrome consomme ~150-200 Mo de RAM par instance et ~300 ms de startup. Pour une flotte de 100 onglets concurrents, prévoyez 16-20 Go de RAM. Containerisez avec Docker et scalez horizontalement. Utilisez playwright-extra avec stealth plugin pour réduire la détectabilité.
| Approche | RAM / instance | Latence | Détectabilité | Coût relatif |
|---|---|---|---|---|
| got-scraping + proxy résidentiel | ~30 Mo | 200-500 ms | Faible | 1× |
| Playwright headless + proxy | ~150-200 Mo | 1-3 s | Très faible | 5-10× |
| Playwright + stealth + proxy résidentiel | ~200-250 Mo | 2-5 s | Minimale | 8-15× |
Éthique et limites légales
Le web scraping opère dans une zone grise légale. Aux États-Unis, le Computer Fraud and Abuse Act (CFAA) a été utilisé contre des scrapers, bien que l'arrêt Van Buren v. United States (2021) ait restreint sa portée. En UE, le RGPD s'applique aux données personnelles que vous pourriez collecter, même indirectement. Règles de bon sens :
- Respectez
robots.txt— c'est un signal de bonne foi devant un tribunal. - Limitez le débit — ne saturz pas l'infrastructure cible. 1-2 req/s par domaine est raisonnable.
- Ne contournez pas d'authentification — accéder à du contenu derrière login sans autorisation est une violation claire.
- Préférez les APIs officielles — Twitter, Reddit, Google proposent des APIs ; utilisez-les quand elles couvrent votre besoin.
- Ne stockez pas de données personnelles au-delà du nécessaire.
Erreurs courantes et edge cases
Oublier le cookie jar en mode sticky session
Si vous utilisez user-session-abc123 sans cookie jar, chaque requête part avec une session serveur vierge. Les sites qui valident la séquence (login → browse → checkout) renverront 403. Associez systématiquement un cookie jar à un sessionId fixe.
Mélanger devices et operatingSystems incompatibles
Demander devices: ['mobile'] avec operatingSystems: ['macos'] produit un user-agent incohérent (macOS n'existe pas sur mobile). header-generator ne le détecte pas toujours. Restez sur des combinaisons réelles : mobile + android/ios, desktop + windows/macos/linux.
Ne pas gérer le backoff exponentiel
Sur un 429, relancer immédiatement aggrave le rate limit. Utilisez retry.backoffLimit: 8000 et laissez got appliquer le backoff. Ajoutez du jitter pour éviter le thundering herd si vous avez plusieurs workers.
Ignorer l'ordre des en-têtes
header-generator gère l'ordre, mais si vous ajoutez manuellement des en-têtes via headers: { ... }, ils s'ajoutent après les en-têtes générés. Les anti-bots vérifient que user-agent arrive avant accept-encoding. Évitez les surcharges manuelles sauf nécessité absolue.
Key Takeaways
- got-scraping génère des en-têtes navigateur cohérents (ordre, sec-ch-ua, accept-language) et supporte HTTP/2 — c'est la base avant tout proxy.
- Les proxies résidentiels deviennent efficaces uniquement quand les en-têtes et le TLS sont plausibles. Sans header-generator, un proxy résidentiel ne suffit pas.
- ProxyHat : gateway
gate.proxyhat.com, port8080HTTP,1080SOCKS5. Pays et session dans le nom d'utilisateur.- Production :
got.extend+ hooksbeforeRequest/afterResponse,p-limitpour la concurrence, cookie jars pour les sessions stickies.- Au-delà de ~500 URLs, migrez vers Crawlee CheerioCrawler pour l'orchestration.
- Respectez
robots.txt, le RGPD/CCPA, et préférez les APIs officielles.
FAQ
Qu'est-ce que got-scraping dans Node.js ?
got-scraping est un client HTTP pour Node.js basé sur got, développé par Apify. Il intègre un générateur d'en-têtes navigateur cohérents, le support HTTP/2, et des options de proxy pensées pour le scraping. Il s'utilise comme got standard, via gotScraping.extend(), avec des middlewares pour injecter en-têtes et proxies par requête.
Pourquoi got-scraping dans Node.js compte-t-il pour les utilisateurs de proxies ?
Parce qu'un proxy résidentiel seul ne suffit pas : les anti-bots analysent les en-têtes et l'empreinte TLS avant l'IP. got-scraping génère des en-têtes cohérents (ordre, sec-ch-ua, accept-language) et négocie le HTTP/2, ce qui rend le trafic plausible. Combiné à un proxy résidentiel, il maximise le taux de succès sur les sites protégés.
Quel type de proxy fonctionne le mieux avec got-scraping ?
Les proxies résidentiels sont le meilleur choix : ils utilisent des IPs de FAI réels avec une réputation neutre. Les proxies datacenter sont filtrés par ASN. Les proxies mobiles offrent la meilleure réputation mais sont plus chers. Avec ProxyHat, utilisez le port 8080 pour HTTP et 1080 pour SOCKS5, en passant le pays et la session dans le nom d'utilisateur.
Comment éviter les blocages avec got-scraping dans Node.js ?
Combinez header-generator (en-têtes cohérents), proxies résidentiels rotatifs, retry hooks avec backoff exponentiel, concurrence bornée (p-limit à 20), et cookie jars pour les sessions stickies. Respectez le robots.txt, limitez à 1-2 req/s par domaine, et faites tourner les sessions à chaque 403/429. Surveillez le taux de succès et ajustez.
Quand passer de got-scraping à un navigateur headless ?
Quand le site exige une exécution JavaScript réelle (SPA rendues côté client, challenges interactifs Cloudflare Turnstile, données chargées via XHR post-DOM). got-scraping couvre 80-90 % des cas. Pour le reste, migrez vers PlaywrightCrawler dans Crawlee avec un proxy résidentiel, en comptant ~200 Mo de RAM par instance headless.






