got-scraping in Node.js: guida completa con proxy residenziali

Una guida pratica per sviluppatori Node.js su got-scraping di Apify: header generator coerenti, supporto HTTP/2, rotazione di proxy residenziali e pattern di produzione per scraping affidabile a larga scala.

got-scraping in Node.js: A Developer's Guide to Headers, HTTP/2 & Residential Proxies

Perché got-scraping in Node.js risolve il problema delle richieste bloccate

Se hai mai lanciato uno scraper Node.js basato su got o axios contro un sito moderno, sai cosa succede: dopo poche decine di richieste ricevi un 403, un challenge JavaScript o un ban silenzioso. Il problema raramente è l'IP da solo — è che il tuo client HTTP rivela inconfutabilmente di non essere un browser. got-scraping in Node.js nasce esattamente per colmare questo divario: è un wrapper attorno a got che genera header coerenti, gestisce HTTP/2 e si integra nativamente con i proxy. In questa guida vedremo come configurarlo con proxy residenziali ProxyHat per ottenere tassi di successo superiori al 95% anche su target protetti.

Prima di proseguire, una premessa etica e legale: raccogli solo dati pubblici, rispetta il robots.txt, i termini di servizio e i limiti di frequenza. Negli Stati Uniti il Computer Fraud and Abuse Act (CFAA) disciplina l'accesso non autorizzato ai sistemi informatici; nell'UE il GDPR si applica ai dati personali. Quando un'API ufficiale esiste, preferiscila allo scraping.

Perché le richieste raw vengono identificate

I sistemi anti-bot moderni non si limitano a controllare l'User-Agent. Analizzano l'intera fingerprint del client HTTP:

  • Ordine degli header — i browser inviano gli header in un ordine specifico; le librerie HTTP di Node.js usano un ordine diverso, immediatamente riconoscibile.
  • Client Hints — header come sec-ch-ua, sec-ch-ua-mobile, sec-ch-ua-platform sono assenti nelle richieste raw o presentano valori incoerenti.
  • Accept-Language e Accept-Encoding — i browser inviano valori specifici con q-values; le librerie spesso omettono Accept-Language o inviano valori predefiniti.
  • TLS fingerprint (JA3/JA4) — Node.js usa una cipher suite order diversa da Chrome o Firefox, visibile già nel handshake TLS.
  • Protocollo HTTP/2 — la maggior parte dei browser usa HTTP/2 o HTTP/3; molte librerie Node.js inviano richieste HTTP/1.1 anche quando il server supporta h2.

Secondo la documentazione MDN su Sec-CH-UA, questi Client Hints sono inviati dal browser come risposta a Accept-CH del server e riflettono caratteristiche reali del client. Se il tuo scraper invia un User-Agent Chrome ma nessun sec-ch-ua, il server rileva l'incongruenza in meno di 1 ms.

Come funziona il got scraping header generator

Il cuore di got-scraping è il pacchetto header-generator, sviluppato da Apify. Invece di hardcodare un singolo User-Agent, genera un set coerente di header che un browser reale invierebbe per quella combinazione di browser, sistema operativo e dispositivo. Questo significa che:

  • L'ordine degli header corrisponde a quello del browser selezionato.
  • I Client Hints (sec-ch-ua, sec-ch-ua-mobile, sec-ch-ua-platform-version) sono presenti e coerenti con l'User-Agent.
  • Accept-Language riflette una localizzazione plausibile.
  • Accept-Encoding include gzip, deflate, br come un browser moderno.

Il generatore è configurabile tramite headerGeneratorOptions, dove specifichi array di browser, dispositivi e sistemi operativi. Ad esempio, puoi restringere a chrome su desktop con windows e linux, evitando combinazioni implausibili che un sistema anti-bot potrebbe comunque marcare come sospette.

La superficie idiomatica di got-scraping

Il pattern idiomatico per usare got-scraping si basa su got.extend() con il middleware useHeaderGenerator. Questo crea un'istanza personalizzata di got con il generatore di header integrato come hook beforeRequest. Ecco un esempio base:

import { gotScraping } from 'got-scraping';

