2026년 트립어드바이저 리뷰 스크래핑 완벽 가이드: 코드 예제와 실전 노하우

트립어드바이저 호텔·레스토랑 리뷰를 스크래핑하는 개발자 중심 가이드입니다. GraphQL 엔드포인트 활용, curl_cffi TLS 지문 모방, ProxyHat 주거 프록시 회전 전략, 속도 제한 및 윤리적 수집까지 모두 다룹니다.

How to Scrape TripAdvisor Reviews in 2026: A Developer's Guide

법적 고지: 이 가이드는 트립어드바이저의 공개 데이터에 접근하는 합법적인 방법만 다룹니다. 트립어드바이저의 이용약관(Terms of Service)을 반드시 확인하고 준수해야 하며, 미국에서는 컴퓨터 사기 및 남용 방지법(CFAA)이, EU에서는 GDPR이 적용됩니다. 로그인이 필요한 데이터, 개인정보, 저작권 보호 콘텐츠는 수집하지 마십시오. 본 내용은 교육 목적이며, 실제 스크래핑 전 법률 자문을 권장합니다.

트립어드바이저 리뷰 스크래핑이란 무엇인가?

트립어드바이저 리뷰 스크래핑은 TripAdvisor의 /Hotel_Review/Restaurant_Review 페이지에서 공개된 리뷰 텍스트, 평점, 작성일, 순위 데이터를 자동화된 방식으로 수집하는 작업을 말합니다. 여행 인텔리전스, 리뷰 분석, 경쟁사 모니터링을 수행하는 개발자들에게 이 데이터는 고객 감정 트렌드, 평점 분포, 계절별 리뷰 패턴을 파악하는 핵심 소스입니다.

하지만 트립어드바이저는 단순 HTML 스크래핑을 극도로 어렵게 만드는 정교한 안티봇 스택을 운영합니다. 2026년 기준, 성공적인 트립어드바이저 데이터 추출을 위해서는 TLS 지문 모방, GraphQL 내부 엔드포인트 이해, 그리고 주거(residential) 프록시 회전이 필수적입니다. 이 가이드는 이 모든 기술을 실제 코드 예제와 함께 다룹니다.

공개 데이터의 범위: 무엇을 수집할 수 있는가?

트립어드바이저에서 로그인 없이 접근할 수 있는 공개 데이터는 다음과 같습니다:

  • 리스팅 페이지: 호텔/레스토랑 이름, 전체 평점, 리뷰 수, 순위, 위치 정보
  • 개별 리뷰: 리뷰 제목, 본문 텍스트(일부 잘림), 평점(1-5), 작성일, 작성자 닉네임
  • 카테고리별 평점: 청결도, 서비스, 가격 대비 만족도 등 세부 평점

주의할 점은 트립어드바이저가 리뷰를 지연 로딩(lazy-loading)한다는 것입니다. 페이지 초기 HTML에는 첫 5-10개 리뷰만 포함되어 있고, 나머지는 스크롤 또는 페이지네이션 이벤트에 의해 동적으로 로드됩니다. 이는 브라우저 렌더링 없이 단순 HTTP 요청만으로는 전체 리뷰를 얻을 수 없음을 의미합니다. 이 문제를 해결하는 핵심이 바로 내부 GraphQL 엔드포인트입니다.

트립어드바이저의 안티봇 스택: 왜 데이터센터 IP가 차단되는가

트립어드바이저는 두 가지 강력한 안티봇 시스템을 결합하여 운영됩니다:

Cloudflare + DataDome 이중 방어

DataDome은 자동화된 트래픽을 탐지하는 전문 봇 방지 솔루션으로, 트립어드바이저와 같은 대형 플랫폼에서 널리 사용됩니다. Cloudflare의 WAF와 결합하여 요청의 TLS 핑거프린트, HTTP/2 프레임 순서, 헤더 일관성, IP 평판을 종합적으로 분석합니다.

