DrissionPage 프록시 완벽 가이드: HTTP와 Chromium 자동화를 하나로

DrissionPage로 HTTP 요청과 브라우저 제어를 전환하며 ProxyHat 주거용 프록시를 통합하는 실전 튜토리얼. 코드 예제, 프로덕션 패턴, 윤리 가이드까지.

DrissionPage Proxy Guide: One Python Tool for HTTP and Chromium Scraping
이 글의 목차

DrissionPage는 Python 개발자가 오랫동안 겪어온 딜레마를 해결합니다: 빠르고 가벼운 HTTP 스크래핑과 무거운 브라우저 자동화 사이에서 하나를 선택해야 했던 문제입니다. requests로는 JavaScript 렌더링 페이지를 처리할 수 없고, Selenium/Playwright로는 단순 HTML 페이지도 브라우저를 띄워야 하니 속도와 비용이 낭비됩니다. DrissionPage는 이 두 세계를 하나의 프레임워크로 통합합니다.

주의: 이 가이드는 공개 데이터 수집만을 다룹니다. 미국 CFAA(Computer Fraud and Abuse Act)와 EU GDPR은 비공개 데이터에 대한 무단 접근을 금지합니다. robots.txt를 존중하고, 서비스 약관을 확인하며, 공식 API가 있다면 우선 사용하세요.

DrissionPage의 아키텍처: 왜 하나의 도구로 충분한가

DrissionPage는 세 가지 페이지 객체를 제공합니다. 각각의 역할과 비용 구조가 다릅니다.

SessionPage — HTTP 전용 모드

SessionPage는 Python requests를 기반으로 작동합니다. 브라우저를 띄우지 않고 HTTP 요청만 보내므로, 단순 HTML 페이지나 JSON API를 수집할 때 가장 빠르고 저렴합니다. 메모리 사용량이 적고, 초당 수백 건의 요청이 가능합니다. DrissionPage 공식 문서에 따르면, SessionPage는 requests의 모든 기능을 래핑하면서도 더 간결한 API를 제공합니다.

ChromiumPage — 브라우저 제어 모드

ChromiumPage는 Chrome DevTools Protocol(CDP)을 통해 실제 Chromium 브라우저를 제어합니다. Selenium과 달리 WebDriver를 사용하지 않고 CDP에 직접 연결하므로, 탐지 확률이 낮고 속도가 빠릅니다. JavaScript 렌더링, SPA 페이지, 동적 콘텐츠를 처리할 때 필요합니다.

WebPage — 모드 전환의 핵심

WebPage가 DrissionPage의 핵심 혁신입니다. 하나의 객체에서 page.get()으로 HTTP 모드로, page.get(mode='d')로 브라우저 모드로 전환할 수 있습니다. 전환 시 쿠키, 헤더, 세션 상태가 자동으로 공유됩니다. 예를 들어, 로그인은 HTTP 모드로 빠르게 처리하고, 로그인 후 페이지는 브라우저 모드로 렌더링하는 하이브리드 접근이 가능합니다.

이 구조가 비용을 줄이는 이유는 명확합니다. 100개 페이지 중 80개가 정적 HTML이라면, 브라우저를 띄우는 것은 20번만으로 충분합니다. Chromium 인스턴스 하나는 약 200~400MB의 메모리를 사용하므로, 80%의 요청을 HTTP로 처리하면 인프라 비용이 크게 절감됩니다.

DrissionPage 웹 스크래핑: 핵심 API 익히기

요소 탐색 — ele()와 eles()

DrissionPage의 요소 탐색 API는 직관적이면서 강력합니다. CSS 선택자, XPath, 그리고 DrissionPage만의 @ 속성 문법을 지원합니다.

from DrissionPage import WebPage

page = WebPage()
page.get('https://example.com')

# CSS 선택자
title = page.ele('css:h1').text

# 태그 + 속성 조합
inputs = page.eles('tag:input@class=search-box')

# XPath
links = page.eles('xpath://a[contains(@href, "/product/")]')

# 텍스트 기반 탐색
button = page.ele('@text()=더 보기')

ele()는 첫 번째 매치를, eles()는 모든 매치를 반환합니다. tag:input 문법은 태그 이름으로 필터링하고, @class는 속성을 지정합니다. XPath가 필요한 복잡한 탐색도 완벽히 지원됩니다.

ChromiumOptions — 브라우저 설정

from DrissionPage import ChromiumOptions, ChromiumPage

