지식

Puppeteer에서 레지덴셜 프록시 사용하는 방법 (page.authenticate 포함)

Puppeteer의 프록시: 프록시는 launch args에, 인증 정보는 page.authenticate에 지정하며, 하나의 게이트웨이를 통해 페이지별 지역 로테이션과 리소스 차단을 수행합니다.

Chris Collins

Chris Collins

2026년 8월 5일 · 6 분 소요

Puppeteer는 실제 Chromium을 구동하며, 이는 대상 사이트가 JavaScript로 콘텐츠를 렌더링하거나, 데이터를 상호작용 뒤에 숨기거나, 실제 브라우저가 아닌 것을 핑거프린팅할 때 정확히 필요한 도구입니다. 레지덴셜 프록시를 추가하는 것은 몇 줄이면 되지만, Puppeteer는 이 작업을 서로 다른 두 곳으로 나누어야 해서 처음 접하는 거의 모든 사람이 실수하게 됩니다. 프록시 주소는 실행 인자에 들어가고, 자격 증명은 완전히 다른 곳에 들어갑니다.

이는 Playwright에서 레지덴셜 프록시 사용하기에 이어지는 Puppeteer 편입니다. 전체 브라우저가 아닌 일반 HTTP 클라이언트를 원한다면 Node.js에서 프록시 사용하기를 참고하세요. 여기서는 브라우저 특유의 함정에 집중합니다.

아래 내용은 모두 Shifter의 레지덴셜 게이트웨이를 기준으로 합니다. 엔드포인트는 p.shifter.io:443 하나이며, 모든 타겟팅 정보는 사용자 이름에 인코딩됩니다. 호스트와 자격 증명을 다른 제공업체 것으로 바꾸면 되며, 구조는 동일합니다.

게이트웨이 모델을 한 문단으로 정리하면

프록시 사용자 이름은 인증 정보 그리고 타겟팅 정보를 함께 담습니다. 국가나 세션을 바꾸기 위해 엔드포인트를 바꾸는 게 아니라, 사용자 이름 문자열을 바꿉니다.

customer-USERNAME-country-us-sid-abc123-ttl-600

country-us는 미국을 타겟팅하고, sid는 고정 세션을 지정하며, ttl은 해당 IP를 N초 동안 유지합니다. sid/ttl을 생략하면 모든 새 연결이 로테이션됩니다. 비밀번호는 계속 동일하게 유지됩니다. Puppeteer에서는 호스트가 실행 플래그에 들어가고, 그 사용자 이름은 page.authenticate에 들어갑니다.

설정: 실행 인자에 프록시, page.authenticate에 자격 증명

Chromium은 프록시 서버를 --proxy-server라는 명령줄 플래그로 받으며, 이는 Puppeteer의 args를 통해 전달됩니다. 여기에 user:pass@host 형식은 받아들이지 않습니다. Chromium은 이 플래그에서 자격 증명을 읽지 않습니다. 대신 page.authenticate를 통해 페이지별로 자격 증명을 제공하며, 이것이 프록시의 407 챌린지에 올바른 Proxy-Authorization으로 응답합니다.

import puppeteer from 'puppeteer';
const browser = await puppeteer.launch({
headless: true,
args: ['--proxy-server=http://p.shifter.io:443'], // host only, no credentials
});
const page = await browser.newPage();
await page.authenticate({
username: `${process.env.SHIFTER_USER}-country-us`, // targeting lives here
password: process.env.SHIFTER_PASS,
});
await page.goto('https://api.ipify.org');
console.log(await page.evaluate(() => document.body.innerText)); // a US residential IP
await browser.close();

숙지해야 할 두 가지가 있습니다. 사용자 이름에는 타겟팅 플래그(-country-us)가 포함되는데, 지역 정보가 URL이 아니라 여기에 있기 때문입니다. 그리고 인증이 필요한 프록시에서는 page.authenticate가 선택이 아닙니다. 이것 없이는 모든 탐색이 407에서 실패합니다. 호스트는 플래그에, 자격 증명은 page.authenticate에 나누어 넣는 이 구조가 Puppeteer 프록시 사용에서 가장 흔한 실수입니다.

하나의 게이트웨이로 지역과 세션 로테이션하기

이 설계의 유용한 결과가 여기 있습니다. 프록시 호스트는 브라우저 실행 시 고정되어 페이지별로 바꿀 수 없지만, 그럴 필요가 없습니다. 타겟팅 정보가 사용자 이름에 있고 page.authenticate는 페이지별로 설정되므로, 각 페이지에 다른 사용자 이름을 주면 같은 게이트웨이에서 다른 신원을 거쳐 라우팅됩니다. 브라우저 하나로 여러 지역을 다룰 수 있고, 재실행도 필요 없습니다.

