퍼피티어 사용자 에이전트 가이드: 설정 및 변경

Puppeteer에서 사용자 에이전트 설정 및 전환 기술을 숙달하여 웹 스크래핑 효율을 높이고 봇 방어 시스템을 우회하세요.
3 분 읽기
Puppeteer
User Agent Guide blog image

Puppeteer 사용자 에이전트 가이드에서는 다음을 확인할 수 있습니다:

  • 웹 스크래핑
  • Puppeteer에서 기본 사용자 에이전트 형식
  • 기본 Chrome 헤드리스 사용자 에이전트 재정의 방법
  • Puppeteer에서 사용자 에이전트 로테이션 구현 방법
  • Puppeteer Extra를 사용하여 사용자 에이전트 익명화하는 방법

자, 시작해 보겠습니다!

사용자 정의 사용자 에이전트를 설정해야 하는 이유

User-Agent 헤더는 클라이언트가 HTTP 요청을 통해 서버에 접속할 때 자신을 식별하기 위해 설정하는 문자열입니다. 일반적으로 요청이 발생한 기계 및/또는 애플리케이션에 대한 정보를 포함합니다. 이 헤더는 웹 브라우저, HTTP 클라이언트 또는 웹 요청을 수행하는 모든 소프트웨어에 의해 설정됩니다.

다음은 웹 페이지 요청 시 Chrome이 설정하는 사용자 에이전트 문자열의 예시입니다:

Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36

위 사용자 에이전트 문자열은 다음과 같은 구성 요소로 이루어져 있습니다:

  • Mozilla/5.0: 원래 Mozilla 브라우저와의 호환성을 나타내기 위해 사용되었으나, 현재는 더 넓은 호환성을 위해 포함됩니다.
  • Windows NT 10.0; Win64; x64: 운영 체제(Windows NT 10.0), 플랫폼(Win64), 시스템 아키텍처(x64)를 나타냅니다.
  • AppleWebKit/537.36: Chrome이 사용하는 브라우저 엔진을 나타냅니다.
  • (KHTML, like Gecko): KHTML 및 Gecko 레이아웃 엔진과의 호환성을 나타냅니다.
  • Chrome/127.0.0.0: 브라우저 이름과 버전을 지정합니다.
  • Safari/537.36: Safari와의 호환성을 나타냅니다.

기본적으로 사용자 에이전트 문자열은 요청이 잘 알려진 브라우저에서 오는지 아니면 다른 유형의 소프트웨어에서 오는지를 드러낼 수 있습니다.

대부분의 웹 스크래핑 봇과 자동화 스크립트가 저지르는 오류는 기본값이나 비(非) 브라우저 사용자 에이전트를 사용하는 것입니다. 이러한 값은 웹 페이지를 보호하기 위해 설계된 봇 방지 조치에 의해 쉽게 탐지될 수 있습니다. 서버는 User-Agent 헤더를 분석하여 요청이 자동화된 봇에서 온 것인지 여부를 판단할 수 있습니다.

자세한 내용은 웹 스크래핑용 사용자 에이전트 가이드를 참조하세요.

Puppeteer의 기본 사용자 에이전트는 무엇인가요?

Puppeteer는 실제 웹 브라우저의 특수 버전을 제어하여 브라우저 작업을 자동화합니다. 기본적으로 Firefox도 지원하지만 특정 버전의 Chrome을 실행합니다. 따라서 Puppeteer의 기본 사용자 에이전트가 제어되는 Chrome 버전에 설정된 것과 일치할 것이라고 생각할 수 있습니다. 하지만 그렇지 않습니다…

그 이유는 Puppeteer가 기본적으로 헤드리스 모드로 브라우저를 실행하기 때문입니다. 브라우저가 헤드리스 모드로 작동할 때는 일반적으로 고유한 사용자 에이전트를 설정합니다. 현재 버전 기준, 기본 Puppeteer 사용자 에이전트는 다음과 같습니다:

Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/127.0.0.0 Safari/537.3

헤드리스 모드에서 실행 중인 Chrome을 식별하는 HeadlessChrome 문자열에 주목하세요. 당연히 위 문자열은 최신 버전 헤드리스 Chrome의 사용자 에이전트와 정확히 일치합니다.