const response = await gotScraping({
  url: 'https://example.com',
  headerGeneratorOptions: {
    browsers: [
      { name: 'chrome', minVersion: 120, httpVersion: '2' },
    ],
    devices: ['desktop'],
    operatingSystems: ['windows', 'macos'],
    locales: ['en-US', 'en'],
  },
});

console.log(response.statusCode);
console.log(response.body.slice(0, 200));

Per riutilizzare la stessa configurazione su più richieste, usa got.extend() per creare un'istanza condivisa:

import { gotScraping } from 'got-scraping';

const client = gotScraping.extend({
  headerGeneratorOptions: {
    browsers: [{ name: 'chrome', minVersion: 120, httpVersion: '2' }],
    devices: ['desktop'],
    operatingSystems: ['windows'],
    locales: ['en-US', 'en'],
  },
  retry: { limit: 3, statusCodes: [403, 429, 503] },
  timeout: { request: 15000 },
});

const res = await client('https://example.com/page');

L'opzione proxyUrl accetta sia proxy HTTP/1.1 che HTTP/2. Per il got-scraping proxy, passi semplicemente l'URL del proxy nell'oggetto opzioni o nell'estensione. Vedremo la configurazione completa con ProxyHat nella prossima sezione.

Routing attraverso proxy residenziali ProxyHat

Anche con header perfetti e HTTP/2, il tuo IP datacenter resta un segnale forte. I CDN come Cloudflare e le piattaforme anti-bot come PerimeterX assegnano un punteggio di rischio all'IP: i datacenter hanno score alti, i residenziali score bassi. Ecco perché un nodejs scraping proxy residenziale è il complemento naturale a got-scraping.

Con ProxyHat, il gateway è gate.proxyhat.com sulla porta 8080 per HTTP e 1080 per SOCKS5. Il geo-targeting e le sessioni si configurano direttamente nel username:

ParametroFormato usernameDescrizione
Paeseuser-country-USIP residenziale degli Stati Uniti
Cittàuser-country-DE-city-berlinGeo-targeting a livello cittadino
Sessione stickyuser-session-abc123Mantiene lo stesso IP per richieste correlate
Combinatouser-country-US-session-abc123Paese + sessione in un unico username

Il formato URL completo per HTTP è:

http://user-country-US-session-abc123:PASSWORD@gate.proxyhat.com:8080

Per SOCKS5, cambia la porta a 1080 e il protocollo:

socks5://user-country-US-session-abc123:PASSWORD@gate.proxyhat.com:1080

Quando usare SOCKS5 invece di HTTP? SOCKS5 è utile quando il target ispeziona il protocollo del proxy o quando hai bisogno di tunneling TCP puro. Per la maggior parte degli scraper HTTP, la porta 8080 è sufficiente e più semplice da configurare. Consulta la documentazione ProxyHat per i dettagli completi.

Esempio Node completo: rotazione residenziale con retry hooks

Vediamo un esempio production-ready che combina got-scraping, proxy residenziali ProxyHat con rotazione per-request, e retry hooks personalizzati. Generiamo username unici per ogni richiesta usando un contatore e un UUID breve, garantendo che ogni richiesta esca da un IP residenziale diverso:

import { gotScraping } from 'got-scraping';
import { randomUUID } from 'node:crypto';
import pLimit from 'p-limit';

const PROXYHAT_USER = 'your_account';
const PROXYHAT_PASS = 'your_password';

function buildProxyUrl(country = 'US') {
  const session = randomUUID().slice(0, 8);
  const username = `${PROXYHAT_USER}-country-${country}-session-${session}`;
  return `http://${username}:${PROXYHAT_PASS}@gate.proxyhat.com:8080`;
}

const client = gotScraping.extend({
  headerGeneratorOptions: {
    browsers: [{ name: 'chrome', minVersion: 120, httpVersion: '2' }],
    devices: ['desktop'],
    operatingSystems: ['windows', 'macos'],
    locales: ['en-US', 'en'],
  },
  retry: {
    limit: 4,
    statusCodes: [403, 429, 500, 502, 503],
    maxRetryAfter: 10000,
  },
  timeout: { request: 20000 },
  hooks: {
    beforeRequest: [
      (options) => {
        // Rota il proxy ad ogni richiesta
        options.proxyUrl = buildProxyUrl('US');
      },
    ],
    afterResponse: [
      (response, retryWithMergedOptions) => {
        if (response.statusCode === 403) {
          // Cambia proxy e riproca
          retryWithMergedOptions({
            proxyUrl: buildProxyUrl('US'),
          });
        }
        return response;
      },
    ],
  },
});

