Scraping

대규모 웹 스크래핑: 공개 프록시를 사용해야 하는 시기와 이유

5 min read Published Updated 993 words

프록시 로테이션은 해결책이 아닌 임시방편에 불과합니다. 대부분의 스크래핑 작업이 실패하는 이유는 IP 주소만이 안티봇 시스템이 측정하는 유일한 신호라고 생각하기 때문입니다. 현실은 최신 봇 관리자(Akamai Bot Manager, Cloudflare Turnstile, Datadome)가 출발지 IP보다 훨씬 더 많은 정보를 핑거프린팅한다는 것입니다. 무료 공용 프록시 풀을 로테이션하는 것은 이러한 시스템에 대해 거의 효과가 없으며, 오히려 상황을 악화시키는 경우가 많습니다.

IP 로테이션의 환상

요청마다 IP를 로테이션하면 스크래퍼임을 스스로 드러내게 됩니다. 사람의 브라우징 패턴은 고정 세션(단일 IP를 수 분 또는 수 시간 동안 유지, 일관된 브라우저 핑거프린트, 예측 가능한 요청 간격)을 보여줍니다. requestsSession 객체와 로테이션 프록시 목록을 사용하는 도구는 이러한 모든 신호를 깨뜨립니다. Akamai의 X-Akamai-Device-Fingerprint 헤더와 Cloudflare의 cf-request-id 상관 관계는 TLS 매개변수, HTTP/2 설정, 타이밍이 동일하게 유지될 때 서로 다른 IP의 요청을 연결할 수 있습니다. Datadome의 JavaScript 챌린지는 프록시 변경에도 살아남는 헤드리스 브라우저 아티팩트를 확인합니다. 전체 클라이언트 핑거프린트를 로테이션하지 않고 IP만 로테이션하는 것은 번호판만 바꾸고 같은 차를 운전하는 것과 같아서, 톨게이트 카메라는 여전히 당신을 식별합니다.

기본 IP 기반 속도 제한(예: JavaScript 챌린지 없이 분당 10회 요청 제한)만 사용하는 사이트를 대상으로 저속, 저용량 스크래핑을 할 때는 단일 리지덴셜 IP 하나로 충분한 경우가 많습니다. 저는 정부 데이터 포털과 공개 API를 대상으로 하나의 고정 IP와 정중한 time.sleep(2)를 사용하여 수년간 스크래퍼를 운영해 왔습니다. 프록시가 필요 없었습니다. 규칙은 간단합니다. 50회 요청 후에도 챌린지 페이지나 CAPTCHA가 나타나지 않으면 로테이션이 필요하지 않습니다.

IP 주소 너머: 핑거프린팅

안티봇 시스템은 이제 요청당 수십 개의 신호를 수집합니다. User-Agent 문자열은 위조하기 쉽지만, Accept-Language, Sec-CH-UA, Connection, Accept-Encoding 순서는 그렇지 않습니다. 더 결정적인 것은 JA3 해시(JA3 참조)로 표준화된 TLS 핑거프린팅으로, 암호화 스위트 순서와 TLS 확장 목록을 통해 클라이언트 라이브러리를 식별합니다. Python의 requests 라이브러리(urllib3를 통해)는 Chrome 124와 구별되는 JA3 해시를 생성합니다. Cloudflare의 Turnstile과 Datadome은 모두 JA3를 확인합니다. 동일한 TLS 스택을 유지하면서 IP만 로테이션하면 모든 요청이 동일한 자동화 클라이언트가 종단 노드만 바꿔가며 접속하는 것처럼 보입니다. 무료 프록시는 오래된 OpenSSL 버전을 실행하거나 이미 블랙리스트에 오른 봇 유사 TLS 구성을 사용하는 경우가 많아 이 문제를 더 악화시킵니다.

HTTP/2 핑거프린팅은 더 나아갑니다. SETTINGS 프레임, 윈도우 업데이트 값, 스트림 동시성 매개변수는 Akamai의 Bot Manager가 세션 간에 추적하는 고유한 "HTTP/2 핑거프린트"를 형성합니다. HTTP/2 구현까지 함께 로테이션하지 않는 프록시 풀은 클러스터링하기 쉽습니다. 이러한 검사를 회피하는 유일한 방법은 실제 브라우저 엔진(Puppeteer, Playwright)을 사용하거나 특정 브라우저 버전을 모방하도록 정교하게 제작된 TLS/HTTP 스택을 사용하는 것입니다. 그리고 그 경우에도 주어진 세션의 요청 간에 동일한 핑거프린트를 유지해야 합니다.