위 문자열이 실제로 Puppeteer의 기본 사용자 에이전트인지 확인하려면 스크립트를 설정하고 httpbin.io/user-agent 페이지로 이동하세요. 이 API 엔드포인트는 요청의 User-Agent 헤더를 반환하여 어떤 브라우저나 HTTP 클라이언트가 사용하는 사용자 에이전트를 확인할 수 있게 해줍니다.

Puppeteer 스크립트를 생성하고, 원하는 페이지를 방문한 후, 본문의 API 응답을 가져와 출력합니다:

import puppeteer from "puppeteer";

(async () => {

// 브라우저 실행 및 새 페이지 열기

const browser = await puppeteer.launch();

const page = await browser.newPage();

// 대상 페이지 연결

await page.goto("https://httpbin.io/user-agent");

// API 응답이 포함된 본문 텍스트 추출

// 출력

const bodyText = await page.evaluate(() => {

return document.body.innerText;

});

console.log(bodyText);

// 브라우저 닫기 및 리소스 해제

await browser.close();

})();

Puppeteer API에 대해 자세히 알아보려면 Puppeteer를 사용한 웹 스크래핑 가이드를 참조하세요.

위의 Node.js 코드를 실행하면 다음과 같은 문자열을 받게 됩니다:

{

"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/127.0.0.0 Safari/537.36"

}

Puppeteer가 설정한 사용자 에이전트가 앞서 제시된 문자열과 일치함을 확인하세요.

문제는 HeadlessChrome 식별자에 있으며, 이는 봇 방지 시스템에 경보를 유발할 수 있습니다. 이러한 시스템은 비정상적인 사용자 에이전트 문자열과 같이 봇 활동을 나타낼 수 있는 패턴을 찾아 들어오는 요청을 분석합니다. 의심스러운 요청은 표시되고 차단됩니다. 따라서 Puppeteer의 기본 사용자 에이전트 문자열을 수정하는 것이 매우 중요합니다!

Puppeteer 사용자 에이전트 변경 방법

사용자 에이전트 변경은 매우 흔하고 유용한 작업이라서, Puppeteer는 이를 위한 전용 메서드를 제공합니다. 특히 Page 클래스는 setUserAgent() 메서드를 노출합니다. 이를 통해 해당 브라우저 탭에서 웹 페이지로 이동할 때 Puppeteer가 설정하는 User-Agent를 수정할 수 있습니다.

아래와 같이 setUserAgent() 를 사용하여 Puppeteer 사용자 에이전트를 변경하세요:

await page.setUserAgent("<사용자_에이전트>");

이제 페이지 객체에 goto() 메서드를 호출하여 수행하는 모든 HTTP GET 요청에는 사용자 정의 User-Agent 헤더가 적용됩니다. 이 변경 사항은 특정 페이지 객체에만 적용된다는 점을 유의하세요. 새 페이지를 열고 상호작용할 경우, Puppeteer는 앞서 본 기본 사용자 에이전트를 사용합니다.

완전한 예제는 다음 코드 조각을 참고하세요:

import puppeteer from "puppeteer";

(async () => {

// 브라우저 실행 및 새 페이지 열기

const browser = await puppeteer.launch();

const page = await browser.newPage();

// 사용자 정의 User-Agent 설정

await page.setUserAgent("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36");

// 대상 페이지로 이동

await page.goto("https://httpbin.io/user-agent");

// API 응답으로 본문 텍스트 추출

// 출력

const bodyText = await page.evaluate(() => {

return document.body.innerText;

});

console.log(bodyText);

// 브라우저 닫기 및 리소스 해제

await browser.close();

})();

위 스크립트를 실행하면 이번에는 결과가 다음과 같습니다:

{

"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36"

}

훌륭합니다! 페이지에서 추출된 사용자 에이전트 문자열이 코드에 설정된 사용자 에이전트와 일치합니다. 이제 Puppeteer에서 사용자 에이전트 변경 작업을 수행하는 방법을 알게 되었습니다.

Puppeteer에서 사용자 에이전트 로테이션 구현하기

헤드리스 브라우저의 User-Agent 헤더를 비헤드리스 브라우저의 것으로 교체하는 것만으로는 봇 방지 시스템을 피하기에 충분하지 않을 수 있습니다. 문제는 브라우저 자동화 스크립트가 비인간적 행동을 나타내는 패턴을 보인다는 점입니다. 특히 동일한 IP 주소에서 동일한 헤더로 대량의 요청을 보낼 경우 더욱 그렇습니다.

