got-scraping nodejs로 차단을 우회하는 완벽한 가이드
Node.js 개발자라면 got-scraping이라는 이름을 들어본 적이 있을 것입니다. 이 라이브러리는 Apify가 got을 기반으로 만든 HTTP 클라이언트로, 브라우저와 거의 구별할 수 없는 요청을 생성하도록 설계되었습니다. 일반적인 got이나 axios 호출은 단 몇 번의 요청 만에 봇 감지 시스템에 노출되지만, got-scraping은 일관된 헤더 세트, HTTP/2 지원, 그리고 프록시 라우팅을 통해 그 간극을 메워줍니다.
이 글에서는 got-scraping을 프록시 미들웨어로 다루는 방법, ProxyHat 주거 프록시를 gate.proxyhat.com:8080에 연결하는 방법, 그리고 Crawlee로 확장하는 패턴까지 실전 코드와 함께 살펴봅니다.
법적 주의사항: 이 글은 공개 데이터 수집을 전제로 합니다. 미국의 CFAA(컴퓨터 사기 및 남용법)과 EU의 GDPR은 비공개 데이터나 ToS 위반 수집에 강력한 제재를 가할 수 있습니다. robots.txt를 준수하고, 속도 제한을 존중하며, 공식 API가 있다면 그것을 먼저 사용하세요.
왜 일반 got/axios 요청이 감지되는가
대부분의 스크래핑 차단은 TLS 지문, 헤더 순서, 그리고 IP 평판이라는 세 가지 축에서 발생합니다. 순수 got은 기본적으로 User-Agent 하나만 설정하면 끝이라고 착각하기 쉽지만, 현대 봇 감지 시스템은 훨씬 더 깊이 들여다봅니다.
- 헤더 순서: Chrome, Firefox, Safari는 각자 고유한 헤더 순서를 사용합니다.
accept가accept-encoding보다 먼저 오는지,sec-ch-ua가user-agent보다 먼저 오는지가 중요합니다. - sec-ch-ua 계열: Chromium 기반 브라우저는
sec-ch-ua,sec-ch-ua-mobile,sec-ch-ua-platform헤더를 보냅니다. 이 값들이user-agent와 일치하지 않으면 즉시 의심을 받습니다. - accept-language 일관성:
en-US,en;q=0.9같은 값이 IP의 지역과 어울리지 않으면 신호가 됩니다. - HTTP/2 사용 여부: 실제 Chrome은 HTTP/2를 사용하지만, 많은 스크래퍼가 여전히 HTTP/1.1로 요청을 보냅니다.
got-scraping의 header-generator는 이 문제를 근본적으로 해결합니다. 브라우저, 운영체제, 기기 조합을 입력하면 그에 맞는 일관된 헤더 세트 전체를 생성합니다. 단순히 user-agent만 바꾸는 것이 아니라, accept, accept-encoding, accept-language, sec-ch-ua 계열, upgrade-insecure-requests까지 브라우저 프로필에 맞춰 정확한 순서로 배치합니다.
이것이 got scraping header generator가 다른 헤더 위장 기법보다 신뢰할 수 있는 이유입니다. 직접 헤더를 하드코딩하면 한 글자만 틀려도 지문이 어긋나지만, header-generator는 수천 개의 실제 브라우저 프로필을 기반으로 일관성을 보장합니다.
got-scraping의 관용적 사용법
got-scraping은 got의 확장이므로, got의 모든 옵션을 그대로 사용할 수 있습니다. 핵심은 got.extend()로 커스텀 인스턴스를 만들고 useHeaderGenerator 옵션을 켜는 것입니다.
기본 인스턴스 구성
import { gotScraping } from 'got-scraping';
import { HeaderGenerator } from 'got-scraping';
const headerGenerator = new HeaderGenerator({
browsers: ['chrome'],
devices: ['desktop'],
operatingSystems: ['windows', 'macos'],
});
const client = gotScraping.extend({
useHeaderGenerator: true,
headerGeneratorOptions: {
browsers: ['chrome'],
devices: ['desktop'],
operatingSystems: ['windows', 'macos'],
},
http2: true,
timeout: { request: 30000 },
retry: { limit: 3 },
});
headerGeneratorOptions는 HeaderGenerator 생성자와 동일한 스키마를 받습니다. browsers, devices, operatingSystems 배열을 조합해 원하는 브라우저 프로필을 만듭니다. http2: true는 가능한 경우 HTTP/2를 사용하도록 강제합니다.
proxyUrl 옵션
got-scraping은 proxyUrl 옵션을 통해 HTTP/1.1과 HTTP/2 프록시를 모두 지원합니다. 이 옵션은 got의 agent를 직접 만지는 것보다 훨씬 안전합니다. HTTP/2 프록시를 사용할 때는 proxyUrl이 https:// 스킴을 사용해야 하며, got-scraping이 자동으로 CONNECT 터널을 설정합니다.
const res = await client('https://example.com', {
proxyUrl: 'http://user-country-US:pass@gate.proxyhat.com:8080',
});
console.log(res.statusCode, res.body.slice(0, 200));
이것이 got-scraping proxy의 기본 형태입니다. proxyUrl에 ProxyHat 게이트웨이를 넣기만 하면 됩니다.
ProxyHat 주거 프록시로 라우팅하기
헤더와 TLS가 완벽해도 IP 평판이 나쁘면 차단은 피할 수 없습니다. 데이터센터 IP는 Cloudflare, Akamai, PerimeterX 같은 시스템에서 거의 즉시 플래그됩니다. 주거 프록시는 실제 ISP가 할당한 주거 IP를 사용하므로, 헤더와 IP가 일관된 지역을 가리킬 때 가장 강력한 조합이 됩니다.
ProxyHat 주거 프록시는 gate.proxyhat.com 게이트웨이를 통해 접근합니다. HTTP는 포트 8080, SOCKS5는 포트 1080을 사용합니다. 사용자 이름에 국가, 도시, 세션 플래그를 넣어 지역 타겟팅과 세션 고정을 제어합니다.
| 연결 유형 | URL 형식 | 사용 사례 |
|---|---|---|
| HTTP (기본) | http://user-country-US:pass@gate.proxyhat.com:8080 | 대부분의 HTTP/HTTPS 스크래핑 |
| HTTP + 세션 | http://user-country-US-session-abc123:pass@gate.proxyhat.com:8080 | 로그인 상태 유지, 다단계 폼 |
| HTTP + 도시 | http://user-country-DE-city-berlin:pass@gate.proxyhat.com:8080 | 지역별 가격/콘텐츠 차이 분석 |
| SOCKS5 | socks5://user-country-US:pass@gate.proxyhat.com:1080 | TCP 레벨 터널링, 특수 프로토콜 |
SOCKS5는 HTTP 프록시가 차단되는 일부 환경에서 유용하지만, 대부분의 웹 스크래핑에서는 HTTP 게이트웨이가 충분합니다. SOCKS5는 socks5:// 스키마를 사용하며 got-scraping의 proxyUrl에 그대로 넣을 수 있습니다.
const res = await client('https://example.com', {
proxyUrl: 'socks5://user-country-US:pass@gate.proxyhat.com:1080',
});
요청별 세션 회전 예제
이제 실제로 동작하는 Node.js 예제를 봅시다. 이 예제는 ProxyHat 사용자 이름을 요청마다 생성하고, got의 hooks로 재시도 로직을 추가합니다.
import { gotScraping } from 'got-scraping';
import { randomUUID } from 'node:crypto';
const PROXYHAT_USER = 'user';
const PROXYHAT_PASS = 'pass';
const GATEWAY = 'gate.proxyhat.com:8080';
function buildProxyUrl({ country = 'US', session } = {}) {
const sid = session ?? randomUUID().slice(0, 12);
const username = `${PROXYHAT_USER}-country-${country}-session-${sid}`;
const encoded = encodeURIComponent(username);
return `http://${encoded}:${PROXYHAT_PASS}@${GATEWAY}`;
}
const client = gotScraping.extend({
useHeaderGenerator: true,
headerGeneratorOptions: {
browsers: ['chrome'],
devices: ['desktop'],
operatingSystems: ['windows'],
},
http2: true,
timeout: { request: 30000 },
retry: { limit: 3, statusCodes: [403, 429, 500, 502, 503] },
hooks: {
beforeRequest: [
(options) => {
// 매 요청마다 새 세션 ID로 새 IP 할당
options.proxyUrl = buildProxyUrl({ country: 'US' });
},
],
afterResponse: [
async (response, retryWithMergedOptions) => {
if (response.statusCode === 403 || response.statusCode === 429) {
// IP가 차단된 것으로 보이면 새 세션으로 재시도
return retryWithMergedOptions({
proxyUrl: buildProxyUrl({ country: 'US' }),
});
}
return response;
},
],
},
});
// 사용 예
const targets = [
'https://example.com/page-1',
'https://example.com/page-2',
'https://example.com/page-3',
];
for (const url of targets) {
const res = await client(url);
console.log(res.statusCode, url, res.body.slice(0, 80));
}
beforeRequest 훅은 매 요청마다 proxyUrl을 새로 설정하므로, 각 요청이 다른 주거 IP에서 나갑니다. afterResponse 훅은 403/429를 받으면 새 세션으로 재시도합니다. 이 패턴은 nodejs scraping proxy 운영에서 가장 자주 쓰이는 형태입니다.
더 많은 엔드포인트 옵션은 ProxyHat 공식 문서에서 확인할 수 있습니다.
프로덕션 패턴
제한된 동시성
수백 개의 요청을 동시에 보내면 ProxyHat 게이트웨이는 잘 버텨도 타겟 서버가 막히거나 차단합니다. p-limit로 동시성을 묶으세요.
import pLimit from 'p-limit';
const limit = pLimit(20); // 동시 20개 요청
const results = await Promise.all(
urls.map((url) => limit(() => client(url)))
);
20~50 동시 요청이 주거 프록시 스크래핑의 무난한 시작점입니다. 응답 시간이 200ms 이하로 유지된다면 점차 올리되, 429 비율이 5%를 넘으면 줄이세요.
쿠키 jar
세션 고정이 필요한 경우 (예: 로그인 후 페이지네이션), cookieJar 옵션과 ProxyHat 세션 플래그를 함께 사용하세요. got은 tough-cookie 기반 jar를 지원합니다.
import { gotScraping } from 'got-scraping';
import { CookieJar } from 'tough-cookie';
const jar = new CookieJar();
const session = 'login-flow-001';
const proxyUrl = `http://${encodeURIComponent(
`user-country-US-session-${session}`
)}:pass@gate.proxyhat.com:8080`;
const client = gotScraping.extend({
cookieJar: jar,
useHeaderGenerator: true,
http2: true,
});
// 같은 세션 IP + 쿠키로 다단계 폼 진행
await client.post('https://example.com/login', {
proxyUrl,
json: { user: 'foo', pass: 'bar' },
});
await client.get('https://example.com/dashboard', { proxyUrl });
세션 ID가 같으면 ProxyHat은 같은 출구 IP를 유지하므로, 쿠키와 IP가 일관되게 유지됩니다.
Crawlee CheerioCrawler로 확장
수천 페이지를 크롤링해야 한다면 Crawlee의 CheerioCrawler가 자연스러운 다음 단계입니다. Crawlee는 got-scraping을 내부적으로 사용하므로, 프록시 설정이 그대로 적용됩니다.
import { CheerioCrawler } from 'crawlee';
const crawler = new CheerioCrawler({
useHeaderGenerator: true,
headerGeneratorOptions: {
browsers: ['chrome'],
devices: ['desktop'],
operatingSystems: ['windows'],
},
proxyConfiguration: {
newUrlFunction: () =>
`http://${encodeURIComponent(
`user-country-US-session-${randomUUID().slice(0, 12)}`
)}:pass@gate.proxyhat.com:8080`,
},
maxConcurrency: 20,
requestHandler: async ({ $, request }) => {
const title = $('title').text();
console.log(request.url, title);
},
});
await crawler.run(['https://example.com/page-1', 'https://example.com/page-2']);
proxyConfiguration.newUrlFunction은 각 요청마다 새 프록시 URL을 반환합니다. 이것이 Crawlee에서 got-scraping proxy를 회전시키는 관용적 방법입니다.
컨테이너화
스케일아웃이 필요하면 각 컨테이너가 독립적인 세션 풀을 가지도록 설계하세요. 예를 들어 10개 컨테이너가 각각 50 동시 요청을 처리하면 총 500 동시 세션이 됩니다. 컨테이너 간 세션 ID 충돌을 피하려면 호스트명이나 컨테이너 ID를 세션 접두사로 사용하세요.
const containerId = process.env.HOSTNAME ?? 'local';
const session = `${containerId}-${randomUUID().slice(0, 8)}`;
헤드리스 브라우저가 불가피한 순간
got-scraping은 강력하지만, 다음 상황에서는 한계가 있습니다.
- JavaScript 렌더링 필수: 콘텐츠가 클라이언트 사이드에서 로드되는 SPA.
- 복잡한 CAPTCHA: hCaptcha, reCAPTCHA v3가 챌린지를 강제하는 경우.
- 행동 지문: 마우스 이동, 스크롤 패턴을 검사하는 고급 시스템.
이때는 Playwright나 Puppeteer로 헤드리스 Chrome을 띄우고, ProxyHat 주거 프록시를 브라우저 수준에서 설정하세요. Crawlee의 PlaywrightCrawler는 got-scraping과 같은 proxyConfiguration 인터페이스를 사용하므로 전환 비용이 낮습니다.
다만 헤드리스 브라우저는 메모리와 CPU 비용이 got-scraping의 수십 배입니다. 가능하면 got-scraping으로 먼저 시도하고, 진짜 렌더링이 필요한 페이지만 헤드리스로 라우팅하는 하이브리드 전략이 비용 효율적입니다.
윤리와 컴플라이언스
기술적으로 가능하다고 해서 합법적인 것은 아닙니다. 스크래핑 전 다음을 확인하세요.
- 공개 데이터만: 로그인 없이 접근할 수 없는 페이지는 CFAA 위반 소지가 있습니다.
- GDPR: EU 거주자 개인 데이터를 수집하면 동의 기반 또는 정당한 이익 근거가 필요합니다.
- robots.txt:
Disallow된 경로는 수집하지 마세요. 법적 강제력은 약하지만, ToS 위반 주장의 근거가 됩니다. - 속도 제한: 타겟 서버에 부하를 주지 않는 속도를 유지하세요. 분당 60~600 요청이 일반적인 안전 범위입니다.
- 공식 API 우선: 공식 API가 있다면 스크래핑보다 안정적이고 합법적입니다.
핵심 요약
- got-scraping은 header-generator로 일관된 브라우저 헤더 세트를 생성하고 HTTP/2를 지원해 차단을 줄입니다.
got.extend()+useHeaderGenerator+headerGeneratorOptions가 관용적 구성 패턴입니다.- ProxyHat 주거 프록시는
gate.proxyhat.com:8080(HTTP) 또는:1080(SOCKS5)로 연결하며, 사용자 이름에 국가/세션 플래그를 넣습니다. beforeRequest훅에서 요청마다 새 세션 ID를 생성해 IP를 회전시키세요.- 동시성은
p-limit로 묶고, 대규모 크롤링은 CrawleeCheerioCrawler로 넘기세요. - 헤드리스 브라우저는 JavaScript 렌더링이 진짜 필요할 때만 사용하세요.
- 공개 데이터, robots.txt, 속도 제한을 존중하고 공식 API를 먼저 확인하세요.
ProxyHat 주거 프록시로 바로 시작하려면 프라이싱 페이지를 확인하고, 웹 스크래핑 사용 사례와 SERP 추적 사용 사례에서 더 많은 패턴을 살펴보세요. 사용 가능한 지역은 위치 페이지에서 확인할 수 있습니다.
자주 묻는 질문
got-scraping in Node.js란 무엇인가요?
got-scraping은 Apify가 got를 기반으로 만든 HTTP 클라이언트로, 브라우저와 구별하기 어려운 요청을 생성하도록 설계되었습니다. 핵심은 header-generator가 일관된 헤더 세트(순서, sec-ch-ua, accept-language)를 생성하고, HTTP/2를 지원하며, proxyUrl 옵션으로 프록시 라우팅을 단순화한다는 점입니다. 일반 got나 axios와 달리 봇 감지 시스템을 통과하기 위한 기본 기능이 내장되어 있습니다.
프록시 사용자에게 got-scraping이 왜 중요한가요?
헤더와 TLS 지문이 브라우저와 일치하지 않으면, 아무리 좋은 주거 프록시를 써도 차단됩니다. got-scraping은 헤더 일관성을 자동으로 보장하므로, 프록시 IP 평판이 헤더 프로필과 어긋나서 발생하는 불필요한 차단을 줄여줍니다. 결과적으로 주거 프록시 투자 대비 성공률이 크게 올라갑니다.
got-scraping에 어떤 프록시 유형이 가장 적합한가요?
주거 프록시가 가장 적합합니다. 데이터센터 IP는 Cloudflare, Akamai 같은 시스템에서 즉시 플래그되는 반면, 주거 IP는 실제 ISP 할당이므로 헤더와 IP 지역이 일치할 때 가장 자연스럽습니다. ProxyHat 주거 프록시는 gate.proxyhat.com:8080(HTTP) 또는 :1080(SOCKS5)로 연결하며, 사용자 이름에 국가와 세션 플래그를 넣어 지역 타겟팅과 세션 고정을 제어합니다.
got-scraping으로 차단을 피하려면 어떻게 하나요?
세 가지를 함께 사용하세요. 첫째, header-generator로 브라우저 프로필을 일관되게 생성합니다. 둘째, 주거 프록시로 IP 평판을 확보하고, 요청마다 세션 ID를 바꿔 IP를 회전시킵니다. 셋째, p-limit로 동시성을 20~50으로 묶고, got의 afterResponse 훅에서 403/429 응답을 새 세션으로 재시도합니다. 이 조합이 대부분의 중간 수준 봇 감지를 통과합니다.
got-scraping과 Crawlee는 어떤 관계인가요?
Crawlee는 Apify가 만든 크롤링 프레임워크로, CheerioCrawler와 PlaywrightCrawler 내부에서 got-scraping을 사용합니다. 따라서 got-scraping의 header-generator, proxyUrl, HTTP/2 지원이 Crawlee에 그대로 적용됩니다. 단일 페이지 요청은 got-scraping을 직접 쓰고, 수천 페이지 크롤링은 Crawlee로 넘어가는 것이 자연스러운 확장 경로입니다.