async function fetchPage(url) {
  try {
    const res = await client(url, {
      responseType: 'json',
    });
    return res.body;
  } catch (err) {
    console.error(`Errore su ${url}: ${err.message}`);
    return null;
  }
}

// Concorrenza limitata a 10 richieste simultanee
const limit = pLimit(10);
const urls = [
  'https://api.example.com/items/1',
  'https://api.example.com/items/2',
  'https://api.example.com/items/3',
  // ...fino a N URL
];

const results = await Promise.all(
  urls.map((url) => limit(() => fetchPage(url)))
);

console.log(`Completate ${results.filter(Boolean).length} richieste su ${urls.length}`);

Il pattern chiave qui è l'hook beforeRequest: ad ogni richiesta, rigeneriamo il proxyUrl con una nuova sessione, ottenendo un IP residenziale diverso. L'hook afterResponse intercetta i 403 e cambia proxy prima del retry, invece di riprovare con lo stesso IP bloccato.

Pattern di produzione: concorrenza, cookie jar e Crawlee

Concorrenza limitata con p-limit

Lanciare 500 richieste in parallelo su un singolo proxy gateway è il modo più veloce per essere rate-limitati. Usa p-limit per mantenere la concorrenza tra 5 e 20 richieste simultanee, a seconda dei limiti del target. Per la maggior parte delle API REST pubbliche, 10 connessioni simultanee sono un buon punto di partenza. ProxyHat supporta 100+ sessioni concorrenti per piano, ma la risorsa limitante è spesso il server target, non il proxy.

Cookie jar per sessioni autenticate

Se il target richiede login o mantiene stato via cookie, usa tough-cookie con un jar per-sessione. Con got-scraping, puoi passare un cookieJar per richiesta:

import { CookieJar } from 'tough-cookie';

const jar = new CookieJar();

// Prima richiesta: ottieni il cookie di sessione
await client('https://example.com/login', {
  method: 'POST',
  json: { user: 'foo', pass: 'bar' },
  cookieJar: jar,
});

// Richieste successive: il cookie viene inviato automaticamente
const data = await client('https://example.com/dashboard', {
  cookieJar: jar,
  proxyUrl: buildProxyUrl('US'),
});

Associa ogni cookie jar a una sessione proxy sticky, in modo che l'IP e i cookie rimangano coerenti per tutta la durata della sessione.

Integrazione con Crawlee CheerioCrawler

Per scraper più strutturati, Crawlee di Apify offre CheerioCrawler, che usa got-scraping sotto il cofano. Puoi configurare il proxy a livello di crawler:

import { CheerioCrawler } from 'crawlee';

const crawler = new CheerioCrawler({
  requestHandler: async ({ $, request }) => {
    const title = $('title').text();
    console.log(`${request.url}: ${title}`);
  },
  proxyConfiguration: {
    newUrlFunction: () => buildProxyUrl('US'),
  },
  maxConcurrency: 10,
  requestHandlerTimeoutSecs: 30,
});

await crawler.run(['https://example.com/page1', 'https://example.com/page2']);

Crawlee gestisce automaticamente la coda delle richieste, i retry, la rotazione dei proxy e il rate limiting. È l'evoluzione naturale quando il tuo scraper supera le 100-200 URL e hai bisogno di gestione dello stato, deduplicazione e storage.

Quando un browser headless è inevitabile

Non tutto può essere scraper con richieste HTTP, anche con got-scraping. I casi in cui un browser headless (Playwright, Puppeteer) diventa necessario includono:

  • Rendering JavaScript lato client — il contenuto è generato dinamicamente e non esiste nell'HTML iniziale.
  • Challenge anti-bot interattivi — Cloudflare Turnstile, hCaptcha, o sfide che richiedono esecuzione JavaScript reale.
  • Interazioni complesse — scroll infinito, click su pulsanti, navigazione multi-step.

