블로그로 돌아가기

헤드리스 브라우저 감지 우회 방법: 셀레니움 및 퍼피티어를 이용한 마스킹

헤드리스 브라우저의 보호를 우회하는 방법을 알아보세요: Selenium, Puppeteer 및 Playwright의 마스킹 기술과 코드 예제 및 프록시 설정.

📅2026년 1월 10일
```html

현대 웹사이트는 자동화된 브라우저(Selenium, Puppeteer, Playwright)를 인식하고 이들의 요청을 차단하는 방법을 배웠습니다. 헤드리스 브라우저는 수십 개의 디지털 흔적을 남기며, 이를 통해 안티봇 시스템은 밀리초 만에 자동화를 감지합니다. 이 가이드에서는 Python과 JavaScript로 작성된 코드 예제를 통해 헤드리스 브라우저를 마스킹하는 모든 방법을 살펴보아, 여러분의 파서가 차단 없이 안정적으로 작동하도록 도와드리겠습니다.

이 기사는 웹 스크래핑, 테스트 자동화 또는 보호된 웹사이트에서 데이터 수집을 수행하는 개발자를 위해 작성되었습니다. 우리는 감지의 기술적 세부 사항과 보호 우회를 위한 실용적인 솔루션을 다룰 것입니다.

웹사이트가 헤드리스 브라우저를 감지하는 방법: 주요 방법

안티봇 시스템은 브라우저를 다단계로 확인하며 수백 개의 매개변수를 분석합니다. 헤드리스 브라우저는 일반 브라우저와 여러 가지 특징이 다르며, 이는 단순히 User-Agent를 변경하는 것으로 숨길 수 없습니다. 감지 방법을 이해하는 것은 효과적인 마스킹의 첫 번째 단계입니다.

자동화 JavaScript 마커

가장 일반적인 방법은 자동화된 브라우저에서만 나타나는 JavaScript 속성을 확인하는 것입니다:

  • navigator.webdriver — Selenium 및 Puppeteer에서 true를 반환합니다.
  • window.chrome — 헤드리스 Chrome에서는 존재하지 않습니다.
  • navigator.plugins.length — 헤드리스 모드에서는 0입니다.
  • navigator.languages — 종종 빈 배열이거나 "en-US"만 포함합니다.
  • navigator.permissions — API는 헤드리스 모드에서 다르게 작동합니다.

Chrome DevTools 프로토콜 분석

Puppeteer와 Playwright는 Chrome DevTools 프로토콜(CDP)을 통해 브라우저를 제어합니다. CDP 연결의 존재는 window.cdc_ 객체를 분석하거나 마우스 및 키보드 이벤트의 비정상적인 행동을 확인하는 특별한 JavaScript 검사를 통해 감지할 수 있습니다.

Canvas 및 WebGL 지문

헤드리스 브라우저는 하드웨어 대신 소프트웨어 렌더링을 사용하기 때문에 동일한 Canvas 및 WebGL 지문을 생성합니다. 안티봇 시스템은 보이지 않는 Canvas 요소를 생성하고 그 위에 텍스트나 도형을 그린 후 이미지 해시를 계산합니다. 수천 명의 사용자가 동일한 해시를 가지면 이는 봇의 징후입니다.

행동 분석

현대 시스템(DataDome, PerimeterX, Cloudflare Bot Management)은 마우스 움직임, 스크롤 속도, 클릭 패턴을 분석합니다. 헤드리스 브라우저는 즉각적으로 행동을 수행하며 자연스러운 지연이 없기 때문에 자동화를 드러냅니다. 또한 이벤트가 분석됩니다: 일반 브라우저에서는 클릭 전에 항상 mousemove 이벤트가 발생하지만, 봇은 종종 마우스 움직임 없이 클릭합니다.

중요: 현대의 안티봇 시스템은 기계 학습을 사용하여 수백 개의 매개변수를 동시에 분석합니다. 단일 매개변수(예: User-Agent)만 마스킹하는 것은 차단으로부터 보호하지 않으며, 종합적인 접근이 필요합니다.

navigator.webdriver 및 기타 JavaScript 마커 제거

navigator.webdriver 속성은 Selenium 및 기타 WebDriver 도구를 감지하는 가장 간단한 방법입니다. 일반 브라우저에서는 이 속성이 undefined를 반환하지만, 자동화된 브라우저에서는 true를 반환합니다. 페이지 로드 전에 JavaScript 코드를 실행하여 이를 제거할 수 있습니다.

Selenium (Python): CDP를 통한 webdriver 제거

Selenium에서는 페이지 로드 전에 JavaScript를 실행하기 위해 Chrome DevTools 프로토콜을 사용해야 합니다:

from selenium import webdriver
from selenium.webdriver.chrome.options import Options

options = Options()
options.add_argument('--disable-blink-features=AutomationControlled')

driver = webdriver.Chrome(options=options)

# CDP를 통한 navigator.webdriver 제거
driver.execute_cdp_cmd('Page.addScriptToEvaluateOnNewDocument', {
    'source': '''
        Object.defineProperty(navigator, 'webdriver', {
            get: () => undefined
        });
    '''
})

driver.get('https://example.com')

--disable-blink-features=AutomationControlled 옵션은 Chrome이 자동화 모드에서 추가하는 플래그를 비활성화합니다. 이는 기본적인 보호로, 다른 방법과 결합해야 합니다.

Puppeteer (Node.js): Page.evaluateOnNewDocument를 통한 마스킹

Puppeteer에서는 페이지 로드 전에 코드를 실행하기 위해 page.evaluateOnNewDocument() 메서드를 사용합니다:

const puppeteer = require('puppeteer');

(async () => {
    const browser = await puppeteer.launch({
        headless: true,
        args: ['--disable-blink-features=AutomationControlled']
    });
    
    const page = await browser.newPage();
    
    // webdriver 및 기타 마커 제거
    await page.evaluateOnNewDocument(() => {
        Object.defineProperty(navigator, 'webdriver', {
            get: () => undefined
        });
        
        // chrome 객체 추가
        window.chrome = {
            runtime: {}
        };
        
        // 플러그인 에뮬레이션
        Object.defineProperty(navigator, 'plugins', {
            get: () => [1, 2, 3, 4, 5]
        });
    });
    
    await page.goto('https://example.com');
})();

Playwright: 내장된 마스킹 옵션

Playwright는 기본적으로 더 발전된 마스킹 기능을 제공하지만, 추가 설정이 여전히 필요합니다:

const { chromium } = require('playwright');

(async () => {
    const browser = await chromium.launch({
        headless: true,
        args: ['--disable-blink-features=AutomationControlled']
    });
    
    const context = await browser.newContext({
        userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
    });
    
    const page = await context.newPage();
    
    await page.addInitScript(() => {
        Object.defineProperty(navigator, 'webdriver', {
            get: () => undefined
        });
    });
    
    await page.goto('https://example.com');
})();

Chrome DevTools 프로토콜 마스킹

Puppeteer와 Playwright는 CDP 연결의 흔적을 남기며, 이는 window 객체를 분석하여 감지할 수 있습니다. 안티봇 시스템은 DevTools 프로토콜을 통해 연결할 때 Chrome이 생성하는 cdc_, $cdc_ 또는 __webdriver_ 접두사가 붙은 변수를 찾습니다.

CDP 변수 제거

다음 스크립트는 window 객체에서 자동화와 관련된 모든 변수를 제거합니다:

await page.evaluateOnNewDocument(() => {
    // cdc_ 접두사가 붙은 모든 변수 제거
    const cdcProps = Object.keys(window).filter(prop => 
        prop.includes('cdc_') || 
        prop.includes('$cdc_') || 
        prop.includes('__webdriver_')
    );
    
    cdcProps.forEach(prop => {
        delete window[prop];
    });
    
    // CDP 숨기기를 위한 document.__proto__ 재정의
    const originalQuery = document.querySelector;
    document.querySelector = function(selector) {
        if (selector.includes('cdc_')) return null;
        return originalQuery.call(this, selector);
    };
});

패치된 Chromium 버전 사용

CDP 흔적을 남기지 않는 수정된 Chromium 빌드가 있습니다. 예를 들어, puppeteer-extra 라이브러리와 puppeteer-extra-plugin-stealth 플러그인은 CDP 마스킹을 위해 수십 개의 패치를 자동으로 적용합니다.

User-Agent 및 HTTP 헤더 설정

헤드리스 브라우저는 구식이거나 비현실적인 User-Agent 문자열을 사용합니다. 예를 들어, Puppeteer는 기본적으로 User-Agent에 "HeadlessChrome"이라는 단어를 추가합니다. 또한 일반 브라우저 요청에 존재하는 추가 헤더를 설정해야 합니다.

마스킹을 위한 최신 User-Agent

실제 브라우저의 최신 User-Agent를 사용하세요. 2024년의 예시는 다음과 같습니다:

# Windows 10의 Chrome 120
Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36

# macOS의 Chrome 120
Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36

# Windows의 Firefox 121
Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:121.0) Gecko/20100101 Firefox/121.0

Selenium에서 헤더 설정

from selenium.webdriver.chrome.options import Options

options = Options()
options.add_argument('user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36')

# CDP를 통한 추가 헤더
driver.execute_cdp_cmd('Network.setUserAgentOverride', {
    "userAgent": 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
    "platform": 'Win32',
    "acceptLanguage": 'en-US,en;q=0.9'
})

Puppeteer에서 헤더 설정

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

await page.setExtraHTTPHeaders({
    'Accept-Language': 'en-US,en;q=0.9',
    'Accept-Encoding': 'gzip, deflate, br',
    'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
    'Sec-Fetch-Site': 'none',
    'Sec-Fetch-Mode': 'navigate',
    'Sec-Fetch-User': '?1',
    'Sec-Fetch-Dest': 'document'
});

Sec-Fetch-* 헤더는 매우 중요합니다. 이는 Chrome 76+에서 등장했으며, 이들이 없으면 구형 브라우저 또는 봇으로 간주됩니다.

Canvas 및 WebGL 지문 에뮬레이션

Canvas 및 WebGL 지문은 강력한 감지 방법입니다. 헤드리스 브라우저는 동일한 지문을 생성합니다. 안티봇 시스템은 보이지 않는 Canvas를 생성하고 그 위에 텍스트를 그린 후 픽셀 해시를 계산합니다. 수천 개의 요청이 동일한 해시를 가지면 이는 봇으로 간주됩니다.

Canvas에 노이즈 추가

다음 스크립트는 Canvas 지문에 무작위 노이즈를 추가하여 각 요청을 고유하게 만듭니다:

await page.evaluateOnNewDocument(() => {
    const originalToDataURL = HTMLCanvasElement.prototype.toDataURL;
    const originalToBlob = HTMLCanvasElement.prototype.toBlob;
    const originalGetImageData = CanvasRenderingContext2D.prototype.getImageData;
    
    // 노이즈 추가 함수
    const addNoise = (canvas, context) => {
        const imageData = originalGetImageData.call(context, 0, 0, canvas.width, canvas.height);
        for (let i = 0; i < imageData.data.length; i += 4) {
            imageData.data[i] += Math.floor(Math.random() * 10) - 5;
            imageData.data[i + 1] += Math.floor(Math.random() * 10) - 5;
            imageData.data[i + 2] += Math.floor(Math.random() * 10) - 5;
        }
        context.putImageData(imageData, 0, 0);
    };
    
    HTMLCanvasElement.prototype.toDataURL = function() {
        addNoise(this, this.getContext('2d'));
        return originalToDataURL.apply(this, arguments);
    };
});

WebGL 매개변수 에뮬레이션

WebGL은 그래픽 카드 및 드라이버에 대한 정보를 노출합니다. 헤드리스 모드에서는 이러한 매개변수가 소프트웨어 렌더링을 드러냅니다:

await page.evaluateOnNewDocument(() => {
    const getParameter = WebGLRenderingContext.prototype.getParameter;
    WebGLRenderingContext.prototype.getParameter = function(parameter) {
        // 실제 그래픽 카드 에뮬레이션
        if (parameter === 37445) {
            return 'Intel Inc.';
        }
        if (parameter === 37446) {
            return 'Intel Iris OpenGL Engine';
        }
        return getParameter.call(this, parameter);
    };
});

매개변수 37445는 UNMASKED_VENDOR_WEBGL이고, 37446은 UNMASKED_RENDERER_WEBGL입니다. 헤드리스 모드에서는 이들이 "Google SwiftShader"를 반환하여 자동화를 드러냅니다.

Selenium Stealth: Python을 위한 준비된 솔루션

selenium-stealth 라이브러리는 Selenium 마스킹을 위한 수십 개의 패치를 자동으로 적용합니다. 이는 Python 개발자에게 가장 간단한 솔루션으로, 각 매개변수를 수동으로 설정할 필요가 없습니다.

설치 및 기본 설정

pip install selenium-stealth
from selenium import webdriver
from selenium_stealth import stealth
from selenium.webdriver.chrome.options import Options

options = Options()
options.add_argument("--headless")
options.add_argument("--no-sandbox")
options.add_argument("--disable-dev-shm-usage")

driver = webdriver.Chrome(options=options)

# 스텔스 패치 적용
stealth(driver,
    languages=["en-US", "en"],
    vendor="Google Inc.",
    platform="Win32",
    webgl_vendor="Intel Inc.",
    renderer="Intel Iris OpenGL Engine",
    fix_hairline=True,
)

driver.get("https://bot.sannysoft.com")
driver.save_screenshot("test.png")

이 라이브러리는 자동으로 navigator.webdriver를 제거하고, window.chrome을 추가하며, 플러그인을 에뮬레이션하고, WebGL을 마스킹하며, 20개 이상의 패치를 적용합니다. 이는 80%의 감지 사례를 커버합니다.

프록시와 함께하는 고급 설정

완벽한 마스킹을 위해 selenium-stealth를 주거용 프록시와 결합하세요. 이들은 실제 가정 사용자의 IP 주소를 제공하여 고급 안티봇 시스템을 우회하는 데 필수적입니다:

from selenium.webdriver.common.proxy import Proxy, ProxyType

proxy = Proxy()
proxy.proxy_type = ProxyType.MANUAL
proxy.http_proxy = "ip:port"
proxy.ssl_proxy = "ip:port"

capabilities = webdriver.DesiredCapabilities.CHROME
proxy.add_to_capabilities(capabilities)

driver = webdriver.Chrome(desired_capabilities=capabilities, options=options)
stealth(driver, languages=["en-US", "en"], vendor="Google Inc.", platform="Win32")

Puppeteer Extra Stealth Plugin для Node.js

Puppeteer에는 puppeteer-extra-plugin-stealth라는 플러그인이 있으며, 이는 JavaScript 생태계에서 헤드리스 브라우저를 마스킹하는 가장 발전된 솔루션입니다. 이 플러그인은 자동화의 특정 측면을 마스킹하는 23개의 독립 모듈을 포함하고 있습니다.

설치 및 기본 사용법

npm install puppeteer-extra puppeteer-extra-plugin-stealth
const puppeteer = require('puppeteer-extra');
const StealthPlugin = require('puppeteer-extra-plugin-stealth');

puppeteer.use(StealthPlugin());

(async () => {
    const browser = await puppeteer.launch({ 
        headless: true,
        args: ['--no-sandbox', '--disable-setuid-sandbox']
    });
    
    const page = await browser.newPage();
    await page.goto('https://bot.sannysoft.com');
    await page.screenshot({ path: 'test.png' });
    await browser.close();
})();

Stealth Plugin이 마스킹하는 것

이 플러그인은 다음 패치를 자동으로 적용합니다:

  • navigator.webdriver 제거
  • window.chrome 객체 추가
  • navigator.permissions API 에뮬레이션
  • navigator.pluginsnavigator.mimeTypes 마스킹
  • Canvas 및 WebGL 지문 에뮬레이션
  • User-Agent 및 언어 마스킹
  • iframe contentWindow의 비정상 수정
  • Battery API, Media Devices, WebRTC 에뮬레이션

프록시 및 추가 매개변수 설정

const puppeteer = require('puppeteer-extra');
const StealthPlugin = require('puppeteer-extra-plugin-stealth');
const AdblockerPlugin = require('puppeteer-extra-plugin-adblocker');

puppeteer.use(StealthPlugin());
puppeteer.use(AdblockerPlugin({ blockTrackers: true }));

(async () => {
    const browser = await puppeteer.launch({
        headless: true,
        args: [
            '--proxy-server=http://your-proxy:port',
            '--disable-web-security',
            '--disable-features=IsolateOrigins,site-per-process'
        ]
    });
    
    const page = await browser.newPage();
    
    // 프록시 인증
    await page.authenticate({
        username: 'your-username',
        password: 'your-password'
    });
    
    await page.setViewport({ width: 1920, height: 1080 });
    await page.goto('https://example.com', { waitUntil: 'networkidle2' });
})();

Playwright: 안티 감지 설정

Playwright는 Puppeteer에 비해 더 정교한 아키텍처를 가지고 있으며, 자동화의 흔적을 덜 남깁니다. 그러나 고급 안티봇 시스템을 우회하기 위해서는 추가 설정이 필요합니다. Playwright에는 스텔스 플러그인의 포트가 있습니다 — playwright-extra.

playwright-extra 설치

npm install playwright-extra playwright-extra-plugin-stealth playwright
const { chromium } = require('playwright-extra');
const stealth = require('playwright-extra-plugin-stealth');

chromium.use(stealth());

(async () => {
    const browser = await chromium.launch({ headless: true });
    const context = await browser.newContext({
        userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
        viewport: { width: 1920, height: 1080 },
        locale: 'en-US',
        timezoneId: 'America/New_York'
    });
    
    const page = await context.newPage();
    await page.goto('https://bot.sannysoft.com');
    await page.screenshot({ path: 'test.png' });
    await browser.close();
})();

최대 마스킹을 위한 브라우저 컨텍스트 설정

Playwright는 개별 설정으로 격리된 브라우저 컨텍스트를 생성할 수 있습니다. 이는 멀티 계정 관리나 병렬 파싱에 유용합니다:

const context = await browser.newContext({
    userAgent: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36',
    viewport: { width: 1440, height: 900 },
    locale: 'en-US',
    timezoneId: 'America/Los_Angeles',
    permissions: ['geolocation'],
    geolocation: { latitude: 37.7749, longitude: -122.4194 },
    colorScheme: 'light',
    deviceScaleFactor: 2,
    isMobile: false,
    hasTouch: false,
    // 컨텍스트에 대한 프록시 설정
    proxy: {
        server: 'http://your-proxy:port',
        username: 'user',
        password: 'pass'
    }
});

geolocationtimezoneId 매개변수는 프록시의 IP 주소와 일치해야 하며, 그렇지 않으면 안티봇 시스템이 불일치를 감지합니다(예: 캘리포니아의 IP 주소이지만 뉴욕의 시간대).

차단 위험을 줄이기 위한 프록시 회전

완벽하게 마스킹된 헤드리스 브라우저라도 수백 개의 요청에 대해 동일한 IP 주소를 사용하는 경우 차단될 수 있습니다. 현대의 안티봇 시스템은 단일 IP에서의 요청 빈도를 분석하고 의심스러운 활동을 차단합니다. 프록시 회전은 파싱 시 보호의 필수 요소입니다.

파싱을 위한 프록시 유형: 비교

프록시 유형 속도 신뢰 점수 더 나은 용도
데이터 센터 매우 높음 (50-200 ms) 낮음 간단한 사이트, 대량 파싱
주거용 중간 (300-1000 ms) 높음 보호된 사이트, 소셜 미디어
모바일 낮음 (500-2000 ms) 매우 높음 모바일 애플리케이션, Instagram, TikTok

보호된 사이트(마켓플레이스, 소셜 미디어, 광고 플랫폼)를 파싱할 때는 주거용 프록시를 사용하는 것이 좋습니다. 이들은 실제 가정 사용자의 IP를 가지고 있으며 안티봇 시스템의 블랙리스트에 올라가지 않습니다.

Puppeteer에서 프록시 회전 구현

const puppeteer = require('puppeteer-extra');
const StealthPlugin = require('puppeteer-extra-plugin-stealth');

puppeteer.use(StealthPlugin());

const proxyList = [
    'http://user1:pass1@proxy1:port',
    'http://user2:pass2@proxy2:port',
    'http://user3:pass3@proxy3:port'
];

async function scrapeWithRotation(urls) {
    for (let i = 0; i < urls.length; i++) {
        const proxy = proxyList[i % proxyList.length];
        
        const browser = await puppeteer.launch({
            headless: true,
            args: [`--proxy-server=${proxy}`]
        });
        
        const page = await browser.newPage();
        
        try {
            await page.goto(urls[i], { waitUntil: 'networkidle2' });
            const data = await page.evaluate(() => document.body.innerText);
            console.log(data);
        } catch (error) {
            console.error(`Error on ${urls[i]}:`, error);
        } finally {
            await browser.close();
        }
        
        // 요청 간 지연
        await new Promise(resolve => setTimeout(resolve, 2000));
    }
}

scrapeWithRotation([
    'https://example1.com',
    'https://example2.com',
    'https://example3.com'
]);

세션 기반 프록시를 통한 회전

일부 프록시 제공업체(ProxyCove 포함)는 세션 기반 회전을 제공합니다. 각 요청은 브라우저를 재시작할 필요 없이 자동으로 새로운 IP를 받습니다. 이는 프록시 URL의 특별한 형식을 통해 구현됩니다:

// 형식: username-session-RANDOM:password@gateway:port
const generateSessionProxy = () => {
    const sessionId = Math.random().toString(36).substring(7);
    return `http://username-session-${sessionId}:password@gateway.proxycove.com:12321`;
};