async function pageFor(browser, country, sid) {
const page = await browser.newPage();
const user = `${process.env.SHIFTER_USER}-country-${country}`
+ (sid ? `-sid-${sid}-ttl-600` : '');
await page.authenticate({ username: user, password: process.env.SHIFTER_PASS });
return page;
}
const de = await pageFor(browser, 'de', 'job-42'); // German sticky session
const us = await pageFor(browser, 'us', null); // rotating US

논리적 작업 단위마다 각각의 sid를 부여하고 세션 중간이 아니라 단위 사이에서 로테이션하세요(고정 프록시와 로테이팅 프록시의 차이에서 이 구분을 다룹니다), 그리고 로드 밸런싱 게시물에서 설명하는 방식대로 작업을 신원에 매핑하세요. 신원 간 쿠키와 스토리지 격리를 위해서는 각각을 별도의 브라우저 컨텍스트에 배치하세요.

const context = await browser.createBrowserContext(); // isolated cookies/storage
const page = await context.newPage();
await page.authenticate({ username: userFor('gb'), password: pass });

이름을 주의하세요. 최근 Puppeteer 버전은 이를 createBrowserContext()라고 부르지만, 이전 버전은 createIncognitoBrowserContext()라고 불렀습니다. 같은 개념이며 이름만 바뀌었습니다.

함정 1: 브라우저를 재사용하고, 요청마다 새로 실행하지 마세요

Chromium을 실행하는 것은 무거운 작업입니다. 요청마다 새 브라우저를 실행하면 매번 수백 밀리초의 시작 오버헤드와 실제 메모리를 소모하게 되며, 이것이 지연 시간 가이드가 제거하려는 오버헤드입니다. 시작 시 브라우저를 하나 실행하고 재사용하며, 동시 작업을 위해 페이지나 컨텍스트를 열고 끝나면 닫으세요. 오래 살아있는 브라우저 하나 아래 페이지 풀을 두는 것이 올바른 구조입니다.

함정 2: 필요 없는 리소스는 차단하세요

브라우저는 실제 브라우저가 가져오는 모든 것, 즉 이미지, 폰트, 미디어, 스타일시트, 분석 스크립트까지 가져옵니다. HTML이나 몇몇 필드만 필요하다면, 이것은 낭비하는 대역폭이고 기다리는 시간입니다. Puppeteer는 요청을 가로채서 필요 없는 것을 중단시킬 수 있게 해주며, 이는 페이지 로드 시간과 대역폭 비용 모두를 상당히 줄여줍니다.

await page.setRequestInterception(true);
page.on('request', (req) => {
const blocked = ['image', 'font', 'media', 'stylesheet'];
if (blocked.includes(req.resourceType())) req.abort();
else req.continue();
});

선택적으로 적용하세요. 일부 사이트는 자신의 CSS나 특정 스크립트 없이는 원하는 콘텐츠를 렌더링하지 않으므로, 적극적으로 차단한 다음 데이터가 여전히 나타나는지 확인하세요. 나타난다면, 이것이 헤드리스 브라우저에서 얻을 수 있는 가장 저렴한 속도 향상입니다.

함정 3: 브라우저는 차단을 피하는 것의 절반일 뿐입니다

레지덴셜 IP는 사람처럼 보이는 것의 네트워크 측면 절반을 처리하지만, Puppeteer는 여전히 헤드리스 Chromium을 구동하고 있으며, 사이트는 브라우저도 핑거프린팅합니다. navigator.webdriver, 헤드리스 특유의 특이점, 자동화 신호 등입니다. 좋은 평판을 가진 깨끗한 IP는 많은 챌린지를 피하게 해주지만, 명백히 자동화된 브라우저를 숨겨주지는 않습니다. 오래되고 쉽게 탐지되는 방식이 아니라 최신 헤드리스 모드를 얻으려면 최신 Puppeteer와 Chromium을 사용하고, 뷰포트와 사용자 에이전트를 사실적으로 유지하며, 페이지를 사람 속도로 구동하세요. 탐지를 유발하는 실수들은 IP 계층만큼이나 브라우저 계층에도 적용되며, 둘은 서로 맞아야 합니다.

함정 4: 동시성에 한계를 두세요

열려 있는 페이지 하나하나가 실제 메모리를 차지하는 실제 브라우저 탭이므로, HTTP 요청을 쏘아 보내듯 수천 개를 열 수는 없습니다. 페이지나 컨텍스트의 풀을 제한된 크기로 유지하며 재사용하고, 대상 호스트별로 진행 중인 작업 수를 제한하여 취약한 사이트가 두들겨 맞는 동시에 관대한 사이트가 굶는 일이 없도록 하세요. 대상의 허용 범위를 넘는 병렬성은 처리량이 아니라 차단과 메모리 부족 크래시를 가져올 뿐입니다(차단을 피하는 방법).

