DrissionPage 프록시 통합 가이드: HTTP와 Chromium 브라우저 자동화를 하나로

DrissionPage로 HTTP 요청과 Chromium 브라우저 제어를 하나의 도구로 통합하는 방법을 다룹니다. ProxyHat 주거 프록시와 결합하여 SessionPage, ChromiumPage, WebPage를 활용한 실전 웹 스크래핑 패턴을 코드 예제와 함께 제공합니다.

DrissionPage Proxy Guide: HTTP + Chromium Scraping with Residential IPs

DrissionPage로 HTTP와 브라우저 자동화를 하나의 도구로 통합하기

웹 스크래핑을 하다 보면 같은 사이트에서 두 가지 모드를 번갈아 써야 하는 상황이 자주 발생합니다. 리스트 페이지는 단순 HTML이라 requests로 충분하지만, 상세 페이지는 JavaScript 렌더링이 필요해 Selenium이나 Playwright를 켜야 합니다. 두 도구를 오가며 쿠키와 세션을 동기화하는 것은 번거롭고 오류가 잦습니다. DrissionPage는 이 문제를 해결하는 Python 프레임워크로, HTTP 요청과 Chromium 브라우저 제어를 하나의 인터페이스에서 처리합니다. 이 글은 DrissionPage 튜토리얼이자 실전 DrissionPage 프록시 설정 가이드입니다.

주의: 이 글은 공개 데이터 수집을 전제로 합니다. 스크래핑 전 대상 사이트의 robots.txt, 이용약관, 그리고 관련 법규(CFAA, GDPR, CCPA 등)를 확인하세요. 가능하면 공식 API를 우선 사용하고, 비인가 접근이나 개인정보 수집은 피해야 합니다.

DrissionPage의 아키텍처: SessionPage, ChromiumPage, WebPage

DrissionPage는 세 가지 페이지 객체를 제공합니다. 각 객체는 서로 다른 방식으로 웹 페이지와 상호작용하지만, 쿠키와 세션 상태를 공유할 수 있어 모드 전환 시 인증 정보를 유지할 수 있습니다.

SessionPage — HTTP 요청 모드

SessionPage는 Python의 requests 라이브러리를 기반으로 동작합니다. 브라우저를 실행하지 않고 HTTP 요청만 보내므로 메모리 사용량이 약 50MB 수준으로 낮고, 응답 시간도 200ms 내외로 빠릅니다. 정적 HTML 페이지나 JSON API 엔드포인트를 스크래핑할 때 적합합니다.

ChromiumPage — CDP 기반 브라우저 제어

ChromiumPage는 Chrome DevTools Protocol(CDP)를 통해 Chromium 기반 브라우저를 제어합니다. Selenium과 달리 WebDriver를 사용하지 않고 CDP로 직접 통신하므로 탐지 가능성이 낮습니다. JavaScript 렌더링, 클릭, 스크롤, 파일 다운로드 등 브라우저 수준의 조작이 필요할 때 사용합니다. 메모리 사용량은 300MB 이상으로 높아지지만, 동적 콘텐츠를 처리할 수 있습니다.

WebPage — 두 모드의 전환

WebPage는 SessionPage와 ChromiumPage를 하나의 객체에서 전환할 수 있는 하이브리드 클래스입니다. page = WebPage()로 시작해 page.change_mode() 메서드로 HTTP 모드와 브라우저 모드를 전환합니다. 전환 시 쿠키와 세션 정보가 자동으로 동기화되므로, 로그인 상태를 유지하면서 모드를 바꿀 수 있습니다. 이것이 DrissionPage의 핵심 가치입니다 — 항상 브라우저를 띄울 필요 없이 필요한 순간에만 브라우저로 전환하면 됩니다.