co = ChromiumOptions()
co.headless(True)
co.set_argument('--no-sandbox')
co.set_argument('--disable-gpu')
co.set_argument('--window-size=1920,1080')
co.set_user_agent('Mozilla/5.0 (Windows NT 10.0; Win64; x64) ...')

page = ChromiumPage(co)

listen.start() — 백그라운드 XHR/JSON 캡처

이 기능은 DrissionPage를 다른 브라우저 자동화 도구와 차별화하는 강력한 도구입니다. listen 모듈은 브라우저의 백그라운드 네트워크 요청을 실시간으로 캡처합니다. 페이지가 AJAX로 데이터를 로드할 때, 응답 JSON을 직접 가로챌 수 있습니다.

page = ChromiumPage()
page.listen.start('api/products')  # URL 패턴 필터

page.get('https://shop.example.com/catalog')

# 캡처된 패킷 대기
packet = page.listen.wait(timeout=10)
if packet:
    print(packet.response.body)  # JSON 응답
    print(packet.url)
    print(packet.method)

이 기능으로 숨겨진 API를 발견하면, 이후 수집은 SessionPage의 HTTP 모드로 전환하여 속도를 10배 이상 높일 수 있습니다. 브라우저로 페이지를 한 번 분석하고, 실제 대량 수집은 HTTP로 수행하는 전략입니다.

DrissionPage 프록시 설정: SessionPage와 ChromiumPage

DrissionPage에서 프록시를 설정하는 방법은 두 가지 모드에서 다릅니다. 각각의 메커니즘을 이해해야 합니다.

SessionPage 프록시 — set_proxies()

from DrissionPage import SessionPage

page = SessionPage()
page.set.proxies('http://user-country-US:password@gate.proxyhat.com:8080')
page.get('https://httpbin.org/ip')
print(page.response.status_code)

SessionPage의 set.proxies()는 내부적으로 requests의 proxies 파라미터를 설정합니다. HTTP/HTTPS/SOCKS5 프록시를 모두 지원합니다.

ChromiumPage 프록시 — ChromiumOptions.set_proxy()

from DrissionPage import ChromiumOptions, ChromiumPage

co = ChromiumOptions()
co.set_proxy('http://user-country-US:password@gate.proxyhat.com:8080')

page = ChromiumPage(co)
page.get('https://httpbin.org/ip')

주의: ChromiumPage는 브라우저 시작 시 프록시를 적용합니다. 런타임 중 프록시를 변경하려면 브라우저를 재시작해야 합니다. 세션 단위로 프록시를 교체하려면 새 ChromiumPage 인스턴스를 생성하세요.

왜 주거용 프록시인가

데이터센터 IP는 클라우드 제공사업자의 IP 대역으로 식별되기 쉽습니다. 많은 타겟 사이트가 프록시 탐지 기술을 사용해 데이터센터 IP를 차단합니다. 주거용(residential) 프록시는 실제 ISP에서 할당된 IP를 사용하므로, 일반 사용자의 트래픽과 구별하기 어렵습니다.

ProxyHat의 주거용 프록시는 99.9% 가동률과 전 세계 190개국 이상의 지역 타겟팅을 제공합니다. DrissionPage와 조합하면, HTTP 모드에서는 초당 50~100건의 요청을, 브라우저 모드에서는 5~10개의 동시 세션을 안정적으로 운영할 수 있습니다.

실전 예제: WebPage 하이브리드 스크래핑 with ProxyHat

이제 실제로 동작하는 완전한 예제를 살펴봅니다. WebPage를 HTTP 모드로 시작하고, 필요할 때 Chromium 모드로 에스컬레이션하는 시나리오입니다.

from DrissionPage import WebPage
import time
import random

def build_proxy_url(country='US', session_id=None, city=None):
    """ProxyHat 주거용 프록시 URL 생성"""
    username = f'user-country-{country}'
    if city:
        username += f'-city-{city}'
    if session_id:
        username += f'-session-{session_id}'
    return f'http://{username}:PASSWORD@gate.proxyhat.com:8080'