In questi casi, usa PlaywrightCrawler o PuppeteerCrawler di Crawlee con lo stesso proxy configuration. Il costo è significativo: un browser headless consuma 200-500 MB di RAM per istanza, rispetto ai 5-10 MB di una richiesta got-scraping. Per un fleet di 50 browser concorrenti, parliamo di 10-25 GB di RAM, contro meno di 1 GB per 50 richieste HTTP concorrenti.

Considerazioni etiche e legali

Lo scraping è uno strumento neutro, ma l'uso che ne fai no. Alcuni principi operativi:

  • Preferisci le API ufficiali quando disponibili. Molte piattaforme offrono API con rate limits generosi (es. 60 richieste/minuto su Twitter v2, 5000 richieste/ora su GitHub).
  • Rispetta robots.txt — è un segnale esplicito del proprietario del sito su cosa è permesso raccogliere.
  • Implementa rate limiting auto-imposto — anche se il server non lo impone, limita a 1-2 richieste/secondo per dominio.
  • Non raccogliere dati personali senza base giuridica valida sotto GDPR. I dati personali includono nomi, email, indirizzi IP (se associati a individui).
  • Memorizza solo ciò che ti serve e cancellalo quando non più necessario.

Per approfondire le best practice, consulta la nostra guida al web scraping e la pagina sulle locazioni proxy disponibili.

Key Takeaways

got-scraping risolve il problema degli header incoerenti generando set di header coerenti per browser/SO/dispositivo. Combinato con proxy residenziali ProxyHat su gate.proxyhat.com:8080, ottieni una fingerprint HTTP realistica e un IP a basso rischio. I pattern di produzione — beforeRequest per rotazione, afterResponse per retry con cambio proxy, p-limit per concorrenza limitata, cookie jar per sessioni — trasformano un prototipo in uno scraper affidabile. Quando il rendering JS è inevitabile, passa a Crawlee con Playwright, mantenendo lo stesso layer proxy.

FAQ

Cos'è got-scraping in Node.js?

got-scraping è un client HTTP per Node.js basato sulla libreria got, sviluppato da Apify. Integra un generatore di header coerenti (header-generator) che produce set di header plausibili per browser, sistemi operativi e dispositivi specifici. Supporta HTTP/2, proxy HTTP e SOCKS5, retry hooks e cookie jar. È progettato per ridurre le probabilità di rilevamento anti-bot rispetto a got o axios raw.

Perché got-scraping in Node.js è importante per chi usa proxy?

Anche con proxy residenziali di alta qualità, header incoerenti rivelano che la richiesta non proviene da un browser reale. got-scraping genera header nell'ordine corretto, include Client Hints come sec-ch-ua e usa HTTP/2, completando la fingerprint del proxy residenziale. Senza header coerenti, anche il miglior IP residenziale può ricevere un 403 in meno di 50 ms.

Quale tipo di proxy funziona meglio con got-scraping in Node.js?

I proxy residenziali sono la scelta ottimale perché hanno un punteggio di rischio IP basso nei sistemi anti-bot. I proxy datacenter vengono identificati facilmente dai CDN. I proxy mobili offrono il punteggio di rischio più basso ma hanno latenza più alta. Per la maggior parte dei casi d'uso, i residenziali su gate.proxyhat.com:8080 offrono il miglior rapporto tra tasso di successo e latenza.

Come evitare i blocchi con got-scraping in Node.js?

Combina tre livelli: header coerenti via headerGeneratorOptions, rotazione di IP residenziali con sessioni per-request, e rate limiting auto-imposto. Usa l'hook beforeRequest per cambiare proxy ad ogni richiesta e afterResponse per intercettare 403/429 e riprovare con un nuovo IP. Limita la concorrenza a 5-20 richieste simultanee con p-limit e mantieni i cookie coerenti con un cookie jar per sessione.

Pronto per iniziare?

Accedi a oltre 50M di IP residenziali in oltre 148 paesi con filtraggio AI.

Vedi i prezziProxy residenziali
← Torna al Blog