특징 SessionPage ChromiumPage WebPage
동작 방식 HTTP 요청 (requests 기반) CDP 브라우저 제어 두 모드 전환 가능
평균 응답 시간 ~200ms ~2–5초 현재 모드에 따라 다름
메모리 사용량 ~50MB ~300MB+ 변동
JS 렌더링 불가 가능 모드에 따라
프록시 설정 set_proxies() ChromiumOptions.set_proxy() 두 방식 모두 지원
적합한 용도 정적 페이지, API SPA, 동적 콘텐츠 혼합 스크래핑

DrissionPage의 관용적 API: ele(), eles(), ChromiumOptions, listen

DrissionPage의 API는 직관적이면서도 강력합니다. 핵심 요소를 정리합니다.

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

단일 요소는 ele(), 다중 요소는 eles()로 찾습니다. CSS 셀렉터, XPath, 태그 이름, 속성 기반 선택을 모두 지원합니다:

# CSS 클래스로 찾기
title = page.ele('@class=title')

# 태그 + 속성 조합
input_box = page.ele('tag:input@type=text')

# XPath
items = page.eles('xpath://div[@class="item"]/a')

# 텍스트로 찾기
button = page.ele('text:로그인')

@ 접두사는 속성 선택을, tag:는 태그 기반 선택을, xpath:는 XPath를 의미합니다. 이 통합 문법이 DrissionPage를 독특하게 만듭니다 — CSS 셀렉터와 XPath를 혼합해서 쓸 수 있습니다.

ChromiumOptions로 브라우저 설정

ChromiumPage를 사용할 때 브라우저 옵션은 ChromiumOptions 객체로 설정합니다. 헤드리스 모드, 사용자 에이전트, 프록시 등을 구성할 수 있습니다:

from DrissionPage import ChromiumOptions

co = ChromiumOptions()
co.headless(True)
co.set_user_agent('Mozilla/5.0 (Windows NT 10.0; Win64; x64) ...')
co.set_proxy('http://user-country-US:pass@gate.proxyhat.com:8080')
co.set_argument('--no-sandbox')
co.set_argument('--disable-gpu')

listen으로 XHR/JSON 캡처

DrissionPage의 강력한 기능 중 하나는 listen 객체입니다. 브라우저가 백그라운드에서 보내는 XHR/Fetch 요청과 응답을 가로채서 JSON 데이터를 직접 추출할 수 있습니다. 이를 통해 페이지에서 숨겨진 API를 발견하고, HTML 파싱 없이 구조화된 데이터를 얻을 수 있습니다:

page = ChromiumPage()
page.listen.start('api/products')  # 특정 URL 패턴 감시

page.get('https://example.com/shop')
# 페이지 로드 시 백그라운드 XHR이 캡처됨

packet = page.listen.wait(timeout=10)
if packet:
    json_data = packet.response.body  # JSON 응답 직접 접근
    print(json_data)

이 패턴은 특히 SPA(Single Page Application)에서 유용합니다. React나 Vue로 렌더링된 페이지에서도 백그라운드 API 호출을 캡처하면, 복잡한 DOM 파싱 없이 JSON 데이터를 직접 얻을 수 있습니다.

DrissionPage 프록시 설정: SessionPage와 ChromiumPage

DrissionPage에서 프록시를 설정하는 방법은 모드에 따라 다릅니다. DrissionPage 프록시 설정은 두 가지 경로로 처리됩니다.

SessionPage — set_proxies()

SessionPage는 set_proxies() 메서드로 HTTP/SOCKS5 프록시를 설정합니다. requestsproxies 딕셔너리와 동일한 형식을 사용합니다:

from DrissionPage import SessionPage

page = SessionPage()
page.set_proxies({
    'http': 'http://user-country-US-session-abc123:pass@gate.proxyhat.com:8080',
    'https': 'http://user-country-US-session-abc123:pass@gate.proxyhat.com:8080'
})
page.get('https://httpbin.org/ip')
print(page.json['origin'])  # 프록시 IP 확인

ChromiumPage — ChromiumOptions.set_proxy()