def scrape_with_escalation(url, target_keyword):
    """HTTP 모드로 시작, 필요시 브라우저로 에스컬레이션"""
    session_id = f'sess-{random.randint(10000, 99999)}'
    proxy_url = build_proxy_url(country='US', session_id=session_id)
    
    page = WebPage()
    
    # 1단계: HTTP 모드로 시도
    page.set.proxies(proxy_url)
    page.get(url, mode='s')  # 's' = SessionPage 모드
    
    # 콘텐츠 확인
    content = page.html
    if target_keyword in content and len(content) > 500:
        print(f'[HTTP] 성공 — {len(content)} bytes')
        return page.ele('css:h1').text, content
    
    # 2단계: 브라우저 모드로 에스컬레이션
    print('[HTTP] 콘텐츠 부족 — Chromium 모드로 전환')
    page.get(url, mode='d')  # 'd' = ChromiumPage 모드
    
    # 쿠키는 자동으로 공유됨
    time.sleep(3)  # JS 렌더링 대기
    
    rendered_content = page.html
    if target_keyword in rendered_content:
        print(f'[Chromium] 성공 — {len(rendered_content)} bytes')
        return page.ele('css:h1').text, rendered_content
    
    print('[실패] 두 모드 모두에서 콘텐츠를 찾지 못함')
    return None, None

# 실행
result = scrape_with_escalation(
    'https://example-shop.com/product/12345',
    'product-details'
)

이 예제의 핵심은 비용 최적화입니다. 대부분의 페이지는 HTTP 모드로 처리되므로 브라우저 리소스를 절약하고, JS 렌더링이 필요한 페이지만 브라우저로 전환합니다. 세션 ID를 고정하면 같은 IP를 유지하여 로그인 상태가 지속됩니다.

listen으로 숨겨진 API 발견 후 HTTP 전환

from DrissionPage import ChromiumPage, SessionPage

def discover_api_and_scrape(page_url, api_pattern):
    """브라우저로 API를 발견하고 HTTP로 대량 수집"""
    # 1단계: ChromiumPage로 API 발견
    co = ChromiumOptions()
    co.set_proxy('http://user-country-US:PASSWORD@gate.proxyhat.com:8080')
    co.headless(True)
    
    browser = ChromiumPage(co)
    browser.listen.start(api_pattern)
    browser.get(page_url)
    
    packet = browser.listen.wait(timeout=15)
    if not packet:
        browser.close()
        return None
    
    api_url = packet.url
    api_headers = packet.request.headers
    print(f'[발견] API: {api_url}')
    
    browser.close()
    
    # 2단계: SessionPage로 대량 수집
    sp = SessionPage()
    sp.set.proxies('http://user-country-US-session-batch1:PASSWORD@gate.proxyhat.com:8080')
    sp.set.headers(api_headers)  # 발견한 헤더 재사용
    
    results = []
    for page_num in range(1, 101):
        sp.get(f'{api_url}?page={page_num}')
        data = sp.response.json()
        results.extend(data.get('items', []))
        time.sleep(random.uniform(0.5, 1.5))  # 합리적 지연
    
    return results

이 패턴은 DrissionPage의 가장 강력한 사용 사례 중 하나입니다. 브라우저는 API를 발견하는 용도로만 사용하고, 실제 수집은 HTTP 모드에서 수행합니다. 100페이지를 수집할 때 브라우저를 100번 띄우는 대신 1번만 사용합니다.

프로덕션 패턴: 규모와 안정성

세션 단위 프록시 고정

각 작업에 고유한 세션 ID를 부여하면, 같은 작업 내에서는 동일한 IP가 유지됩니다. 이는 로그인 세션이나 다단계 폼 제출에 필수적입니다.

import uuid

def create_pinned_session(country='US'):
    session_id = str(uuid.uuid4())[:8]
    proxy = f'http://user-country-{country}-session-{session_id}:PASS@gate.proxyhat.com:8080'
    page = WebPage()
    page.set.proxies(proxy)
    return page, session_id

재시도 로직과 백오프

def fetch_with_retry(page, url, max_retries=3):
    for attempt in range(max_retries):
        try:
            resp = page.get(url, timeout=15)
            if resp.status_code == 200:
                return resp
            elif resp.status_code == 429:
                wait = 2 ** attempt + random.uniform(0, 1)
                print(f'Rate limited — {wait:.1f}s 대기')
                time.sleep(wait)
            elif resp.status_code == 403:
                print('차단됨 — 새 세션 필요')
                return None
        except Exception as e:
            print(f'오류: {e} — 재시도 {attempt + 1}/{max_retries}')
            time.sleep(2 ** attempt)
    return None

동시성 관리