무료 공용 프록시 풀의 경제학

제 테스트에서 무료 공용 프록시 목록의 실패율은 60~80%입니다. 대부분의 프록시는 처음부터 작동하지 않거나, 호스트에 의해 제한되거나, 주요 봇 관리자에 의해 이미 플래그가 지정되어 있습니다. 공개 디렉터리에서 수집한 무료 SOCKS5 프록시의 평균 수명은 15분 미만입니다. 500개의 프록시를 로테이션하는 풀을 유지하려면 시간당 수천 개의 IP를 소모하게 되며, 요청의 80%는 타임아웃되거나 403을 반환합니다. 대역폭은 신뢰할 수 없고, 지연 시간 급증은 흔하며, 많은 무료 프록시가 광고를 삽입하거나 응답 본문을 수정합니다. 유료 리지덴셜 프록시 네트워크(예: Bright Data, Oxylabs)는 95% 이상의 성공률과 고정 세션 옵션을 제공하지만, GB당 10~20달러의 비용이 듭니다. 규모 면에서 리지덴셜 프록시는 고가치 대상에 대한 IP 기반 차단을 우회해야 할 때만 경제성이 있습니다. 그 외의 경우에는 적절한 요청 속도 조절을 갖춘 단일 클린 IP가 혼란스러운 무료 풀보다 성능이 뛰어납니다.

로테이션이 실제로 효과적인 경우

프록시 로테이션은 IP별로 초기화되는 IP 기반 속도 제한이라는 특정 위협에 효과적입니다. 사이트가 단순한 X-Forwarded-For 검사나 IP별 토큰 버킷을 사용하는 경우, 요청마다 로테이션하면 제한을 우회할 수 있습니다. 이는 소규모 전자상거래 사이트나 봇 탐지를 업데이트하지 않은 레거시 API에서 흔히 볼 수 있습니다. 이런 경우 무료 프록시 풀도 작동하지만, 실패한 프록시를 폐기하고 빠르게 새 프록시로 교체하는 재시도 로직을 구현해야 합니다.

다음은 requests와 재시도-로테이션 루프를 사용한 최소한의 Python 예제입니다. proxy_list에 프록시 URL 목록이 있고 url 대상이 있다고 가정합니다.

import requests
from itertools import cycle

proxy_pool = cycle(proxy_list)
max_retries = 5

for attempt in range(max_retries):
    proxy = next(proxy_pool)
    try:
        resp = requests.get(
            url,
            proxies={"http": proxy, "https": proxy},
            timeout=10,
            headers={"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) ..."}
        )
        if resp.status_code == 200:
            break
    except (requests.ConnectionError, requests.Timeout):
        continue
else:
    raise RuntimeError("All proxies failed")

이 패턴은 사이트의 탐지가 순수하게 IP 기반일 때만 작동합니다. 요청 사이에 time.sleep(random.uniform(1,3))를 추가하여 사람의 타이밍을 모방하십시오. Turnstile이나 Datadome을 실행하는 사이트의 경우 이 코드는 항상 실패합니다. 프록시에 관계없이 챌린지 페이지가 403 또는 CAPTCHA를 반환하기 때문입니다. 이러한 경우에는 로테이션 IP 목록이 아닌 실제 핑거프린트를 가진 헤드리스 브라우저가 필요합니다.

고정 세션(관련 요청 집합에 대해 동일한 IP 유지)은 종종 요청별 로테이션보다 더 효과적입니다. 많은 전자상거래 사이트는 브라우징 세션(예: 장바구니에 항목 추가, 결제) 동안 단일 IP를 기대합니다. 세션 중간에 로테이션하면 사기 플래그가 트리거됩니다. 프록시 풀을 사용하되 요청별이 아닌 세션별로 하나의 IP를 할당하십시오. 무료 프록시는 동일한 IP가 여러 사용자에 의해 재사용되기 때문에 고정 세션을 거의 지원하지 않으며, 세션 데이터 교차 오염이 발생합니다. 유료 리지덴셜 프록시는 자연스러운 브라우징 행동에 부합하는 고정 세션 지속 시간(5~30분)을 제공합니다.

대상의 탐지 스택을 이해한 경우에만 로테이션을 선택하십시오. 먼저 단일 IP로 테스트하십시오. 속도 제한에 도달한 경우에만 로테이션을 추가하십시오. 그리고 프로덕션에서 무료 프록시에 절대 의존하지 마십시오. 실패율로 인해 엔지니어링 시간과 데이터 손실 비용이 저렴한 리지덴셜 요금제보다 더 많이 들 수 있습니다.