ChromiumPage는 브라우저 자체에 프록시를 설정해야 합니다. ChromiumOptions.set_proxy()를 사용하면 Chromium이 모든 트래픽을 지정된 프록시로 라우팅합니다:

from DrissionPage import ChromiumPage, ChromiumOptions

co = ChromiumOptions()
co.set_proxy('http://user-country-US-session-abc123:pass@gate.proxyhat.com:8080')
co.headless(True)

page = ChromiumPage(co)
page.get('https://httpbin.org/ip')
print(page.ele('tag:pre').text)  # 프록시 IP 확인

왜 주거 프록시(residential proxy)가 필요한가? 데이터센터 IP 대역은 Cloudflare, Akamai, PerimeterX 같은 anti-bot 시스템에서 쉽게 식별됩니다. 주거 프록시는 실제 ISP에 등록된 IP를 사용하므로 일반 사용자 트래픽과 구분하기 어렵습니다. SERP 추적, 이커머스 가격 모니터링, 소셜 미디어 리서치 등 hard target에서는 주거 프록시가 사실상 필수입니다. 웹 스크래핑 사용 사례에서 자세한 시나리오를 확인할 수 있습니다.

실전 예제: WebPage로 HTTP에서 Chromium으로 전환하기

이제 ProxyHat 주거 프록시와 결합하여 WebPage를 사용하는 완전한 예제를 살펴보겠습니다. 시나리오: (1) HTTP 모드로 로그인 페이지에서 세션 획득, (2) ChromiumPage로 전환하여 JS 렌더링이 필요한 대시보드 데이터 수집, (3) listen으로 백그라운드 API 캡처.

from DrissionPage import WebPage, ChromiumOptions
import urllib.parse

# ProxyHat 주거 프록시 사용자명 빌더
def build_proxy_user(country='US', session_id=None):
    user = f'user-country-{country}'
    if session_id:
        user += f'-session-{session_id}'
    return user

PROXY_PASS = 'your_password'
PROXY_HOST = 'gate.proxyhat.com'
PROXY_PORT = 8080

# 세션 ID로 스티키 세션 보장
session_id = 'abc123'
proxy_user = build_proxy_user(country='US', session_id=session_id)
proxy_url = f'http://{proxy_user}:{PROXY_PASS}@{PROXY_HOST}:{PROXY_PORT}'

# 1단계: WebPage를 HTTP 모드로 시작
page = WebPage()
page.set_proxies({
    'http': proxy_url,
    'https': proxy_url
})

# 로그인 페이지에서 세션 쿠키 획득
page.get('https://example.com/login')
page.ele('tag:input@name=username').input('myuser')
page.ele('tag:input@name=password').input('mypass')
page.ele('text:로그인').click()

# 2단계: ChromiumPage 모드로 전환 (쿠키 자동 동기화)
co = ChromiumOptions()
co.set_proxy(proxy_url)
co.headless(True)
page.change_mode(co=co)  # 브라우저 모드로 전환, 세션 유지

# 3단계: listen으로 백그라운드 API 캡처
page.listen.start('api/dashboard')
page.get('https://example.com/dashboard')

packet = page.listen.wait(timeout=15)
if packet:
    data = packet.response.body
    print(f'캡처된 데이터: {data}')
else:
    print('API 응답을 캡처하지 못했습니다.')

page.quit()

이 예제에서 주목할 점은 change_mode() 호출 시 쿠키가 자동으로 브라우저로 전달된다는 것입니다. 별도의 쿠키 복사 로직이 필요 없습니다. 또한 session-abc123 플래그를 사용해 스티키 세션을 유지하므로, 로그인 시 사용한 IP와 대시보드 접근 시 IP가 동일합니다. IP가 바뀌면 세션이 무효화될 수 있기 때문입니다.

ProxyHat의 게이트웨이는 gate.proxyhat.com:8080(HTTP) 또는 gate.proxyhat.com:1080(SOCKS5)을 사용합니다. 국가, 도시, 세션 ID를 사용자명에 인코딩하여 세밀한 제어가 가능합니다. 지원 위치 목록에서 사용 가능한 국가/도시를 확인하세요.