Puppeteer에서 봇 탐지 위험을 최소화하려면 요청을 최대한 다양하게 만들어야 합니다. 효과적인 방법은 각 요청마다 다른 사용자 에이전트를 설정하는 것입니다. 이 전략을 사용자 에이전트 로테이션이라고 하며, 봇으로 표시될 가능성을 줄이는 데 도움이 됩니다.

다음 튜토리얼 섹션에서는 Puppeteer에서 사용자 에이전트 로테이션을 구현하는 방법을 배울 수 있습니다!

1단계: 무작위 사용자 에이전트 생성

무작위 사용자 에이전트를 얻는 주요 방법은 두 가지입니다. 첫 번째는 유효한 사용자 에이전트 목록을 확보한 후 목록에서 무작위로 하나를 선택하는 것으로, Node.js 사용자 에이전트 가이드에서 보여드린 바와 같습니다.

두 번째 방법은 타사 사용자 에이전트 생성기 라이브러리를 사용하는 것입니다. JavaScript에서 가장 널리 사용되는 것은 유효한 사용자 에이전트를 생성해 주는 user-agents 패키지입니다. 본 가이드에서는 이 방법을 따를 것입니다!

프로젝트의 종속성에 user-agents 라이브러리를 추가하려면 다음 npm 명령을 실행하세요:

npm install user-agents

user-agents는 매일 업데이트되어 항상 최신 사용자 에이전트를 포함합니다.

라이브러리 설치 후, Puppeteer 스크립트에 UserAgent 객체를 임포트하세요:

import UserAgent from "user-agents";

이제 다음 코드로 무작위 사용자 에이전트 문자열을 생성할 수 있습니다:

const userAgent = new UserAgent().random().toString();

특정 기기, 운영 체제 등에 대한 사용자 에이전트를 얻는 등 고급 사용법은 공식 문서를 참고하세요.

2단계: 무작위 사용자 에이전트 설정

setUserAgent() 메서드를 호출하여 무작위 사용자 에이전트 문자열을 Puppeteer에 전달하세요:

const userAgent = new UserAgent().random().toString();

await page.setUserAgent(userAgent);

이제 페이지 객체를 통해 수행되는 모든 요청에는 무작위로 생성된 사용자 정의 사용자 에이전트가 적용됩니다.

3단계: 대상 페이지 방문

헤드리스 브라우저에서 대상 웹페이지를 방문하려면 page 객체의 goto() 메서드를 호출하세요:

await page.goto("https://httpbin.io/user-agent");

단계 #4: 모든 것 통합하기

다음은 최종 Puppeteer 사용자 에이전트 로테이션 스크립트입니다:

import puppeteer from "puppeteer";

import UserAgent from "user-agents";

(async () => {

// 브라우저 실행 및 새 페이지 열기

const browser = await puppeteer.launch();

const page = await browser.newPage();

// 무작위 사용자 에이전트 생성

const userAgent = new UserAgent().random().toString();

// 무작위 사용자 에이전트 설정

await page.setUserAgent(userAgent);

// 대상 페이지로 이동

await page.goto("https://httpbin.io/user-agent");

// API 응답의 본문 텍스트 추출

// 출력

const bodyText = await page.evaluate(() => {

return document.body.innerText;

});

console.log(bodyText);

// 브라우저 닫기 및 리소스 해제

await browser.close();

})();

스크립트를 여러 번 실행하면 서로 다른 사용자 에이전트가 표시됩니다.

자, 이제 됐습니다! Puppeteer의 사용자 에이전트 로테이션 로직이 완벽하게 작동합니다.

puppeteer-extra-plugin-anonymize-ua를 사용한 Puppeteer 사용자 에이전트 설정

위에서 소개한 Puppeteer 사용자 에이전트 설정 방법은 효과적이지만, 한 가지 큰 단점이 있습니다. userAgent() 메서드는 특정 페이지 세션에서만 사용자 에이전트를 변경할 뿐, 모든 브라우저 탭에 걸쳐 적용되지는 않습니다.

Puppeteer가 기본 사용자 에이전트를 절대 사용하지 않도록 하려면 Puppeteer Extra의 puppeteer-extra-plugin-anonymize-ua 플러그인을 사용할 수 있습니다. 이 프로젝트에 익숙하지 않다면, Puppeteer Extra는 커뮤니티 정의 플러그인 지원을 추가하여 Puppeteer를 확장합니다. 자세한 내용은 Puppeteer Extra Stealth 플러그인 가이드에서 확인할 수 있습니다.