실제로 프록시를 타고 있는지 확인하기

벤치마킹이나 다른 디버깅을 하기 전에, 페이지 내부에서 종료 IP를 확인하세요.

await page.goto('http://ip-api.com/json');
console.log(await page.evaluate(() => document.body.innerText)); // expect the targeted country

자신의 IP가 나온다면 --proxy-server 플래그가 적용되지 않았다는 의미입니다. 407 대화상자에서 멈춘다면 page.authenticate가 없거나 자격 증명이 잘못되었다는 의미입니다. 일반적으로 멈춘다면 로컬 아웃바운드가 차단된 것입니다. 이 세 가지 모두 타임아웃 진단 가이드에서 다룹니다.

FAQ

--proxy-serveruser:pass@host를 넣어도 왜 작동하지 않나요? Chromium은 --proxy-server 플래그에서 프록시 자격 증명을 읽지 않습니다. 거기에는 호스트만 전달하고, page.authenticate({ username, password })로 자격 증명을 제공해야 하며, 이것이 프록시의 407 챌린지를 처리합니다. 게이트웨이가 타겟팅 정보를 사용자 이름에 인코딩하므로, 전체 사용자 이름(-country-... 포함)이 page.authenticate에 들어갑니다.

프록시가 실행 시 설정되는데 페이지마다 다른 국가를 어떻게 사용하나요? 프록시 호스트를 바꾸는 게 아니라 page.authenticate 사용자 이름을 바꿉니다. 타겟팅 정보가 사용자 이름에 있고 게이트웨이 호스트는 고정이므로, 각 페이지는 다른 사용자 이름으로 인증하여 다른 신원을 통해 나갈 수 있습니다. 브라우저 하나로 여러 지역을 서비스할 수 있습니다.

브라우저를 재실행하지 않고 프록시를 로테이션할 수 있나요? 신원과 지역에 대해서는 가능합니다. 페이지나 컨텍스트별로 page.authenticate 사용자 이름을 바꾸면 됩니다. 진짜로 다른 프록시 호스트가 필요할 때만 재실행이 필요한데, 단일 게이트웨이 엔드포인트를 사용할 때는 그럴 필요가 없습니다.

Puppeteer에서 대역폭을 줄이려면 어떻게 하나요? 요청 가로채기를 활성화하고 필요 없는 리소스 유형(이미지, 폰트, 미디어, 종종 스타일시트)을 중단시키세요. 대상 사이트가 여전히 원하는 데이터를 렌더링하는지 확인한 다음 그 차단 설정을 유지하세요. 이것이 헤드리스 브라우저에서 속도와 비용 모두에 가장 큰 영향을 주는 단일 요소입니다.

Puppeteer냐 Playwright냐? 둘 다 실제 브라우저를 구동하며 둘 다 레지덴셜 프록시와 잘 작동합니다. Playwright는 프록시(자격 증명 포함)를 컨텍스트 옵션에서 직접 받고, Puppeteer는 실행 플래그와 page.authenticate로 나눕니다. 생태계 적합성과 기존 코드를 기준으로 선택하세요. 프록시 개념은 동일합니다.

결론

Puppeteer와 레지덴셜 프록시를 함께 쓰는 것은 이 구분이 이해되면 간단합니다. 프록시 호스트는 실행 시 --proxy-server에 들어가고, 사용자 이름에 타겟팅 정보를 담은 자격 증명은 페이지별로 page.authenticate에 들어갑니다. 브라우저를 재실행하는 대신 그 사용자 이름을 바꾸어 지역과 세션을 로테이션하고, 브라우저 컨텍스트로 신원을 격리하며, 오래 살아있는 브라우저 하나를 재사용하고, 필요 없는 리소스를 차단하며, 브라우저 핑거프린트도 IP만큼 사람처럼 보여야 한다는 것을 기억하세요.

이것만 제대로 해도 Puppeteer는 일반 HTTP 클라이언트가 처리할 수 없는 JavaScript가 많은 대상을 처리할 수 있습니다. 레지덴셜 게이트웨이를 겨냥하고, 풀의 품질이 얼마나 자주 챌린지를 받는지 결정한다는 것을 기억하세요(IP 평판). 가격 페이지에는 자신의 대상으로 테스트해볼 수 있는 GB당 요금제가 있습니다.

시작할 준비가 되셨나요?

205M개 이상의 IP, 195개 이상의 국가를 지원하는 Shifter의 레지덴셜 프록시를 $0.75/GB부터 이용해보세요.

시작하기