프로덕션 패턴: 세션 고정, 재시도, 동시성 제어

세션별 프록시 고정

각 스크래핑 세션에 고유한 세션 ID를 부여하면, ProxyHat이 해당 세션 동안 동일한 IP를 유지합니다. 이는 로그인 상태를 유지해야 하는 스크래핑 작업에서 필수적입니다:

import uuid

def create_session_proxy(country='US'):
    session_id = uuid.uuid4().hex[:12]
    user = f'user-country-{country}-session-{session_id}'
    proxy_url = f'http://{user}:pass@gate.proxyhat.com:8080'
    return proxy_url, session_id

# 각 워커에 고유 세션 할당
proxy_url, session_id = create_session_proxy('US')
page = WebPage()
page.set_proxies({'http': proxy_url, 'https': proxy_url})

재시도 로직

스크래핑 실패 시 자동으로 재시도하되, 세션 ID를 새로 발급하여 새 IP로 시도하는 것이 좋습니다. 3회 재시도 후 실패하면 해당 URL을 실패 큐에 넣습니다:

def scrape_with_retry(url, max_retries=3):
    for attempt in range(max_retries):
        proxy_url, session_id = create_session_proxy('US')
        page = WebPage()
        page.set_proxies({'http': proxy_url, 'https': proxy_url})
        try:
            page.get(url, timeout=15)
            if page.status_code == 200:
                return page.html
        except Exception as e:
            print(f'시도 {attempt+1} 실패: {e}')
        finally:
            page.close()
    return None

동시성 제어

DrissionPage로 동시 스크래핑을 할 때는 시스템 리소스를 고려해야 합니다. SessionPage는 가벼우므로 100개 동시 세션까지도 가능하지만, ChromiumPage는 브라우저 프로세스당 약 300MB의 메모리를 사용하므로 동시 실행 수를 제한해야 합니다. 일반적으로 ChromiumPage는 머신당 5–10개 동시 실행이 적당합니다.

컨테이너 환경에서는 각 컨테이너에 1–2개의 Chromium 인스턴스를 할당하고, 컨테이너를 수평 확장하는 방식이 효율적입니다. Docker를 사용할 경우 --shm-size=2g 플래그로 공유 메모리를 늘려 Chromium의 크래시를 방지하세요.

listen으로 숨겨진 API 발견

프로덕션에서 가장 유용한 패턴 중 하나는 listen으로 페이지의 모든 네트워크 요청을 기록한 뒤, 데이터를 JSON으로 반환하는 API 엔드포인트를 식별하는 것입니다. 이 API를 찾으면 이후 스크래핑은 SessionPage로 해당 API를 직접 호출하면 되므로 브라우저가 필요 없어집니다:

page = ChromiumPage()
page.listen.start()  # 모든 요청 감시
page.get('https://example.com/products')

# 캡처된 모든 패킷 순회
for packet in page.listen.steps(count=20, timeout=10):
    url = packet.url
    if 'api' in url and packet.response.body:
        print(f'API 발견: {url}')
        # 이 URL을 SessionPage로 직접 호출 가능

page.quit()

이 방식으로 초기에는 브라우저를 사용해 API를 발견하고, 이후에는 HTTP 요청으로 전환하여 비용과 속도를 최적화할 수 있습니다. SERP 추적 사용 사례에서도 이 패턴이 유용합니다.

브라우저로 전환하지 말아야 할 때와 윤리

브라우저가 불필요한 경우

모든 페이지를 ChromiumPage로 처리하는 것은 비효율적입니다. 다음 경우에는 SessionPage(HTTP)만으로 충분합니다:

  • 서버 사이드 렌더링(SSR) 페이지 — HTML에 이미 데이터가 포함되어 있는 경우
  • 공개 JSON API — 직접 HTTP 요청으로 데이터를 가져올 수 있는 경우
  • 단순 폼 제출 — JavaScript 검증이 없는 로그인 폼
  • 대량 데이터 수집 — 수천 페이지를 순회할 때는 HTTP 모드의 속도 이점이 결정적입니다