puppeteer-extra-plugin-anonymize-ua 플러그인은 Puppeteer가 설정한 사용자 에이전트를 익명화할 수 있습니다. puppeteer-extra와 필요한 플러그인을 설치하려면 다음 명령어를 실행하세요:

npm install puppeteer-extra puppeteer-extra-plugin-anonymize-ua

다음으로 puppeteer-extra 에서 puppeteer를, puppeteer-extra-plugin-anonymize-ua에서 AnonymizeUAPlugin을 임포트하세요:

import puppeteer from "puppeteer-extra";

import AnonymizeUAPlugin from "puppeteer-extra-plugin-anonymize-ua";

puppeteer-extra-plugin-anonymize-ua를 구성하여 임의의 사용자 에이전트를 생성하고, Puppeteer Extra의 use() 메서드를 사용하여 플러그인으로 등록합니다:

puppeteer.use(

AnonymizeUAPlugin({

customFn: () => new UserAgent().random().toString(),

})

);

이제 두 개의 별도 페이지 객체를 사용하여 두 개의 다른 탭에서 페이지를 방문해 보세요:

import puppeteer from "puppeteer-extra";

import AnonymizeUAPlugin from "puppeteer-extra-plugin-anonymize-ua";

import UserAgent from "user-agents";

(async () => {

// puppeteer-extra-plugin-anonymize-ua 플러그인 구성 및 등록

puppeteer.use(

AnonymizeUAPlugin({

customFn: () => new UserAgent().random().toString(),

})

);

// 브라우저 실행 및 새 페이지 열기

const browser = await puppeteer.launch();

// 새 페이지 열기

const page1 = await browser.newPage();

// 대상 페이지로 이동

await page1.goto("https://httpbin.io/user-agent");

// API 응답의 본문 텍스트 추출

// 및 출력

const bodyText1 = await page1.evaluate(() => {

return document.body.innerText;

});

console.log(bodyText1);

// 새 페이지 열기

const page2 = await browser.newPage();

// 대상 페이지 연결

await page2.goto("https://httpbin.io/user-agent");

// API 응답으로 본문 텍스트 추출

// 그리고 출력

const bodyText2 = await page2.evaluate(() => {

return document.body.innerText;

});

console.log(bodyText2);

// 브라우저 닫기 및 리소스 해제

await browser.close();

})();

결과는 아래와 같이 두 개의 서로 다른 사용자 에이전트가 됩니다:

{

"user-agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 17_5_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.5 Mobile/15E148 Safari/604.1"

}

{

"user-agent": "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Mobile Safari/537.36"

}

두 사용자 에이전트는 서로 다르며, 둘 다 Puppeteer의 기본 사용자 에이전트도 아닙니다. 이는 puppeteer-extra-plugin-anonymize-ua가 customFn 함수에 지정된 대로 각 페이지 객체를 무작위 사용자 에이전트로 커스터마이징하기 때문입니다. 이렇게 하면 Puppeteer가 기본 사용자 에이전트를 절대 노출하지 않습니다!

결론

이 글에서는 User-Agent 헤더 설정의 중요성을 살펴보고 기본 Puppeteer 사용자 에이전트의 모습을 확인했습니다. 기본값을 재정의하고 사용자 에이전트 로테이션을 구현하여 기본적인 스크래핑 방지 시스템을 회피하는 방법을 배웠습니다. 그러나 더 정교한 시스템은 여전히 자동화된 요청을 탐지하고 차단할 수 있습니다. IP 차단 방지를 위해 Puppeteer에서 프록시를 구성할 수 있지만, 그것조차 항상 충분하지 않을 수 있습니다!

더 효과적인 해결책으로 Scraping Browser를사용해 보세요—Puppeteer 및 기타 모든 브라우저 자동화 도구와 통합되는 차세대 브라우저입니다. Scraping Browser는 브라우저 지문 인식(fingerprinting)을 피하면서 안티봇 기술을 손쉽게 우회해 줍니다. 내부적으로는 사용자 에이전트 로테이션, IP 로테이션, CAPTCHA 해결 같은 기능을 활용합니다. 브라우저 자동화가 이토록 쉬웠던 적은 없습니다!

지금 가입하여 무료 체험을 시작하세요.