const browser = await puppeteer.launch({
    args: [`--proxy-server=${generateSessionProxy()}`]
});

마스킹 품질을 확인하는 방법: 테스트 도구

마스킹 설정 후, 여러분의 헤드리스 브라우저가 일반 사용자를 얼마나 잘 모방하는지 확인해야 합니다. 브라우저의 수십 개 매개변수를 분석하고 자동화의 흔적이 남아 있는지 보여주는 몇 가지 전문 사이트가 있습니다.

주요 테스트 도구

  • bot.sannysoft.com — webdriver, Chrome 객체, 플러그인, Canvas를 포함하여 15개 이상의 감지 매개변수를 확인합니다.
  • arh.antoinevastel.com/bots/areyouheadless — 헤드리스 Chrome 감지에 특화되어 있습니다.
  • pixelscan.net — 모든 매개변수를 시각화하여 고급 지문 분석을 제공합니다.
  • abrahamjuliot.github.io/creepjs — 가장 상세한 분석(200개 이상의 매개변수)을 제공하며, 브라우저의 신뢰 수준을 보여줍니다.
  • iphey.com — IP 주소가 프록시 및 VPN에 속하는지 확인합니다.

테스트 자동화

설정 변경 후 마스킹 품질을 자동으로 확인하는 스크립트를 작성하세요:

const puppeteer = require('puppeteer-extra');
const StealthPlugin = require('puppeteer-extra-plugin-stealth');

puppeteer.use(StealthPlugin());

async function testStealth() {
    const browser = await puppeteer.launch({ headless: true });
    const page = await browser.newPage();
    
    // 테스트 1: Sannysoft
    await page.goto('https://bot.sannysoft.com');
    await page.screenshot({ path: 'test-sannysoft.png', fullPage: true });
    
    // 테스트 2: Are you headless
    await page.goto('https://arh.antoinevastel.com/bots/areyouheadless');
    const headlessDetected = await page.evaluate(() => {
        return document.body.innerText.includes('You are not Chrome headless');
    });
    console.log('헤드리스 감지됨:', !headlessDetected);
    
    // 테스트 3: Webdriver 속성
    const webdriverPresent = await page.evaluate(() => navigator.webdriver);
    console.log('navigator.webdriver:', webdriverPresent);
    
    // 테스트 4: Chrome 객체
    const chromePresent = await page.evaluate(() => !!window.chrome);
    console.log('window.chrome 존재:', chromePresent);
    
    await browser.close();
}

testStealth();

성공적인 마스킹 체크리스트

여러분의 헤드리스 브라우저가 올바르게 마스킹되었다면:

  • navigator.webdriverundefined를 반환합니다.
  • window.chrome이 존재하고 runtime 객체를 포함합니다.
  • navigator.plugins.length가 0보다 큽니다.
  • WebGL 공급자 및 렌더러가 실제 그래픽 카드를 보여주며 SwiftShader가 아닙니다.
  • Canvas 지문이 각 세션마다 고유합니다.
  • User-Agent가 최신 Chrome/Firefox 버전에 해당합니다.
  • 프록시의 IP 주소가 블랙리스트에 올라 있지 않습니다(확인은 iphey.com을 통해).
  • 시간대 및 로케일이 IP 주소의 지리적 위치와 일치합니다.