핵심 문제는 TLS/HTTP2 지문(TLS fingerprinting)입니다. 일반 Python requests 라이브러리가 생성하는 TLS ClientHello 메시지는 브라우저와 확연히 다릅니다. JA3/JA4 해시로 이 차이를 식별하므로, 아무리 User-Agent를 Chrome으로 설정해도 TLS 레이어에서 즉시 차단됩니다. MDN의 User-Agent 문서에서도 헤더만으로는 봇 탐지를 우회할 수 없음을 명시하고 있습니다.

데이터센터 IP 자동 차단

데이터센터 IP 대역(AWS, GCP, Azure 등)은 DataDome의 IP 평판 데이터베이스에 등록되어 있어, 헤더가 완벽해도 403 Forbidden 또는 CAPTCHA 챌린지를 반환합니다. 이것이 주거(residential) 프록시가 필수적인 이유입니다. 주거 IP는 실제 ISP에서 할당된 IP처럼 보이므로, IP 평판 검사를 통과합니다.

내부 GraphQL 엔드포인트: /data/graphql/ids

트립어드바이저의 프론트엔드는 리뷰를 동적으로 로드하기 위해 내부 GraphQL 엔드포인트 /data/graphql/ids를 사용합니다. 이 엔드포인트에 POST 요청을 보내면 구조화된 JSON 형태로 리뷰 데이터를 반환합니다.

주요 특징:

  • 메서드: POST
  • 필수 헤더: X-Requested-By 토큰 (페이지 HTML에서 추출 가능), Content-Type: application/json
  • 바디: GraphQL 쿼리 문자열과 변수(리스팅 ID, 오프셋, 페이지 크기)
  • 반환 데이터: 리뷰 노드(title, rating, text, publishedDate, userProfile 등)

이 방식의 장점은 HTML 파싱이 불필요하고, 페이지네이션을 오프셋 기반으로 제어할 수 있다는 것입니다. 하지만 동일한 안티봇 스택이 GraphQL 엔드포인트에도 적용되므로, 여전히 TLS 지문 모방과 주거 프록시가 필요합니다.

지역별 리스팅과 지리 타겟팅

트립어드바이저는 방문자의 위치에 따라 리스팅 순서와 표시되는 리뷰가 달라집니다. 예를 들어 영국 런던에서 접근하면 현지 리뷰가 우선 표시됩니다. 이 때문에 ProxyHat의 국가/도시 지리 타겟팅 기능(-country-GB-city-london)이 중요합니다. 특정 지역의 현지화된 리뷰를 수집하려면 해당 지역의 주거 IP를 사용해야 합니다. ProxyHat 위치 목록에서 지원되는 모든 국가와 도시를 확인할 수 있습니다.

실전 Python 예제: curl_cffi + ProxyHat로 GraphQL 리뷰 수집

다음 예제는 curl_cffi 라이브러리를 사용하여 Chrome TLS 지문을 모방하고, ProxyHat 주거 프록시를 통해 트립어드바이저 GraphQL 엔드포인트에 POST 요청을 보내는 완전한 코드입니다.

from curl_cffi import requests
import json

# ProxyHat 주거 프록시 설정 (영국 런던 지리 타겟팅)
proxy_url = "http://user-country-GB-city-london:YOUR_PASSWORD@gate.proxyhat.com:8080"

# GraphQL 엔드포인트
graphql_url = "https://www.tripadvisor.com/data/graphql/ids"

# X-Requested-By 토큰 (리스팅 페이지 HTML에서 추출)
x_requested_by = "T4S2C5R3N4M2E1"  # 예시 값 — 실제 페이지에서 추출

# GraphQL 쿼리: 리뷰 노드 요청
query = """
query ReviewListQuery($locationId: Int!, $offset: Int!, $limit: Int!) {
  locationReviews(locationId: $locationId, offset: $offset, limit: $limit) {
    reviewList {
      reviews {
        title
        rating
        text
        publishedDate
      }
    }
  }
}
"""

variables = {
    "locationId": 1234567,   # 실제 리스팅 ID로 교체
    "offset": 0,
    "limit": 10
}

