Pourquoi got-scraping avec Node.js change la donne
Si vous avez déjà écrit un scraper en Node.js avec axios ou got brut, vous connaissez le scénario : 50 requêtes passent, puis soudain vous recevez des 403 Forbidden ou des challenges Cloudflare. Le problème n'est pas votre logique de scraping — c'est que votre client HTTP trahit son identité à plusieurs niveaux. got-scraping avec Node.js résout précisément cela en générant des ensembles d'en-têtes cohérents qui imitent un vrai navigateur, avec support HTTP/2 natif.
got-scraping est un wrapper construit par Apify au-dessus de got, le client HTTP populaire pour Node.js. Il intègre header-generator, une bibliothèque qui produit des en-têtes dans le bon ordre, avec les bonnes valeurs sec-ch-ua, accept-language, et tous les en-têtes que Chrome, Firefox ou Safari envoient réellement. Combiné à un got-scraping proxy résidentiel, vous obtenez un niveau de furtivité que axios.get() ne pourra jamais atteindre seul.
Avertissement légal : ce guide couvre la collecte de données publiques uniquement. Aux États-Unis, le CFAA criminalise l'accès non autorisé à des systèmes informatiques. En Europe, le RGPD régule le traitement des données personnelles. Respectez le robots.txt, les conditions d'utilisation des sites, et préférez toujours une API officielle quand elle existe.
Pourquoi les requêtes got/axios brutes se font repérer
Les systèmes anti-bot modernes comme Cloudflare, Datadome et PerimeterX ne se contentent plus de vérifier un seul signal. Ils croisent plusieurs couches :
- Empreinte TLS (JA3/JA4) — la négociation TLS de Node.js diffère de celle de Chrome. Le JA3 fingerprint de Node 20 ne correspond à aucun navigateur connu.
- Ordre des en-têtes — Chrome envoie toujours
sec-ch-uaavantuser-agent, puisaccept. got et axios envoient les en-têtes dans l'ordre d'insertion, ce qui est immédiatement détectable. - En-têtes manquants — un vrai navigateur envoie 15–25 en-têtes, dont
sec-fetch-dest,sec-fetch-mode,sec-fetch-site,priority. La plupart des clients HTTP n'en envoient que 4 ou 5. - HTTP/2 — Chrome utilise HTTP/2 par défaut avec HPACK et des paramètres SETTINGS spécifiques. Node.js en HTTP/1.1 se distingue immédiatement.
Le dépôt got-scraping d'Apify a été conçu spécifiquement pour résoudre ces problèmes. Il s'appuie sur header-generator pour produire des ensembles d'en-têtes cohérents — pas seulement un User-Agent aléatoire, mais toute la suite d'en-têtes que le navigateur choisi enverrait réellement, dans le bon ordre.
La surface idiomatique de got-scraping
got-scraping expose une API qui étend got de manière transparente. Vous pouvez l'utiliser comme un drop-in replacement, puis le configurer via got.extend().
got.extend, useHeaderGenerator et headerGeneratorOptions
Le pattern idiomatique consiste à créer une instance personnalisée avec got.extend(), en passant useHeaderGenerator: true et des headerGeneratorOptions qui contrôlent quels profils de navigateurs sont émis :
const { gotScraping } = require('got-scraping');
const client = gotScraping.extend({
useHeaderGenerator: true,
headerGeneratorOptions: {
browsers: ['chrome', 'firefox'],
devices: ['desktop'],
operatingSystems: ['windows', 'macos'],
locales: ['fr-FR', 'en-US'],
},
http2: true,
});
// Chaque requête reçoit un ensemble d'en-têtes cohérent
const res = await client.get('https://example.com');
console.log(res.headers);
Ici, got scraping header generator garantit que si le User-Agent dit Chrome 120 sur Windows, les en-têtes sec-ch-ua, sec-ch-ua-platform et accept seront cohérents avec cette signature. C'est cette cohérence qui manque à la plupart des scrapers DIY.
L'option proxyUrl pour HTTP/1 et HTTP/2
got-scraping accepte une option proxyUrl qui fonctionne aussi bien avec des proxies HTTP/1.1 qu'avec des proxies HTTP/2. Pour un nodejs scraping proxy résidentiel, vous passez simplement l'URL complète :
const res = await client.get('https://httpbin.org/headers', {
proxyUrl: 'http://user-country-US-session-abc123:pass@gate.proxyhat.com:8080',
});
Le proxy résidentiel de ProxyHat supporte le tunneling HTTPS via CONNECT, ce qui signifie que votre trafic TLS reste chiffré de bout en bout — le proxy ne voit que la destination, pas le contenu.
Routage via proxies résidentiels ProxyHat
Une fois que vos en-têtes et votre empreinte TLS ressemblent à un vrai navigateur, la dernière couche de détection est l'adresse IP. Un datacenter IP (OVH, AWS, DigitalOcean) est immédiatement flagué par la plupart des bases de données IP reputation. C'est là que les proxies résidentiels deviennent essentiels.
Les proxies résidentiels de ProxyHat routent votre trafic via des adresses IP attribuées par des FAI réels (AT&T, Orange, Deutsche Telekom). Pour les sites anti-bot, votre requête ressemble à celle d'un utilisateur domestique normal, pas à celle d'un bot dans un datacenter.
ProxyHat HTTP sur le port 8080
Le endpoint HTTP par défaut est gate.proxyhat.com:8080. Le geo-targeting et les sessions sticky se configurent directement dans le nom d'utilisateur :
// Proxy résidentiel US avec session sticky
const proxyUrl = 'http://user-country-US-session-abc123:PASSWORD@gate.proxyhat.com:8080';
// Proxy résidentiel allemand ciblant Berlin
const proxyDe = 'http://user-country-DE-city-berlin-session-def456:PASSWORD@gate.proxyhat.com:8080';
SOCKS5 sur le port 1080
Pour les cas où SOCKS5 est préférable (par exemple, certains clients HTTP ne supportent que SOCKS5, ou vous voulez éviter le tunnel CONNECT), ProxyHat expose aussi SOCKS5 sur le port 1080 :
const proxySocks5 = 'socks5://user-country-GB-session-ghi789:PASSWORD@gate.proxyhat.com:1080';
Consultez la documentation ProxyHat pour la liste complète des paramètres de géo-ciblage disponibles.
Exemple Node.js complet : rotation de sessions résidentielles avec retry
Voici un exemple runnable qui combine got-scraping, la rotation de proxies résidentiels ProxyHat, et des hooks de retry. Le pattern clé : générer un identifiant de session unique par requête pour obtenir une nouvelle IP résidentielle à chaque appel.
const { gotScraping } = require('got-scraping');
const crypto = require('crypto');
const PROXYHAT_USER = 'user';
const PROXYHAT_PASS = 'pass';
function buildProxyUrl(country = 'US') {
const session = crypto.randomBytes(8).toString('hex');
return `http://${PROXYHAT_USER}-country-${country}-session-${session}:${PROXYHAT_PASS}@gate.proxyhat.com:8080`;
}
const client = gotScraping.extend({
useHeaderGenerator: true,
headerGeneratorOptions: {
browsers: ['chrome'],
devices: ['desktop'],
operatingSystems: ['windows'],
locales: ['en-US'],
},
http2: true,
retry: {
limit: 3,
statusCodes: [403, 429, 500, 502, 503],
backoffLimit: 5000,
},
hooks: {
beforeRequest: [
(options) => {
// Nouvelle IP résidentielle à chaque requête
options.proxyUrl = buildProxyUrl('US');
},
],
afterResponse: [
(response, retryWithMergedOptions) => {
if (response.statusCode === 403 || response.statusCode === 429) {
// Rotation d'IP et retry
return retryWithMergedOptions({
proxyUrl: buildProxyUrl('US'),
});
}
return response;
},
],
},
});
async function scrape(urls) {
const results = [];
for (const url of urls) {
try {
const res = await client.get(url, { timeout: { request: 15000 } });
results.push({ url, status: res.statusCode, length: res.body.length });
} catch (err) {
results.push({ url, error: err.message });
}
}
return results;
}
scrape([
'https://httpbin.org/ip',
'https://httpbin.org/headers',
'https://httpbin.org/user-agent',
]).then(console.log);
Avec ce pattern, chaque requête obtient une IP résidentielle US différente. Si une IP se fait bloquer (403/429), le hook afterResponse déclenche un retry avec une nouvelle session — donc une nouvelle IP. Le retry.limit de 3 signifie jusqu'à 3 tentatives avec backoff exponentiel jusqu'à 5 secondes.
Patterns de production
Concurrency bornée avec p-limit
Scrapper 10 000 URLs en parallèle va saturer votre machine et probablement déclencher des rate limits côté serveur. Utilisez p-limit pour borner la concurrence :
const pLimit = require('p-limit');
const limit = pLimit(20); // 20 requêtes simultanées max
const tasks = urls.map((url) => limit(() => client.get(url)));
const results = await Promise.allSettled(tasks);
20 requêtes concurrentes est un bon point de départ. Au-delà, ajoutez un délai de 200–500ms entre les batches pour lisser la charge.
Cookie jars pour les sessions persistantes
Certains sites nécessitent une session cookie cohérente à travers plusieurs pages. got-scraping supporte tough-cookie via l'option cookieJar :
const { CookieJar } = require('tough-cookie');
const jar = new CookieJar();
const sessionClient = client.extend({
cookieJar: jar,
hooks: {
beforeRequest: [
(options) => {
options.proxyUrl = buildProxyUrl('US');
},
],
},
});
// La session cookie est maintenue à travers les requêtes
await sessionClient.get('https://example.com/login');
await sessionClient.get('https://example.com/dashboard');
Astuce : si vous voulez une session sticky (même IP + même cookies), gardez le même identifiant de session dans le nom d'utilisateur ProxyHat. Changez de session pour obtenir une nouvelle IP.
Passage à Crawlee et CheerioCrawler
Quand votre scraper grandit au-delà de quelques centaines d'URLs, il devient pertinent de passer à Crawlee, le framework d'Apify qui encapsule got-scraping. CheerioCrawler utilise got-scraping en interne et ajoute la gestion automatique des retries, du rate limiting, et du routing :
const { CheerioCrawler } = require('crawlee');
const crawler = new CheerioCrawler({
requestHandler: async ({ $, request }) => {
const title = $('title').text();
console.log(request.url, title);
},
proxyConfiguration: {
proxyUrls: [
'http://user-country-US-session-s1:pass@gate.proxyhat.com:8080',
'http://user-country-US-session-s2:pass@gate.proxyhat.com:8080',
'http://user-country-US-session-s3:pass@gate.proxyhat.com:8080',
],
},
maxRequestsPerMinute: 60,
autoscaledPoolOptions: { maxConcurrency: 20 },
});
await crawler.run(['https://example.com/page1', 'https://example.com/page2']);
Crawlee gère automatiquement le pool de proxies, le scaling, et les retries. C'est le chemin naturel quand got-scraping seul ne suffit plus.
Quand un navigateur headless devient inévitable
got-scraping est excellent pour le contenu HTML statique et les API JSON. Mais certains sites nécessitent une exécution JavaScript réelle : rendu SPA (React/Vue), challenges Cloudflare Turnstile, ou détéction active du canvas WebGL. Dans ces cas, passez à Playwright ou Puppeteer via Crawlee's PlaywrightCrawler. Le coût est réel : un navigateur headless consomme 150–300 MB de RAM par instance, contre ~2 MB pour got-scraping. Réservez cette approche pour les sites qui le justifient vraiment.
| Approche | Consommation RAM | Vitesse | Furtivité | Cas d'usage |
|---|---|---|---|---|
| axios + proxy datacenter | ~2 MB | Très rapide | Faible | Sites sans protection |
| got-scraping + proxy résidentiel | ~5 MB | Rapide | Élevée | HTML statique, API JSON |
| Playwright + proxy résidentiel | 150–300 MB | Lent | Très élevée | SPA, challenges JS |
Éthique et bonnes pratiques
- Respectez
robots.txt— vérifiez/robots.txtavant de scrapper. C'est une signal, pas une loi, mais l'ignorer vous expose à des risques. - Préférez les APIs officielles — si un site propose une API publique (même payante), c'est presque toujours plus fiable et plus rapide que le scraping.
- Limitez votre taux — 1–5 requêtes/seconde par domaine est raisonnable. Au-delà, vous stresserez l'infrastructure cible.
- Données publiques uniquement — ne contournez pas de paywalls, d'authentification, ou de restrictions d'accès. Le CFAA et le RGPD s'appliquent.
- Identifiez-vous quand c'est approprié — pour la recherche académique ou le monitoring légitime, un User-Agent informatif peut être préférable à l'imitation.
Points clés à retenir
- got-scraping avec Node.js génère des en-têtes de navigateur cohérents via
header-generator, résolvant le problème de l'ordre et des en-têtes manquants.- Le support HTTP/2 natif réduit l'écart d'empreinte TLS entre votre client et un vrai navigateur Chrome.
- Un got-scraping proxy résidentiel via
gate.proxyhat.com:8080est essentiel une fois les en-têtes couverts — les IP datacenter restent le signal le plus facile à détecter.- La rotation de sessions (identifiant unique par requête) donne une nouvelle IP résidentielle à chaque appel, avec retry automatique sur 403/429.
- Bornez votre concurrence avec
p-limit(20 concurrent max), utilisez des cookie jars pour les sessions persistantes, et passez à Crawlee pour le scraping à grande échelle.- Un navigateur headless (Playwright) n'est nécessaire que pour les SPA et les challenges JS actifs — le coût RAM est 30–60x supérieur.
Pour explorer les options de proxies résidentiels disponibles et leur tarification, consultez la page tarification ProxyHat. Pour voir la couverture géographique par pays et ville, visitez la page des locations ProxyHat. Des cas d'usage détaillés sont disponibles sur web scraping et SERP tracking.






