Scarnox · Blog

차단되지 않고 스크래핑하기: 코드가 포함된 실전 가이드

스크래핑 중 차단되는 것은 보통 세 가지 중 하나를 뜻합니다. 요청을 너무 많이, 너무 빨리 보냈거나, 클라이언트가 브라우저나 알려진 봇과 전혀 달라 보였거나, IP 주소가 사이트가 덜 신뢰하는 목록에 올라 있는 경우입니다. 몇 가지 습관으로 셋 모두를 줄일 수 있습니다. 차단을 일찍 알아차리고, 사이트가 밀어낼 때 속도를 줄이고, 일관되고 정직한 신원을 유지하고, 프록시는 적절한 곳에서만 쓰는 것입니다. 이 가이드는 각 항목을 동작하는 코드와 함께 살펴봅니다. 스크래핑이 허용된 사이트에서만 사용하세요.

차단 알아보기

차단은 항상 오류 페이지처럼 보이지 않습니다. 다음을 살펴보세요.

실패할 때마다 상태 코드와 본문의 짧은 샘플을 기록하세요. 로그에서 보이지 않는 차단은 고칠 수 없습니다.

재시도로 물러서기

사이트가 "속도를 늦추라"고 말하면, 코드는 조금이 아니라 충분히 느려져야 합니다. 시도 횟수 제한이 있는 지수 백오프가 표준적인 방법입니다. 사이트가 Retry-After를 보내면 그것도 존중합니다.

import time
import requests

session = requests.Session()
session.headers.update({
    "User-Agent": "ExampleBot/1.0 (+https://example.com/bot)",
    "Accept-Language": "en-US,en;q=0.9",
})

def polite_get(url: str, max_attempts: int = 4) -> requests.Response:
    delay = 2.0
    resp = None
    for _ in range(max_attempts):
        resp = session.get(url, timeout=30)
        if resp.status_code not in (429, 503):
            return resp
        retry_after = resp.headers.get("Retry-After", "")
        wait = float(retry_after) if retry_after.isdigit() else delay
        time.sleep(wait)
        delay *= 2
    return resp  # 여전히 차단됨: 호출자가 처리하도록 마지막 응답을 반환합니다

resp = polite_get("https://example.com/products?page=1")
print(resp.status_code, len(resp.text))

이 함수가 하지 않는 일에 주목하세요. 403은 재시도하지 않으며, 하나의 차단을 피하려고 신원을 바꿔 가며 돌지도 않습니다. 403은 풀어야 할 퍼즐이 아니라 멈추라는 결정입니다.

차단을 단계별로 진단하기

실행이 실패하기 시작하면, 다른 것을 바꾸기 전에 다음 점검을 거치세요.

  1. 처음 실패한 URL과 상태 코드를 보세요. 차단은 보통 무작위가 아니라 특정 지점에서 시작됩니다.
  2. 첫 실패 직전 몇 분간의 요청 빈도를 비교하세요. 순간적인 폭주가 가장 흔한 원인입니다.
  3. 실패가 한 경로, 한 섹션, 또는 하루 중 특정 시간에만 묶여 있는지 확인하세요.
  4. 같은 URL을 일반 브라우저에서 한 번 직접 열어 보세요. 브라우저가 로드하면 차이는 여러분의 요청 패턴에 있습니다. 브라우저도 차단되면, 사이트가 지금은 여러분에게 페이지를 보여 주지 않기로 한 것입니다.
  5. 그다음에야 코드를 바꾸세요. 먼저 속도를 늦추고, 두 번째로 백오프를 추가하고, 마지막으로 신원을 점검하세요.

여러 가지를 한꺼번에 바꾸면 무엇이 도움이 됐는지 알 수 없습니다.

일관되고 정직한 신원 유지하기

스크래퍼는 요청마다 신원이 바뀌거나, 나머지 트래픽과 맞지 않을 때 차단됩니다. 하나의 명확한 User-Agent를 가진 단일 세션이 가장 단순하고 안정적인 신원입니다. 봇에 이름을 붙이고, 연락처 링크를 추가하고, 일반 클라이언트가 보낼 헤더만 보내세요. 여러 다른 방문자처럼 보이려고 User-Agent를 바꾸는 것은 회피의 한 형태이며, 차단을 줄이기보다 늘리는 경향이 있습니다.

사이트가 브라우저와 단순 HTTP 클라이언트에 서로 다른 콘텐츠를 제공한다면, 그 페이지에는 실제 브라우저를 쓰고 같은 속도 제한을 유지하세요. 그것은 정당한 경로이며, 요청 패턴도 합리적으로 유지됩니다.

프록시는 신중하게 쓰기

프록시는 요청이 나오는 주소를 바꿉니다. 테스트가 허용된 사이트에서 특정 지역을 테스트하거나, 자신의 인프라에 부하를 분산하는 것처럼 정당한 필요를 위한 도구입니다. 사이트가 여러분에게 건 제한에서 빠져나가는 방법이 아닙니다. 프록시 형식은 프록시 작업 유형에서 쓰는 것과 같습니다.

proxies = {
    "http": "http://user:pass@proxy.example.net:8000",
    "https": "http://user:pass@proxy.example.net:8000",
}
resp = session.get("https://example.com/products", proxies=proxies, timeout=30)

프록시 유형을 고르는 것은 별도의 문제이며, 주거용 vs 데이터센터 프록시와 스크래핑용 회전 프록시에서 다룹니다.

차단이 captcha로 바뀔 때

일부 사이트는 속도 문제에 강한 차단 대신 captcha로 답합니다. 합리적인 순서는 멈추기, 속도 늦추기, 규칙을 다시 확인하기이며, 그다음에야 풀이를 고려합니다. PopularCaptcha 위젯의 경우, Scarnox의 실시간 API는 h-captcha-response 필드에 제출할 토큰을 돌려줍니다. 다른 captcha 유형은 실시간 목록을 확인하세요. reCAPTCHA, Cloudflare Turnstile, GeeTest, AWS WAF, Arkose 지원은 출시 예정입니다. 자세한 안내는 웹 스크래핑 captcha에 있습니다.

사이트에서 차단이 보이기 시작했다면, 원인은 거의 항상 요청 패턴입니다. 스크래핑할 때 captcha 피하기에서 이를 막는 습관을 다룹니다.

책임 있게 스크래핑하기

다음 단계