결론

헤드리스 브라우저를 마스킹하는 것은 수십 개의 매개변수에 대한 세심한 주의를 요구하는 복합적인 작업입니다. 현대의 안티봇 시스템은 기계 학습을 사용하여 브라우저의 수백 가지 특성을 동시에 분석하므로, 단순히 User-Agent를 변경하는 것만으로는 효과가 없습니다. 성공적인 파싱을 위해서는 여러 보호 방법을 조합해야 합니다.

효과적인 마스킹의 주요 요소는 자동화 JavaScript 마커(navigator.webdriver, CDP 변수) 제거, Canvas 및 WebGL 지문 에뮬레이션, 현실적인 HTTP 헤더 설정 및 고품질 프록시 사용입니다. 준비된 솔루션(selenium-stealth for Python, puppeteer-extra-plugin-stealth for Node.js)은 80%의 사례를 커버하지만, 고급 보호를 우회하기 위해서는 추가 설정이 필요합니다.

매우 중요한 점은 프록시 선택입니다. 완벽하게 마스킹된 브라우저라도 블랙리스트에 올라간 IP 주소를 사용하거나 하나의 IP에서 너무 많은 요청을 하면 차단될 수 있습니다. 보호된 사이트를 파싱할 때는 주거용 프록시를 사용하여 자동 회전을 통해 높은 신뢰 점수와 최소한의 차단 위험을 보장하는 것이 좋습니다. 이들은 서버 주소 대신 실제 가정 사용자의 IP를 사용합니다.

정기적으로 전문 서비스(bot.sannysoft.com, pixelscan.net)를 통해 마스킹 품질을 테스트하고 안티봇 시스템의 변화에 맞게 설정을 조정하세요. 파싱은 봇 개발자와 보호 시스템 제작자 간의 지속적인 무기 경쟁이므로, 오늘 작동하는 구성도 몇 달 후에는 업데이트가 필요할 수 있습니다.

```