ChromiumPage는 메모리 집약적이므로 동시 실행 수를 제한해야 합니다. 일반적으로 메모리 4GB당 5~8개의 동시 브라우저 세션이 안정적인 임계값입니다. SessionPage는 훨씬 더 높은 동시성이 가능합니다 — 50~100개의 동시 HTTP 세션이 일반적인 범위입니다.

패턴 모드 동시성 권장 메모리/세션 적용 시나리오
대량 HTML 수집 SessionPage 50~100 ~20MB 정적 페이지, JSON API
JS 렌더링 수집 ChromiumPage 5~8 200~400MB SPA, 동적 콘텐츠
하이브리드 WebPage 10~20 혼합 API 발견 후 HTTP 전환
API 캡처 ChromiumPage + listen 2~3 300~500MB 숨겨진 API 탐색

컨테이너화 패턴

# Dockerfile 예시
FROM python:3.11-slim

RUN apt-get update && apt-get install -y \
    chromium \
    chromium-driver \
    fonts-liberation \
    && rm -rf /var/lib/apt/lists/*

RUN pip install DrissionPage

ENV DISPLAY=:99
ENV CHROME_PATH=/usr/bin/chromium

COPY scraper.py /app/scraper.py
WORKDIR /app

CMD ["python", "scraper.py"]

컨테이너 환경에서는 --no-sandbox--disable-dev-shm-usage 플래그가 필수입니다. 공유 메모리가 부족하면 Chromium이 크래시할 수 있습니다.

브라우저로 에스컬레이션하지 말아야 할 때

브라우저는 만능 해결책이 아닙니다. 다음 상황에서는 HTTP 모드를 유지하세요:

  • JSON API가 공개된 경우: 브라우저를 띄울 이유가 없습니다. SessionPage로 직접 호출하세요.
  • 대량 페이지 수집: 1,000개 이상의 페이지를 수집할 때 브라우저는 비효율적입니다. HTTP 모드로 처리하고, 차단된 페이지만 브라우저로 재시도하세요.
  • 단순 HTML 테이블: 정적 HTML에 데이터가 있다면 page.eles('tag:tr')로 충분합니다.
  • 속도가 최우선인 경우: 브라우저는 페이지당 2~5초가 추가됩니다. HTTP는 일반적으로 200~800ms면 충분합니다.

반대로, 다음 상황에서는 브라우저 에스컬레이션이 정당합니다:

  • Cloudflare/Turnstile 챌린지: 브라우저 환경에서만 해결 가능합니다.
  • 무한 스크롤: JS 이벤트를 트리거해야 데이터가 로드됩니다.
  • 동적 폼 제출: JS 검증이 포함된 다단계 폼은 브라우저가 필요합니다.
  • WebSocket 기반 데이터: listen으로 캡처할 수 있습니다.

윤리와 법적 고려사항

스크래핑은 강력한 도구지만, 책임감 있게 사용해야 합니다. 핵심 원칙은 다음과 같습니다:

  • 공개 데이터만 수집: 로그인 없이 접근 가능한 페이지만 대상으로 하세요. 비공개 데이터에 접근하면 CFAA 위반이 될 수 있습니다.
  • robots.txt 존중: RFC 9309에 정의된 robots.txt 프로토콜을 따르세요. DrissionPage는 robots.txt를 자동으로 확인하지 않으므로, 별도로 파싱해야 합니다.
  • 요청 속도 제한: 타겟 서버에 부하를 주지 않도록 초당 1~5건 이하로 유지하세요. 대량 수집 시 time.sleep(random.uniform(1, 3))을 사용하세요.
  • GDPR 주의: EU 사용자의 개인 데이터를 수집할 때는 GDPR 적용 대상일 수 있습니다. 개인 식별 정보(PII)는 수집하지 마세요.
  • 공식 API 우선: 타겟 사이트가 공식 API를 제공한다면, 스크래핑보다 API를 사용하세요. 더 안정적이고 법적 위험이 없습니다.

ProxyHat 설정 가이드

ProxyHat과 DrissionPage의 통합은 간단합니다. 프라이싱 페이지에서 플랜을 확인하고, 위치 페이지에서 사용 가능한 국가를 확인하세요.

연결 파라미터 요약

파라미터
게이트웨이 gate.proxyhat.com
HTTP 포트 8080
SOCKS5 포트 1080
국가 타겟팅 user-country-US
도시 타겟팅 user-country-DE-city-berlin
세션 고정 user-session-abc123

자세한 설정은 ProxyHat 문서를 참조하세요. 웹 스크래핑 사용 사례SERP 추적 사용 사례 페이지에서 더 많은 실전 시나리오를 확인할 수 있습니다.

핵심 요약

Key Takeaways:

  • DrissionPage의 WebPage는 HTTP와 Chromium 모드를 전환하며 쿠키/세션을 공유합니다 — 80%의 요청을 HTTP로 처리해 비용을 절감하세요.
  • listen.start()로 숨겨진 API를 발견한 후 SessionPage로 대량 수집하는 하이브리드 패턴이 가장 효율적입니다.
  • 프록시는 SessionPage의 set.proxies()와 ChromiumPage의 ChromiumOptions.set_proxy()로 설정합니다.
  • 주거용 프록시로 세션을 고정하고, 요청 간 1~3초 지연을 두어 차단을 피하세요.
  • 브라우저는 JS 렌더링이 필요할 때만 사용하고, 정적 페이지는 항상 HTTP 모드를 우선하세요.
  • 공개 데이터만 수집하고, robots.txt를 존중하며, 공식 API가 있으면 우선 사용하세요.

DrissionPage와 ProxyHat 주거용 프록시의 조합은 Python 스크래퍼에게 강력한 도구입니다. 하나의 프레임워크로 HTTP와 브라우저를 전환하며, 주거용 IP로 차단을 회피하고, listen으로 숨겨진 API를 발견하는 워크플로우는 다른 어떤 도구 조합으로도 쉽게 구현할 수 없는 효율성을 제공합니다. ProxyHat 프라이싱을 확인하고 지금 시작하세요.

자주 묻는 질문

DrissionPage란 무엇인가요?

DrissionPage는 Python 기반 웹 자동화 프레임워크로, requests 스타일의 HTTP 요청과 Chromium 브라우저 제어를 하나의 API로 통합합니다. SessionPage, ChromiumPage, WebPage 세 가지 페이지 객체를 제공하며, WebPage는 HTTP 모드와 브라우저 모드를 전환하면서도 쿠키와 세션 상태를 공유합니다. 이를 통해 단순 페이지는 HTTP로, JS 렌더링이 필요한 페이지는 브라우저로 처리할 수 있어 비용과 속도를 최적화할 수 있습니다.

DrissionPage에서 프록시가 왜 중요한가요?

DrissionPage는 HTTP 모드와 브라우저 모드 모두에서 단일 IP로 요청을 보내면 빠르게 차단될 수 있습니다. 특히 SERP 추적, 이커머스 가격 모니터링, 소셜 미디어 수집 같은 하드 타겟에서는 주거용 프록시로 IP를 순환시키고 지역을 타겟팅하는 것이 필수적입니다. DrissionPage의 set_proxies()와 ChromiumOptions.set_proxy()를 통해 두 모드 모두에 프록시를 적용할 수 있어, 차단 회피와 안정적인 데이터 수집이 가능합니다.

DrissionPage에 어떤 프록시 유형이 가장 적합한가요?

대부분의 스크래핑 시나리오에서는 주거용(residential) 프록시가 가장 안정적입니다. 실제 ISP IP를 사용하므로 타겟 사이트의 봇 탐지를 우회하기 쉽습니다. 데이터센터 프록시는 속도가 빠르지만 IP 대역이 쉽게 식별되어 차단될 수 있습니다. 모바일 프록시는 가장 높은 신뢰도를 제공하지만 비용이 높습니다. 일반적으로 주거용 프록시로 시작하고, 차단이 잦은 타겟에만 모바일로 에스컬레이션하는 전략을 권장합니다.

DrissionPage로 차단을 피하려면 어떻게 해야 하나요?

주거용 프록시로 IP를 순환하고, 세션을 고정하여 로그인 상태를 유지하며, 요청 사이에 적절한 지연을 두는 것이 핵심입니다. ChromiumPage 사용 시 실제 브라우저 지문을 유지하고, listen.start()로 백그라운드 XHR을 캡처하여 숨겨진 API를 발견하면 HTTP 모드로 전환해 속도를 높일 수 있습니다. robots.txt를 존중하고, 공개 데이터만 수집하며, 요청 속도를 합리적인 수준으로 유지하는 것이 장기적인 안정성에 중요합니다.

시작할 준비가 되셨나요?

148개국 이상의 주거용, ISP, 모바일 프록시. 무료 계정을 만드세요.

무료 계정 만들기
← 블로그로 돌아가기