Si has intentado hacer got-scraping en Node.js con got o axios puro y te has encontrado con respuestas 403, desafíos de CAPTCHA o bloqueos silenciosos, no estás solo. Los sitios modernos no solo inspeccionan tu User-Agent: analizan el orden de las cabeceras, las pistas sec-ch-ua, la huella TLS y la reputación de tu IP. got-scraping, el cliente HTTP de Apify basado en got, fue diseñado específicamente para resolver la mitad de esa ecuación — las cabeceras y el transporte — mientras que un got-scraping proxy residencial resuelve la otra mitad.
Esta guía es para desarrolladores que scrapean a escala en Node.js. Cubrimos el generador de cabeceras, la superficie idiomática de la API, el enrutamiento a través de proxies residenciales en gate.proxyhat.com:8080, un ejemplo completo con rotación y reintentos, y los patrones de producción que necesitas cuando pasas de prototipo a miles de peticiones por minuto.
Aviso legal y ético. Esta guía asume que recolectas datos públicos, respetas
robots.txt, los términos de servicio aplicables y normativas como el GDPR y la CFAA en EE. UU. Si un sitio ofrece una API oficial o datos abiertos, úsala primero. El scraping no exime de cumplir la ley.
Por qué las peticiones con got/axios puro son detectadas
Cuando usas got o axios sin personalización, tu petición HTTP/1.1 envía cabeceras en un orden predecible y minimalista: Host, User-Agent (a menudo got/14.4.5 o el de Node por defecto), Accept y poco más. Un navegador Chromium real, en cambio, envía más de una docena de cabeceras en un orden específico, incluyendo sec-ch-ua, sec-fetch-site, accept-language y priority. Los sistemas anti-bot como Cloudflare, Datadome y PerimeterX comparan tu conjunto de cabeceras con el esperado para tu User-Agent declarado. Si declaras Chrome pero no envías sec-ch-ua, la petición se marca como sospechosa en milisegundos.
El problema se agrava con TLS. La huella JA3/JA4 de tu handshake TLS depende de la librería subyacente. Node.js usa OpenSSL, que produce una huella distinta a la de Chrome. Aunque las cabeceras sean perfectas, un WAF avanzado puede comparar la huella TLS con el navegador declarado y bloquearte. Por eso, incluso con cabeceras impecables, necesitas un nodejs scraping proxy residencial para que, al menos, la reputación de la IP no te delate.
Los datos lo confirman: un estudio de ZenRows sobre evasión de Cloudflare muestra que la coherencia entre User-Agent, cabeceras y huella TLS es el factor número uno que determina si una petición pasa el desafío inicial. Y según la documentación de Crawlee, la gestión de proxies y cabeceras es la pieza más subestimada en pipelines de scraping de producción.
got-scraping y su generador de cabeceras: coherencia sin esfuerzo
got-scraping extiende got con un got scraping header generator que emite conjuntos de cabeceras coherentes para un navegador, dispositivo y sistema operativo determinados. No se trata de pegar un User-Agent estático: el generador produce todas las cabeceras que ese navegador enviaría, en el orden correcto, con valores consistentes entre sí. Si dices que eres Chrome 124 en Windows, el generador emite el sec-ch-ua correspondiente, el accept-language plausible y las cabeceras sec-fetch-* apropiadas.
Además, got-scraping soporta HTTP/2 de forma nativa. HTTP/2 permite multiplexar múltiples peticiones sobre una sola conexión TCP, reduciendo latencia y huella de conexión. Esto importa porque los WAF también observan patrones de conexión: abrir una nueva conexión TCP por cada petición es un comportamiento más típico de un script que de un navegador que reutiliza conexiones.
Superficie idiomática de la API
La API de got-scraping se construye sobre got.extend(), el mecanismo estándar de got para crear instancias con configuración compartida. Los puntos clave son:
useHeaderGenerator: activa el generador de cabeceras para que cada petición reciba un conjunto coherente.headerGeneratorOptions: define el perfil del navegador (browsers,devices,operatingSystems,locales).proxyUrl: soporta proxies HTTP/1.1 y HTTP/2, así como SOCKS5 con el prefijosocks5://.http2: habilita HTTP/2 cuando el servidor lo soporta.
Veamos la configuración base:
import { gotScraping } from 'got-scraping';
const client = gotScraping.extend({
useHeaderGenerator: true,
headerGeneratorOptions: {
browsers: ['chrome'],
devices: ['desktop'],
operatingSystems: ['windows', 'macos'],
locales: ['es-ES', 'en-US'],
},
http2: true,
timeout: { request: 30000 },
retry: { limit: 3 },
});
const res = await client.get('https://example.com');
console.log(res.statusCode, res.headers['content-type']);
Aquí cada petición recibe un User-Agent y un conjunto completo de cabeceras sec-ch-ua, accept-language y sec-fetch-* consistentes entre sí. El generador elige aleatoriamente dentro de las opciones que le diste, de modo que dos peticiones consecutivas pueden tener cabeceras ligeramente distintas — como ocurriría con navegadores reales.
Enrutando a través de proxies residenciales en ProxyHat
Las cabeceras resuelven la capa HTTP. La reputación de la IP resuelve la capa de red. Un got-scraping proxy residencial usa direcciones IP asignadas por ISPs a hogares reales, por lo que para un WAF son indistinguibles de un visitante legítimo. Los proxies datacenter, en cambio, provienen de rangos ASN conocidos (AWS, DigitalOcean, OVH) que muchos sitios bloquean por defecto o someten a desafíos adicionales.
ProxyHat expone un gateway único en gate.proxyhat.com con puerto 8080 para HTTP y 1080 para SOCKS5. El geo-targeting y el control de sesión se codifican en el nombre de usuario, lo que te permite rotar IPs por petición o mantener una sesión pegajosa sin cambiar la URL base.
| Parámetro | Formato | Ejemplo |
|---|---|---|
| HTTP proxy | http://USER:PASS@gate.proxyhat.com:8080 | Rotación automática por petición |
| SOCKS5 proxy | socks5://USER:PASS@gate.proxyhat.com:1080 | Útil para ciertos WAF que inspeccionan proxies HTTP |
| Geo-país | user-country-US | IP residencial de EE. UU. |
| Geo-ciudad | user-country-DE-city-berlin | Berlín, Alemania |
| Sesión pegajosa | user-session-abc123 | Mantiene la misma IP entre peticiones |
En got-scraping, pasas la URL del proxy a proxyUrl y la librería se encarga del resto, incluyendo el túnel CONNECT para HTTPS. Para SOCKS5, simplemente usa el prefijo socks5:// y got-scraping delegará en el agente SOCKS apropiado.
Ejemplo completo: rotación residencial con reintentos en Node.js
El siguiente ejemplo integra got-scraping con ProxyHat, rotando IPs residenciales de EE. UU. por petición mediante un identificador de sesión único. Cada petición genera un sessionId distinto, lo que fuerza una IP nueva sin perder la coherencia de cabeceras. El hook beforeRequest inyecta el proxy dinámicamente, y afterResponse comprueba si la respuesta indica un bloqueo para forzar un reintento.
import { gotScraping } from 'got-scraping';
import { randomUUID } from 'node:crypto';
const PROXYHAT_USER = process.env.PROXYHAT_USER;
const PROXYHAT_PASS = process.env.PROXYHAT_PASS;
function buildProxyUrl(sessionId, country = 'US') {
const username = `${PROXYHAT_USER}-country-${country}-session-${sessionId}`;
const auth = Buffer.from(`${username}:${PROXYHAT_PASS}`).toString('base64');
return `http://${username}:${PROXYHAT_PASS}@gate.proxyhat.com:8080`;
}
const scraper = gotScraping.extend({
useHeaderGenerator: true,
headerGeneratorOptions: {
browsers: ['chrome'],
devices: ['desktop'],
operatingSystems: ['windows'],
locales: ['en-US'],
},
http2: true,
timeout: { request: 30000 },
retry: { limit: 4, statusCodes: [403, 429, 500, 502, 503] },
hooks: {
beforeRequest: [
(options) => {
const sessionId = randomUUID().slice(0, 8);
options.proxyUrl = buildProxyUrl(sessionId);
},
],
afterResponse: [
(response, retryWithMergedOptions) => {
const body = response.body?.toLowerCase?.() ?? '';
if (
response.statusCode === 403 ||
body.includes('captcha') ||
body.includes('access denied')
) {
return retryWithMergedOptions({
proxyUrl: buildProxyUrl(randomUUID().slice(0, 8)),
});
}
return response;
},
],
},
});
const res = await scraper.get('https://example.com');
console.log(res.statusCode, res.body.slice(0, 120));
El hook beforeRequest construye una URL de proxy nueva en cada intento, forzando rotación. El hook afterResponse detecta bloqueos por contenido o por código de estado y reintenta con una IP distinta. Esta combinación de cabeceras coherentes + IP residencial fresca por intento es lo que maximiza la tasa de éxito frente a WAFs agresivos.
Para SOCKS5, sustituye la URL del proxy por socks5://USERNAME:PASSWORD@gate.proxyhat.com:1080. Algunos sitios inspeccionan proxies HTTP intermedios; SOCKS5 opera a nivel de transporte y puede evadir esa inspección, a costa de una ligera sobrecarga.
Patrones de producción: concurrencia, cookies y Crawlee
Concurrencia limitada con p-limit
Abrir 1000 peticiones simultáneas agota los sockets de Node, dispara rate limits del destino y satura tu pool de proxies. p-limit te permite fijar un techo de concurrencia razonable — típicamente entre 20 y 50 peticiones en vuelo — sin perder paralelismo.
import pLimit from 'p-limit';
const limit = pLimit(30);
const urls = ['https://example.com/a', 'https://example.com/b', /* ... */];
const results = await Promise.all(
urls.map((url) => limit(() => scraper.get(url).then((r) => r.body).catch((e) => null)))
);
Cookies persistentes con cookie jars
Muchos sitios requieren mantener cookies entre peticiones — tokens anti-bot, tokens de sesión, cookies de preferencia. got soporta tough-cookie de forma nativa mediante la opción cookieJar. Puedes compartir un jar entre peticiones que pertenezcan a la misma sesión lógica.
import { CookieJar } from 'tough-cookie';
const jar = new CookieJar();
const sessionClient = scraper.extend({ cookieJar: jar });
await sessionClient.get('https://example.com/login');
await sessionClient.post('https://example.com/api', { json: { q: 'test' } });
Integración con Crawlee y CheerioCrawler
Cuando tu scraping crece más allá de un puñado de endpoints, Crawlee — del mismo equipo que got-scraping — ofrece colas de URLs, gestión de proxies, deduplicación y extracción con Cheerio. CheerioCrawler usa got-scraping por debajo, por lo que heredas cabeceras coherentes y HTTP/2 gratis.
import { CheerioCrawler, ProxyConfiguration } from 'crawlee';
const proxyConfiguration = new ProxyConfiguration({
proxyUrls: [
`http://${process.env.PROXYHAT_USER}-country-US-session-s1:${process.env.PROXYHAT_PASS}@gate.proxyhat.com:8080`,
`http://${process.env.PROXYHAT_USER}-country-US-session-s2:${process.env.PROXYHAT_PASS}@gate.proxyhat.com:8080`,
],
});
const crawler = new CheerioCrawler({
proxyConfiguration,
maxConcurrency: 30,
requestHandler: async ({ $, request }) => {
const title = $('title').text();
console.log(request.url, title);
},
});
await crawler.run(['https://example.com/page1', 'https://example.com/page2']);
Crawlee rota entre las URLs de proxy que le pasas, reintenta automáticamente y gestiona la cola de peticiones. Es el siguiente paso natural cuando pasas de un script a un pipeline de scraping de producción. Consulta más detalles sobre nuestra infraestructura de proxies en /es/locations y sobre casos de uso en /es/use-cases/web-scraping y /es/use-cases/serp-tracking.
Cuándo un navegador headless es inevitable (y cuándo no)
got-scraping resuelve la capa HTTP, pero no ejecuta JavaScript. Si el sitio renderiza contenido crítico en el cliente — SPAs con React/Vue, contenido detrás de un desafío JS complejo, o huellas de canvas/WebGL — necesitarás un navegador headless como Playwright o Puppeteer. La regla práctica: intenta primero con got-scraping + proxies residenciales; si el contenido no aparece en el HTML inicial, entonces escala a headless.
Un navegador headless consume entre 150 y 300 MB de RAM por instancia, frente a los ~5 MB de un proceso got-scraping. Para fleet a escala, conteneriza con Docker y orquesta con Kubernetes, limitando el número de pestañas concurrentes por instancia. Puedes seguir usando proxies residenciales de ProxyHat dentro de Playwright mediante context.route() o el parámetro --proxy-server de Chromium, apuntando a gate.proxyhat.com:8080.
Consideraciones éticas y legales
Antes de lanzar cualquier crawler a escala, revisa estos puntos:
- Robots.txt. Léelo y respétalo. Es una señal de cortesía, pero también puede ser considerado en disputas legales.
- Términos de servicio. Algunos sitios prohíben explícitamente el scraping. Violar los ToS puede tener consecuencias bajo la CFAA en EE. UU. o cláusulas contractuales en la UE.
- GDPR y CCPA. Si recolectas datos personales de usuarios europeos o californianos, aplica los principios de minimización y propósito del Artículo 5 del GDPR.
- Rate limits. Limita tu concurrencia para no degradar el servicio del objetivo. Un buen vecino del scraping no satura el servidor.
- APIs oficiales primero. Si el sitio ofrece una API pública o datos abiertos, úsala. Es más estable, más rápido y legalmente más seguro.
Para más detalles técnicos sobre configuración de proxies, consulta la documentación oficial de ProxyHat y nuestra página de precios.
Puntos clave
Key Takeaways
- got-scraping en Node.js resuelve la coherencia de cabeceras y HTTP/2; un proxy residencial resuelve la reputación de IP. Necesitas ambos para evadir WAFs modernos.
- El got scraping header generator emite conjuntos completos y consistentes (
sec-ch-ua,accept-language,sec-fetch-*) para el navegador declarado, eliminando la principal causa de bloqueos a nivel HTTP.- Usa
gate.proxyhat.com:8080para HTTP y:1080para SOCKS5, con geo-targeting y sesión en el nombre de usuario.- Limita la concurrencia con
p-limit(20–50), persiste cookies contough-cookie, y escala a Crawlee cuando necesites colas y deduplicación.- Reserva el navegador headless para contenido que requiere ejecución JS; consume 30–60× más memoria por instancia.
- Respeta
robots.txt, ToS, GDPR/CFAA y los rate limits del objetivo. Prefiere siempre APIs oficiales cuando existan.
Preguntas frecuentes
¿Qué es got-scraping en Node.js?
got-scraping es un cliente HTTP para Node.js construido por Apify sobre la librería got. Añade un generador de cabeceras que produce conjuntos coherentes de cabeceras de navegador (User-Agent, sec-ch-ua, accept-language, sec-fetch-*), soporte nativo de HTTP/2 y una opción proxyUrl que acepta proxies HTTP y SOCKS5. Está diseñado específicamente para scraping, a diferencia de got o axios puro, que envían cabeceras minimalistas fácilmente detectables por WAFs.
¿Por qué importa got-scraping en Node.js para usuarios de proxies?
Porque las cabeceras y la IP son las dos capas que los WAFs inspeccionan. Un proxy residencial con buena reputación es inútil si tus cabeceras delatan que eres un script. got-scraping garantiza que tus cabeceras sean coherentes con un navegador real, mientras que el proxy residencial garantiza que tu IP no pertenezca a un ASN bloqueado. Ambos componentes son complementarios, no sustitutivos.
¿Qué tipo de proxy funciona mejor con got-scraping en Node.js?
Los proxies residenciales son los más efectivos para scraping general, porque provienen de rangos IP asignados por ISPs a hogares reales y tienen alta reputación. Los proxies datacenter son más rápidos y baratos, pero muchos sitios los bloquean o someten a desafíos adicionales. Los proxies móviles ofrecen la máxima reputación pero a mayor coste. Para la mayoría de casos, residenciales con rotación por sesión ofrecen el mejor equilibrio entre éxito, velocidad y precio.
¿Cómo evitas bloqueos al implementar got-scraping en Node.js?
Combina cabeceras coherentes del generador, rotación de IPs residenciales por petición o por sesión, reintentos en códigos 403/429, concurrencia limitada (20–50 peticiones), cookies persistentes cuando el sitio lo requiera y respeto a robots.txt y rate limits. Usa el hook afterResponse para detectar respuestas de bloqueo por contenido y forzar un reintento con una IP nueva. Si el sitio requiere ejecución de JavaScript, escala a un navegador headless con Playwright.
¿Puedo usar SOCKS5 con got-scraping y ProxyHat?
Sí. got-scraping soporta el prefijo socks5:// en proxyUrl. En ProxyHat, usa socks5://USERNAME:PASSWORD@gate.proxyhat.com:1080. SOCKS5 opera a nivel de transporte y puede evadir la inspección de proxies HTTP intermedios que algunos WAFs realizan, aunque con una ligera sobrecarga respecto a HTTP.