headers = {
    "X-Requested-By": x_requested_by,
    "Content-Type": "application/json",
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36",
    "Referer": "https://www.tripadvisor.com/Hotel_Review-g186338-d1234567-Reviews-Example_Hotel-London_England.html",
    "Accept": "application/json",
    "Accept-Language": "en-GB,en;q=0.9",
}

# Chrome TLS 지문 모방으로 POST 요청
response = requests.post(
    graphql_url,
    headers=headers,
    json={"query": query, "variables": variables},
    proxies={"http": proxy_url, "https": proxy_url},
    impersonate="chrome131",
    timeout=30
)

if response.status_code == 200:
    data = response.json()
    reviews = data.get("data", {}).get("locationReviews", {}).get("reviewList", {}).get("reviews", [])
    for review in reviews:
        print(f"제목: {review.get('title', 'N/A')}")
        print(f"평점: {review.get('rating', 'N/A')}/5")
        print(f"날짜: {review.get('publishedDate', 'N/A')}")
        # 리뷰 텍스트는 종종 잘림(truncated) 상태로 반환됨
        text = review.get('text', '')
        print(f"본문: {text[:200]}..." if len(text) > 200 else f"본문: {text}")
        print("---")
else:
    print(f"요청 실패: {response.status_code}")
    print(response.text[:500])

위 코드의 핵심 포인트:

  • impersonate="chrome131" — curl_cffi가 Chrome 131의 TLS ClientHello, HTTP/2 SETTINGS 프레임, 헤더 순서를 그대로 모방합니다.
  • ProxyHat 사용자명에 -country-GB-city-london을 포함하여 런던 주거 IP로 요청을 보냅니다.
  • X-Requested-By 토큰은 리스팅 페이지 HTML 내 인라인 스크립트에서 정규식으로 추출해야 합니다. 토큰은 세션 기반이므로 주기적으로 갱신하세요.

Node.js 예제 (간소화)

const axios = require('axios');

const proxyUrl = 'http://user-country-GB-city-london:YOUR_PASSWORD@gate.proxyhat.com:8080';

async function fetchReviews() {
  const response = await axios.post(
    'https://www.tripadvisor.com/data/graphql/ids',
    {
      query: `query ReviewListQuery($locationId: Int!, $offset: Int!, $limit: Int!) {
        locationReviews(locationId: $locationId, offset: $offset, limit: $limit) {
          reviewList { reviews { title rating text publishedDate } }
        }
      }`,
      variables: { locationId: 1234567, offset: 0, limit: 10 }
    },
    {
      headers: {
        'X-Requested-By': 'T4S2C5R3N4M2E1',
        'Content-Type': 'application/json',
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
      },
      proxy: { host: 'gate.proxyhat.com', port: 8080, auth: { username: 'user-country-GB-city-london', password: 'YOUR_PASSWORD' } },
      timeout: 30000
    }
  );
  console.log(response.data);
}
fetchReviews().catch(console.error);
참고: Node.js에서는 TLS 지문 모방을 위해 curl-impersonate 바인딩 또는 undici의 커스텀 TLS 옵션 사용을 고려하세요. 일반 axios만으로는 DataDome의 TLS 검사를 통과하기 어렵습니다.

현실적인 속도 제한, 세션 관리, 페이지네이션

속도 제한 가이드라인

실제 운영 환경에서 IP당 권장 요청 속도는 대략 50-100 리스팅/시간입니다. 이를 초과하면 DataDome이 해당 IP에 대해 약 5-10분의 일시적 차단을 적용합니다. 차단이 발생하면 즉시 백오프(backoff)를 수행해야 합니다.

지표권장 값설명
요청 간격2-5초각 GraphQL 요청 사이의 대기 시간
IP당 시간당 요청50-100주거 IP 기준, 초과 시 일시 차단
차단 후 대기5-10분403 응답 시 백오프
동시 세션10-20ProxyHat 세션 ID로 분산
페이지 크기(limit)10GraphQL variables의 limit 값

스티키 세션으로 연속성 유지