반면 ChromiumPage가 필요한 경우는 다음과 같습니다:

  • JavaScript로 렌더링되는 SPA (React, Vue, Angular)
  • Cloudflare challenge나 CAPTCHA가 있는 페이지
  • 인터랙티브 요소(클릭, 스크롤, 드래그)가 필요한 페이지
  • 백그라운드 XHR을 캡처해야 하는 경우

윤리적 고려사항

DrissionPage로 웹 스크래핑을 수행할 때는 다음 원칙을 지키세요:

  • robots.txt 확인 — 수집이 허용되는 경로인지 확인합니다.
  • 요청 속도 제한 — 초당 요청 수를 합리적인 수준(예: 1–2 req/s)으로 유지합니다.
  • 공식 API 우선 — 많은 플랫폼이 공식 API를 제공합니다. 가능하면 API를 사용하세요.
  • 개인정보 보호 — GDPR, CCPA 등 개인정보 보호법을 준수하고, PII(개인 식별 정보) 수집을 피합니다.
  • 인가된 접근 금지 — 로그인이 필요한 비공개 영역은 사전 허가 없이 접근하지 마세요. CFAA(Computer Fraud and Abuse Act) 위반 가능성이 있습니다.

프록시 사용 자체가 불법은 아니지만, 대상 사이트의 ToS를 위반하면서 수집한 데이터의 사용은 법적 위험이 있습니다. 특히 상업적 목적으로 타사의 데이터를 사용할 때는 법률 자문을 권장합니다. 자세한 윤리 가이드는 Wikipedia의 웹 스크래핑 문서DrissionPage 공식 GitHub 저장소를 참고하세요.

핵심 요약 (Key Takeaways)

DrissionPage의 핵심 가치: 하나의 도구로 HTTP 요청(SessionPage)과 브라우저 제어(ChromiumPage)를 전환하며 쿠키/세션을 유지할 수 있습니다. WebPage 객체로 모드를 전환하면 별도의 상태 동기화 없이 두 세계를 오갈 수 있습니다.

  • 비용 절감: 항상 브라우저를 띄울 필요 없이 필요한 순간에만 ChromiumPage로 전환하면 메모리와 시간을 절약할 수 있습니다. SessionPage는 약 50MB 메모리, ChromiumPage는 300MB+를 사용합니다.
  • 프록시 통합: SessionPage는 set_proxies(), ChromiumPage는 ChromiumOptions.set_proxy()로 설정합니다. ProxyHat 게이트웨이(gate.proxyhat.com:8080)를 사용해 주거 프록시를 구성하세요.
  • listen 활용: listen.start()로 백그라운드 XHR을 캡처하면 숨겨진 API를 발견할 수 있습니다. 이후 SessionPage로 해당 API를 직접 호출하여 속도를 극대화하세요.
  • 세션 고정: ProxyHat 사용자명에 session-{id}를 포함하면 스티키 세션을 유지할 수 있습니다. 로그인 상태를 유지해야 하는 작업에 필수적입니다.
  • 윤리 준수: robots.txt 확인, 요청 속도 제한, 공식 API 우선 사용, 개인정보 보호법 준수를 생활화하세요.

ProxyHat의 주거 프록시는 프라이싱 페이지에서 확인할 수 있으며, 공식 문서에서 인증 및 세션 관리 방법을 자세히 알 수 있습니다. DrissionPage 튜토리얼 시리즈의 다음 글에서는 listen을 활용한 고급 API 역엔지니어링 패턴을 다룰 예정입니다.

시작할 준비가 되셨나요?

AI 필터링으로 148개국 이상에서 5천만 개 이상의 레지덴셜 IP에 액세스하세요.

가격 보기레지덴셜 프록시
← 블로그로 돌아가기