여러 페이지의 리뷰를 순차적으로 수집할 때, 각 요청마다 다른 IP가 할당되면 DataDome이 비정상 패턴으로 간주할 수 있습니다. ProxyHat의 -session- 플래그를 사용하면 동일한 세션 ID에 대해 동일한 IP가 유지됩니다.

# 세션 유지 — 동일 IP로 연속 요청
proxy_url = "http://user-session-hotel123-session-1:YOUR_PASSWORD@gate.proxyhat.com:8080"

# 페이지네이션: 오프셋 증가
for offset in range(0, 500, 10):
    variables["offset"] = offset
    response = requests.post(graphql_url, headers=headers, json={"query": query, "variables": variables}, proxies={"http": proxy_url, "https": proxy_url}, impersonate="chrome131", timeout=30)
    if response.status_code == 403:
        print(f"차단 감지 — 5분 대기")
        time.sleep(300)
        continue
    # 응답 처리...
    time.sleep(random.uniform(2, 5))

백오프 전략

403 응답을 받으면 지수 백오프(exponential backoff)를 적용하세요. 첫 차단 시 60초, 두 번째 120초, 세 번째 300초 대기 후 재시도합니다. 3회 연속 차단 시 해당 세션을 폐기하고 새 세션 ID로 전환합니다.

윤리적 스크래핑: GDPR, 개인정보, 공식 API

집계 데이터만 수집

리뷰 분석의 목적이 감정 분석이나 트렌드 파악이라면, 개별 작성자의 식별 정보(닉네임, 프로필 사진, 위치)는 수집하지 마세요. 평점, 리뷰 텍스트, 작성일만으로도 대부분의 분석 목적을 달성할 수 있습니다. 리뷰 텍스트 역시 개인 식별 정보(PII)를 포함할 수 있으므로, 저장 전 자동 필터링을 권장합니다.

GDPR 준수 (EU)

GDPR에 따라 EU 거주자의 개인 데이터를 처리할 때는 명확한 법적 근거가 필요합니다. 리뷰 작성자의 닉네임이나 프로필 정보를 저장하는 것은 개인정보 처리에 해당할 수 있습니다. EU 리뷰어의 데이터를 수집할 경우 다음을 고려하세요:

  • 데이터 최소화 원칙: 분석에 꼭 필요한 필드만 저장
  • 익명화: 닉네임 대신 해시값 저장
  • 보유 기간 제한: 분석 완료 후 데이터 삭제

공식 Content API를 언제 사용할까?

트립어드바이저는 TripAdvisor Content API를 공식적으로 제공합니다. 이 API는 리스팅 정보, 평점, 리뷰 수 등을 정식으로 제공하며, 안티봇 우회가 필요 없습니다. 상업적 목적이거나 대규모 정기 수집이 필요하다면, 공식 API 라이선스를 먼저 검토하세요. 다만 공식 API는 전체 리뷰 텍스트를 제공하지 않을 수 있으며, 사용량 제한과 비용이 발생합니다.

기준공식 Content API웹 스크래핑
법적 안정성높음 (공식 라이선스)낮음 (ToS 위반 가능)
전체 리뷰 텍스트제한적가능 (공개 데이터)
비용API 플랜에 따라 유료프록시 비용
안티봇 우회불필요필수 (TLS 모방 + 주거 프록시)
속도 제한API 정책에 따름50-100/시간/IP

ProxyHat 설정 및 관련 리소스

ProxyHat은 주거, 모바일, 데이터센터 프록시를 제공하며, 프록시 가격에서 플랜을 확인할 수 있습니다. 트립어드바이저 스크래핑에는 주거 프록시를 권장하며, 게이트웨이 주소 gate.proxyhat.com의 HTTP 포트 8080 또는 SOCKS5 포트 1080을 사용합니다.

더 자세한 연결 방법은 ProxyHat 공식 문서를 참고하세요. 웹 스크래핑 전반의 사용 사례는 웹 스크래핑 사용 사례에서, SERP 추적 관련 정보는 SERP 추적 페이지에서 확인할 수 있습니다.

핵심 요약 (Key Takeaways)

  • 트립어드바이저 리뷰 스크래핑에는 단순 HTML 파싱이 아닌 내부 GraphQL 엔드포인트(/data/graphql/ids) 활용이 효율적입니다.
  • Cloudflare + DataDome 안티봇 스택으로 인해 데이터센터 IP는 자동 차단됩니다. 주거 프록시가 필수입니다.
  • curl_cffiimpersonate="chrome131" 옵션으로 Chrome TLS 지문을 모방하세요. 일반 requests로는 차단됩니다.
  • ProxyHat 지리 타겟팅(-country-GB-city-london)으로 현지화된 리뷰에 접근할 수 있습니다.
  • 속도 제한은 IP당 약 50-100 리스팅/시간이며, 차단 시 5-10분 백오프를 적용하세요.
  • 스티키 세션(-session-)으로 페이지네이션 중 IP 일관성을 유지하세요.
  • 개인정보 수집을 최소화하고 GDPR을 준수하세요. 상업적 목적이라면 공식 Content API를 먼저 검토하세요.

FAQ

트립어드바이저 리뷰 스크래핑을 2026년에도 가능한가요?

네, 가능합니다. 단, 단순 HTML 스크래핑이 아닌 내부 GraphQL 엔드포인트를 활용하고, Chrome TLS 지문을 모방하는 라이브러리(curl_cffi 등)를 사용하며, 주거 프록시로 IP 회전을 수행해야 합니다. 2026년 기준 DataDome의 탐지는 더 정교해졌지만, 적절한 TLS 모방과 주거 IP를 조합하면 공개 리뷰 데이터에 접근할 수 있습니다.

어떤 프록시 유형이 트립어드바이저 스크래핑에 가장 적합한가요?

주거(residential) 프록시가 가장 적합합니다. 데이터센터 IP는 DataDome의 IP 평판 데이터베이스에 등록되어 있어 헤더가 완벽해도 차단됩니다. 모바일 프록시도 작동하지만 비용이 높고 속도가 느릴 수 있습니다. ProxyHat 주거 프록시를 사용하고, 국가/도시 지리 타겟팅으로 현지화된 리뷰에 접근하는 것을 권장합니다.

트립어드바이저 리뷰 스크래핑 시 차단을 어떻게 피하나요?

세 가지를 결합하세요: (1) curl_cffi로 Chrome TLS 지문 모방, (2) ProxyHat 주거 프록시로 IP 회전, (3) IP당 50-100 요청/시간 속도 제한 준수. 403 응답 시 5-10분 백오프를 적용하고, 스티키 세션으로 페이지네이션 중 IP 일관성을 유지하세요. 요청 간 2-5초의 랜덤 대기 시간을 추가하면 자연스러운 패턴으로 보입니다.

트립어드바이저 리뷰 스크래핑은 합법인가요?

공개 데이터(로그인 없이 접근 가능한 데이터)의 수집 자체는 일반적으로 허용되지만, 트립어드바이저의 이용약관 위반 여부, 미국 CFAA, EU GDPR 등 관련 법률을 반드시 검토해야 합니다. 개인 식별 정보(닉네임, 프로필) 수집을 피하고, 집계된 리뷰 데이터(평점, 텍스트, 날짜)만 수집하는 것이 윤리적이고 법적 리스크가 낮습니다. 상업적 목적이라면 공식 Content API를 먼저 검토하세요.

GraphQL 엔드포인트의 X-Requested-By 토큰은 어떻게 얻나요?

X-Requested-By 토큰은 리스팅 페이지(/Hotel_Review 또는 /Restaurant_Review URL)의 HTML 내 인라인 JavaScript에서 찾을 수 있습니다. 페이지를 가져온 후 정규식으로 X-Requested-By 값 또는 관련 설정 객체를 추출하세요. 이 토큰은 세션 기반이므로 만료될 수 있으며, 주기적으로 갱신해야 합니다. 토큰 추출 자체도 동일한 안티봇 스택을 통과해야 하므로 curl_cffi와 주거 프록시를 함께 사용하세요.

시작할 준비가 되셨나요?

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

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