내 Amazon 리뷰 스크레이퍼는 아무 문제 없이 6주를 버텼다 — 그러다 어느 아침, 200 OK만 돌려주고 페이지는 텅 비어 있었다. 에러도 없고, CAPTCHA도 없고, 수백 개의 리뷰 대신 HTML만 비어 있었다.
이 얘기가 낯익다면, 너만 그런 게 아니다. 2025년 말 Amazon은 전체 리뷰 페이지를 로그인 화면 뒤로 막아버렸고, 그 여파로 수많은 Python 스크립트가 하룻밤 사이에 망가졌다. 최근 몇 달 동안 Thunderbit에서 나는 이 문제를 양쪽에서 다뤄왔다 — AI 스크레이퍼를 직접 만들면서, 동시에 내 Python 리뷰 파이프라인도 유지하면서. 그래서 스크립트가 멈췄을 때 내게 있었으면 했던 가이드를 직접 쓰기로 했다. 이 글은 실제로 잘 작동하는 방법을 다룬다: 쿠키 기반 인증, Amazon의 CSS 위장에도 흔들리지 않는 안정적인 선택자, 10페이지 제한을 우회하는 방법, 봇 방어 대응, 그리고 원문 리뷰를 진짜 비즈니스 인사이트로 바꿔주는 감성 분석까지. 그리고 중간쯤에서 “이 코드를 다 내가 유지보수해야 한다고?” 싶어지면, Thunderbit가 Python 없이 2분 만에 같은 일을 해내는 방법도 보여주겠다.
Amazon 리뷰 스크래핑이란 무엇이고 왜 중요한가?
Amazon 리뷰 스크래핑은 고객 리뷰 데이터 — 별점, 리뷰 본문, 작성자 이름, 날짜, 검증 구매 배지 같은 정보 — 를 Amazon 상품 페이지에서 자동으로 추출하는 작업이다. Amazon이 2010년에 Product Advertising API에서 리뷰 콘텐츠를 아예 제거했고 다시 돌려놓지 않았기 때문에, 이 데이터에 접근할 수 있는 자동화된 경로는 사실상 스크래핑뿐이다.
숫자도 이걸 뒷받침한다. 구매자 95%가 구매 전 리뷰를 읽고, 94%는 Amazon이 제품 리뷰의 1순위 출처라고 말한다. 상품 페이지에 리뷰 5개만 보여줘도 전환율이 270%까지 오를 수 있다. 리뷰 감성을 체계적으로 분석하는 기업은 고객 유지율이 최대 15% 더 높다. 이건 추상적인 데이터 사이언스 연습이 아니다. 경쟁 정보, 제품 개선 신호, 마케팅 언어가 Amazon 서버에 그대로 공개돼 있는 셈이다.
Python으로 Amazon 리뷰를 스크래핑하는 이유
이 작업에는 여전히 Python이 가장 많이 쓰인다. 2024년 Stack Overflow Developer Survey에서 가장 많이 수요가 있는 언어였고, requests, BeautifulSoup, pandas, Scrapy 같은 생태계 덕분에 전업 개발자가 아니어도 웹 스크래핑을 시작하기 쉽다.
팀마다 이 데이터를 쓰는 방식도 다르다:
| 팀 | 사용 사례 | 추출하는 내용 |
|---|---|---|
| 제품 / R&D | 반복되는 불만 파악, 수정 우선순위 설정 | 1~2성 리뷰 본문, 키워드 빈도 |
| 영업 | 경쟁 제품 감성 추적 | 평점, 리뷰 수 추세 |
| 마케팅 | 광고 문구 작성용 고객 언어 찾기 | 긍정적인 리뷰 표현, 기능 언급 |
| Ecommerce 운영 | 자사 제품 감성의 시간 추적 | 별점 분포, 검증 구매 비율 |
| 시장 조사 | 카테고리 리더를 기능 기준으로 비교 | 여러 ASIN의 리뷰 데이터셋 |
한 생활용품 브랜드는 부정 리뷰를 파고들어 22%가 “논스틱 코팅이 닳는다”고 말하는 걸 발견했고, 제품을 다시 설계한 뒤 60일 만에 베스트셀러 1위로 돌아갔다. 한 피트니스 트래킹 회사는 “스트랩 때문에 피부가 자극된다”는 불만을 텍스트에서 찾아냈고, 라텍스 알레르기 이슈를 확인한 뒤 저자극 버전을 출시해 반품률을 40% 줄였다. 이런 게 바로 엔지니어링 비용을 정당화하는 ROI다.
로그인 화면: 왜 네 리뷰 스크래퍼가 갑자기 멈췄는가
2024년 11월 14일, Amazon은 상품의 전체 리뷰 페이지를 보려면 로그인하라고 요구하기 시작했다. 이 변화는 커뮤니티 포럼과 스크래핑 업체 블로그에서도 확인됐다. /product-reviews/{ASIN}/를 시크릿 창에서 열어보면, 리뷰 대신 로그인 페이지로 이동한다.

증상은 꽤 교묘하다. 스크립트는 200 OK를 받지만, HTML 본문에는 리뷰가 아니라 로그인 폼(name="email", id="ap_password")만 있다. 에러 코드도 없고, CAPTCHA도 없다. 그냥... 쓸모 있는 내용이 없다.
Amazon이 이 조치를 한 이유는 봇 방지와 지역별 규정 대응 때문이다. 적용이 늘 일정한 건 아니다 — 특히 1페이지에서는 새 브라우저 창이 몇 개의 리뷰를 먼저 불러오다가 막히기도 한다 — 하지만 대량 스크래퍼를 돌린다면 이 장벽이 항상 있다고 가정하는 게 맞다.
Amazon의 지역 도메인(.de, .co.uk, .co.jp)은 이 제한을 각각 따로 적용한다. 한 포럼 사용자가 말했듯, “국가마다 로그인해야 한다.” .com용 쿠키가 .co.uk에서는 먹히지 않는다.
상단 리뷰와 전체 리뷰: 로그인 없이 아직 볼 수 있는 것
Amazon 상품 페이지(/dp/{ASIN}/)에는 여전히 로그인 없이도 약 8개의 “상단 리뷰”가 보인다. 이 리뷰들은 Amazon 알고리즘이 수동으로 고른 것이고, 빠르게 분위기를 보기엔 괜찮지만 정렬, 필터링, 페이지 넘김은 안 된다.
전체 리뷰 페이지(/product-reviews/{ASIN}/)는 최신순 정렬, 별점 필터링, 수백 개 리뷰 탐색까지 가능하지만 로그인해야 한다.
몇 개만 빠르게 훑어볼 거면 상품 페이지를 긁으면 된다. 수백 개 또는 수천 개가 필요하면 인증을 처리해야 한다.
시작하기 전에 필요한 것: Python과 라이브러리 준비
코드를 쓰기 전에 먼저 준비할 것들:
- 난이도: 중간 정도 (Python에 익숙하고, HTML 기본 개념을 아는 정도)
- 소요 시간: 전체 파이프라인 약 45분, 기본 스크래핑은 약 10분
- 필수: Python 3.8+, Chrome 브라우저, 정상적인 Amazon 계정
핵심 라이브러리를 설치한다:
pip install requests beautifulsoup4 lxml pandas textblob
선택 사항(더 정교한 감성 분석용):
pip install transformers torch
ASIN이 뭐냐고? Amazon의 10자리 상품 식별자다. 상품 URL 어디에나 있다. 예를 들어 amazon.com/dp/B0BCNKKZ91에서 ASIN은 B0BCNKKZ91이다. 이 값을 리뷰 URL에 넣게 된다.
1단계: 쿠키 기반 인증으로 로그인 화면 넘기기
가장 안정적인 방법은 브라우저에서 Amazon에 로그인한 뒤 세션 쿠키를 복사해서 Python의 requests.Session()에 넣는 것이다. 이렇게 하면 Selenium 기반 로그인 자동화에서 자주 걸리는 CAPTCHA와 SMS 2단계 인증을 피할 수 있다.
필요한 쿠키는 7개다:
| 쿠키 이름 | 역할 |
|---|---|
session-id | 바뀌는 세션 ID |
session-id-time | 세션 타임스탬프 |
session-token | 바뀌는 세션 토큰 |
ubid-main | 사용자 브라우징 ID |
at-main | 주요 인증 토큰 |
sess-at-main | 세션 수준 인증 |
x-main | 이메일 기반 식별자 |
Chrome DevTools에서 쿠키 추출하는 방법
- Chrome에서 amazon.com에 로그인한다
- DevTools를 연다 (F12 또는 우클릭 → Inspect)
- Application → Storage → Cookies →
https://www.amazon.com로 이동한다 - 표에 있는 각 쿠키 이름을 찾아 값을 복사한다
- Python에서 세미콜론으로 구분된 문자열 형태로 정리한다
세션 설정은 이렇게 한다:
import requests
session = requests.Session()
# 여기에 쿠키 값을 붙여넣기
cookies = {
"session-id": "YOUR_SESSION_ID",
"session-id-time": "YOUR_SESSION_ID_TIME",
"session-token": "YOUR_SESSION_TOKEN",
"ubid-main": "YOUR_UBID_MAIN",
"at-main": "YOUR_AT_MAIN",
"sess-at-main": "YOUR_SESS_AT_MAIN",
"x-main": "YOUR_X_MAIN",
}
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/147.0.0.0 Safari/537.36",
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8",
"Accept-Language": "en-US,en;q=0.5",
}
session.cookies.update(cookies)
session.headers.update(headers)
중요: 모든 요청에 같은 session 객체를 사용해야 한다. 그래야 쿠키가 일관되게 유지되고 진짜 브라우저 세션처럼 보인다. 쿠키는 보통 며칠에서 몇 주까지 버티지만, 다시 로그인 화면으로 튕기기 시작하면 브라우저에서 새로 뽑아와야 한다.
다른 지역 도메인에서는 쿠키 이름이 조금 달라진다 — amazon.de는 at-main 대신 at-acbde를 쓰고, amazon.co.uk는 at-acbuk를 쓴다. 각 마켓은 따로 세션을 잡아야 한다.
2단계: 요청을 만들고 BeautifulSoup로 리뷰 HTML 파싱하기
Amazon 리뷰 URL 형식은 이렇게 생겼다:
https://www.amazon.com/product-reviews/{ASIN}/ref=cm_cr_arp_d_viewopt_srt?sortBy=recent&pageNumber=1
핵심 함수는 다음과 같다:
from bs4 import BeautifulSoup
import time, random
def get_soup(session, url):
time.sleep(random.uniform(2, 5)) # 예의 바른 딜레이
response = session.get(url, timeout=15)
# 로그인 화면 감지
if "ap_email" in response.text or "Amazon Sign-In" in response.text:
raise Exception("로그인 화면이 감지됨 — 쿠키를 새로 받아라")
if response.status_code != 200:
raise Exception(f"HTTP {response.status_code}")
return BeautifulSoup(response.text, "lxml")
작지만 유용한 팁 하나: 리뷰 페이지로 바로 가지 말고, 먼저 상품 페이지를 한 번 열어라. 세션이 더 자연스러운 브라우징 패턴을 갖게 된다.
# 먼저 상품 페이지 방문해서 실제 사용자처럼 보이게 하기
product_url = f"https://www.amazon.com/dp/{asin}"
session.get(product_url, timeout=15)
time.sleep(random.uniform(1, 3))
# 그다음 리뷰 페이지로 이동
reviews_url = f"https://www.amazon.com/product-reviews/{asin}/ref=cm_cr_arp_d_viewopt_srt?sortBy=recent&pageNumber=1"
soup = get_soup(session, reviews_url)
3단계: 안정적인 선택자로 리뷰 데이터를 추출하기(CSS 클래스 의존은 그만)
여기서 대부분의 2022~2023년 튜토리얼이 무너진다. Amazon은 CSS 클래스 이름을 계속 바꾼다. 어느 개발자가 답답해서 포럼에 쓴 것처럼, “span 태그 클래스 이름에 규칙이라고는 하나도 없더라.”
해결책은 data-hook 속성이다. Amazon은 리뷰 요소에 이 속성을 쓰고, 놀랍게도 꽤 안정적이다. 이건 Amazon 프론트엔드 자체가 의존하는 의미 있는 식별자라서 쉽게 랜덤화되지 않는다.
| 리뷰 필드 | 안정적인 선택자(data-hook) | 깨지기 쉬운 선택자(class) |
|---|---|---|
| 리뷰 본문 | [data-hook="review-body"] | .review-text-content (변동됨) |
| 별점 | [data-hook="review-star-rating"] | .a-icon-alt (애매함) |
| 리뷰 제목 | [data-hook="review-title"] | .review-title (가끔만) |
| 작성자 | span.a-profile-name | 비교적 안정적 |
| 리뷰 날짜 | [data-hook="review-date"] | .review-date (지역별 차이) |
| 검증 구매 여부 | [data-hook="avp-badge"] | span.a-size-mini |
data-hook 선택자를 쓰는 추출 코드는 이렇다:
import re
def extract_reviews(soup):
reviews = []
review_divs = soup.select('[data-hook="review"]')
for div in review_divs:
# 별점
rating_el = div.select_one('[data-hook="review-star-rating"]')
rating = None
if rating_el:
rating_text = rating_el.get_text(strip=True)
match = re.search(r'(\d\.?\d?)', rating_text)
if match:
rating = float(match.group(1))
# 제목
title_el = div.select_one('[data-hook="review-title"]')
title = title_el.get_text(strip=True) if title_el else ""
# 리뷰 본문
body_el = div.select_one('[data-hook="review-body"]')
body = body_el.get_text(strip=True) if body_el else ""
# 작성자
author_el = div.select_one('span.a-profile-name')
author = author_el.get_text(strip=True) if author_el else ""
# 날짜와 국가
date_el = div.select_one('[data-hook="review-date"]')
date_text = date_el.get_text(strip=True) if date_el else ""
# 형식: "Reviewed in the United States on January 15, 2025"
country_match = re.search(r'Reviewed in (.+?) on', date_text)
date_match = re.search(r'on (.+)$', date_text)
country = country_match.group(1) if country_match else ""
date = date_match.group(1) if date_match else ""
# 검증 구매
verified_el = div.select_one('[data-hook="avp-badge"]')
verified = bool(verified_el)
reviews.append({
"author": author,
"rating": rating,
"title": title,
"content": body,
"date": date,
"country": country,
"verified": verified,
})
return reviews
나는 이 data-hook 선택자 세트를 몇 달째 여러 ASIN에 적용해왔는데, 한 번도 바뀌지 않았다. 반면 CSS 클래스는 그 기간에만 두 번 이상 바뀌었다.
4단계: 페이지 넘김과 Amazon의 10페이지 제한 처리하기
Amazon은 pageNumber를 정렬/필터 조합당 10페이지, 즉 리뷰 약 100개로 제한한다. 10페이지가 넘으면 “Next page” 버튼도 사라진다.
기본 페이지 루프는 이렇게 생겼다:
all_reviews = []
for page in range(1, 11):
url = f"https://www.amazon.com/product-reviews/{asin}/ref=cm_cr_arp_d_viewopt_srt?sortBy=recent&pageNumber={page}"
soup = get_soup(session, url)
page_reviews = extract_reviews(soup)
if not page_reviews:
break # 이 페이지에는 더 이상 리뷰가 없음
all_reviews.extend(page_reviews)
print(f"Page {page}: {len(page_reviews)} reviews")
Amazon 리뷰 10페이지 제한을 넘는 방법
우회 방법은 필터를 나눠서 보는 것이다. filterByStar와 sortBy 조합마다 독립적인 10페이지 창이 생긴다.
별점 필터 값: one_star, two_star, three_star, four_star, five_star
정렬 값: recent, helpful (기본값)
5개의 별점 필터 × 2개의 정렬을 조합하면 최대 100페이지, 즉 상품당 1,000개 리뷰까지 접근할 수 있다. 별점 분포가 치우친 상품이라면, 실제로는 거의 전체 리뷰셋에 가깝게 모을 수도 있다.
star_filters = ["one_star", "two_star", "three_star", "four_star", "five_star"]
sort_orders = ["recent", "helpful"]
all_reviews = []
seen_titles = set() # 기본 중복 제거
for star in star_filters:
for sort in sort_orders:
for page in range(1, 11):
url = (
f"https://www.amazon.com/product-reviews/{asin}"
f"?filterByStar={star}&sortBy={sort}&pageNumber={page}"
)
soup = get_soup(session, url)
page_reviews = extract_reviews(soup)
if not page_reviews:
break
for review in page_reviews:
# 제목 + 작성자 조합으로 중복 제거
key = (review["title"], review["author"])
if key not in seen_titles:
seen_titles.add(key)
all_reviews.append(review)
print(f"[{star}/{sort}] Page {page}: {len(page_reviews)} reviews")
print(f"Total unique reviews: {len(all_reviews)}")
이 버킷들 사이에는 겹치는 리뷰가 생기므로 중복 제거가 필수다. 나는 리뷰 제목 + 작성자 이름 조합을 빠른 키로 쓴다. 완벽하진 않지만, 대부분의 중복은 걸러낸다.
5단계: 봇 방어 우회하기(로테이션, 속도 조절, 재시도)
Amazon은 AWS WAF Bot Control을 쓰고 있고, 점점 더 공격적으로 바뀌고 있다. User-Agent만 바꾸거나, 딜레이만 넣는 식의 단일 대응으로는 이제 부족하다.
| 기법 | 구현 방식 |
|---|---|
| User-Agent 로테이션 | 10개 이상의 실제 브라우저 문자열 중 랜덤 선택 |
| 지수 백오프 | 503 오류 시 2초 → 4초 → 8초로 재시도 지연 |
| 요청 속도 제한 | 페이지 사이에 random.uniform(2, 5)초 대기 |
| 프록시 로테이션 | residential 프록시를 번갈아 사용 |
| 세션 지문 고정 | 세션마다 쿠키와 헤더를 일관되게 유지 |
| TLS 위장 | 프로덕션에서는 requests 대신 curl_cffi 사용 |
프로덕션용 재시도 래퍼는 이렇게 짤 수 있다:
import time, random
USER_AGENTS = [
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/147.0.0.0 Safari/537.36",
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/147.0.0.0 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:149.0) Gecko/20100101 Firefox/149.0",
"Mozilla/5.0 (Macintosh; Intel Mac OS X 15_7_5) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/26.0 Safari/605.1.15",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/146.0.0.0 Safari/537.36",
]
def scrape_with_retries(session, url, max_retries=3):
for attempt in range(max_retries):
try:
session.headers["User-Agent"] = random.choice(USER_AGENTS)
time.sleep(random.uniform(2, 5))
response = session.get(url, timeout=15)
# 차단 감지
if "validateCaptcha" in response.url or "Robot Check" in response.text:
wait = (2 ** attempt) * 5
print(f"CAPTCHA 감지됨. {wait}초 대기...")
time.sleep(wait)
continue
if response.status_code in (429, 503):
wait = (2 ** attempt) * 2
print(f"속도 제한 감지 ({response.status_code}). {wait}초 대기...")
time.sleep(wait)
continue
if "ap_email" in response.text:
raise Exception("로그인 화면 — 쿠키가 만료됨")
return BeautifulSoup(response.text, "lxml")
except Exception as e:
if attempt == max_retries - 1:
raise
print(f"시도 {attempt + 1} 실패: {e}")
return None
프록시에 대한 메모: Amazon은 AWS, GCP, Azure, DigitalOcean 같은 데이터센터 IP 대역을 네트워크 수준에서 차단한다. 수백 페이지 이상을 스크래핑한다면 residential 프록시가 거의 필수다 — 사용량에 따라 월 $50–200+ 정도를 예상해야 한다. 하루 100회 미만 정도의 작은 프로젝트라면, 집 IP에서 조심스럽게 속도를 낮춰 돌리는 것만으로도 충분한 경우가 많다.
Amazon은 TLS 지문도 검사한다. Python의 기본 requests는 알려진 JA3 hash가 있어 방어 시스템에 선제 차단되기도 한다. 프로덕션 스크래퍼라면 실제 브라우저의 TLS 스택처럼 보이게 하는 curl_cffi 사용을 고려해볼 만하다. 몇백 페이지 수준의 가벼운 작업이라면, 좋은 헤더를 붙인 requests로도 대체로 충분하다.
6단계: 스크래핑한 Amazon 리뷰를 CSV나 Excel로 내보내기
리뷰를 모았다면, pandas로 원하는 형식으로 내보내는 건 쉽다:
import pandas as pd
df = pd.DataFrame(all_reviews)
df.to_csv("amazon_reviews.csv", index=False)
print(f"Exported {len(df)} reviews to amazon_reviews.csv")
예시 출력:
| author | rating | title | content | date | country | verified |
|---|---|---|---|---|---|---|
| Sarah M. | 5.0 | Best purchase this year | Battery lasts all day, screen is gorgeous... | January 15, 2025 | the United States | True |
| Mike T. | 2.0 | Disappointed after 2 weeks | The charging port stopped working... | February 3, 2025 | the United States | True |
| Priya K. | 4.0 | Great value for the price | Does everything I need, minor lag on heavy apps... | March 10, 2025 | the United States | False |
Excel로 내보내려면 df.to_excel("amazon_reviews.xlsx", index=False)를 쓰면 된다. 단, openpyxl이 필요하다.
Google Sheets로 보내려면 gspread를 쓸 수 있지만, Google Cloud에서 8단계가 넘는 설정이 필요하다 — 프로젝트 만들기, API 두 개 활성화, service account credentials 생성, 시트 공유까지. 이게 스크래핑보다 준비가 더 많다고 느껴진다면, 맞다. (바로 이런 순간에 Thunderbit처럼 Google Sheets로 원클릭 내보내기를 해주는 도구가 엄청 매력적으로 보인다.)
보너스: 5줄짜리 Python으로 리뷰에 감성 분석 추가하기
대부분의 스크래핑 글은 CSV 내보내기에서 끝난다. 하지만 감성 점수를 붙여야 원시 데이터가 비즈니스 의사결정으로 바뀐다.
가장 빠른 기본 버전은 TextBlob을 쓴다:
from textblob import TextBlob
df["sentiment"] = df["content"].apply(lambda x: TextBlob(str(x)).sentiment.polarity)
이렇게 하면 각 리뷰에 -1.0(매우 부정적)에서 +1.0(매우 긍정적) 사이의 polarity 점수가 붙는다. 예시는 다음과 같다:
| content (축약) | rating | sentiment |
|---|---|---|
| "Battery lasts all day, screen is gorgeous..." | 5.0 | 0.65 |
| "The charging port stopped working after..." | 2.0 | -0.40 |
| "Does everything I need, minor lag on..." | 4.0 | 0.25 |
| "Absolute garbage. Returned immediately." | 1.0 | -0.75 |
| "It's okay. Nothing special but works." | 3.0 | 0.10 |
흥미로운 건 불일치 구간이다 — 3성인데 텍스트는 매우 긍정적이거나, 5성인데 표현은 꽤 부정적인 경우. 이런 차이는 별점만 봐서는 놓치는 미묘한 고객 의견을 드러낸다.

프로덕션 수준의 정확도를 원한다면 Hugging Face Transformers가 낫다. VADER는 트윗용으로 만들어졌지 제품 리뷰용은 아니고, transformer 모델은 리뷰 분류에서 98%가 넘는 정확도를 보이기도 한다. nlptown/bert-base-multilingual-uncased-sentiment 모델은 1~5성 점수까지 직접 예측한다:
from transformers import pipeline
clf = pipeline("sentiment-analysis",
model="nlptown/bert-base-multilingual-uncased-sentiment")
df["predicted_stars"] = df["content"].apply(
lambda x: int(clf(str(x)[:512])[0]["label"][0])
)
Amazon 리뷰는 J자형 분포를 보인다 — 5성에서 큰 비중이 튀고, 1성도 어느 정도 있고, 중간은 상대적으로 적다. 즉 평균 평점은 실제 품질을 꽤 부정확하게 보여줄 수 있다. 1성 리뷰 묶음을 따로 나눠서 반복되는 문제를 보면, 보통 하나의 고칠 수 있는 결함이 드러난다.
솔직한 선택: 혼자 짠 Python vs 유료 API vs Thunderbit
나는 Amazon용 Python 스크래퍼를 여러 번 유지해봤고, 솔직히 말하면 자주 깨진다. 선택자가 바뀌고, 쿠키가 만료되고, Amazon이 새 봇 탐지 레이어를 넣고, 그러면 주말이 데이터 분석이 아니라 스크래퍼 디버깅으로 날아간다. 포럼 사용자들도 같은 불만을 말한다 — “지난달엔 됐는데” 식의 DIY 스크립트가 계속 패치를 요구한다.
세 가지 주요 접근을 비교하면 이렇다:
| 기준 | 혼자 짠 Python(BS4/Selenium) | 유료 스크래핑 API | Thunderbit(노코드) |
|---|---|---|---|
| 초기 설정 시간 | 1~3시간 | 30분(API 키) | 2분 |
| 비용 | 무료(+프록시 비용) | 월 $50–200+ | 무료 플랜 있음 |
| 로그인 화면 처리 | 쿠키 수동 관리 | 보통 처리됨 | 자동 처리 |
| 유지보수 | 높음(선택자 깨짐) | 낮음(벤더가 관리) | 거의 없음(AI가 적응) |
| 페이지 넘김 | 직접 구현 필요 | 내장됨 | 내장됨 |
| 다국가 지원 | 도메인별 세션 필요 | 보통 지원 | 브라우저 기반이라 로케일 자연 대응 |
| 감성 분석 | 직접 코드 작성 | 때로 포함 | Sheets로 내보낸 뒤 어디서든 분석 가능 |
| 가장 적합한 경우 | 학습, 완전한 통제 | 대규모 프로덕션 파이프라인 | 빠른 데이터 추출, 비기술 팀 |
Python은 완전한 제어권을 주고, 스크래핑이 내부적으로 어떻게 돌아가는지 배우는 데는 최고의 방법이다. 유료 API(ScrapingBee, Oxylabs, Bright Data)는 안정성이 비용보다 중요한 프로덕션 파이프라인에 잘 맞는다. 그리고 개발 부담 없이 리뷰 데이터가 필요한 팀 — 매주 경쟁 제품을 모니터링하는 Ecommerce 운영팀, 고객 표현을 광고 문구로 옮기는 마케팅팀 — 에는 세 번째 길이 있다.
코드 없이, 유지보수 없이 Thunderbit로 Amazon 리뷰 스크래핑하기
우리는 정확히 Python 스크래퍼를 계속 손보는 일이 너무 부담스러운 상황을 위해 Thunderbit를 만들었다. 흐름은 이렇다:
- Thunderbit Chrome 확장 프로그램을 설치한다
- 브라우저에서 Amazon 상품 리뷰 페이지로 이동한다 (이미 로그인되어 있으니 로그인 화면은 문제가 아니다)
- **“AI Suggest Fields”**를 클릭하면 Thunderbit가 페이지를 읽고 Author, Rating, Title, Review Text, Date, Verified Purchase 같은 컬럼을 제안한다
- **“Scrape”**를 누르면 내장된 페이지 넘김과 함께 데이터가 바로 추출된다
- Excel, Google Sheets, Airtable, Notion으로 내보낸다
핵심은 Thunderbit의 AI가 매번 페이지 구조를 다시 읽는다는 점이다. 관리해야 할 CSS 선택자도 없고, 쿠키도 직접 다룰 필요가 없고, 봇 방지 코드도 따로 쓸 필요가 없다. Amazon이 HTML을 바꿔도 AI가 적응한다. 프로그래밍 방식이 필요하지만 전부 직접 구현하고 싶지는 않은 사람을 위해, Thunderbit는 Extract API도 제공한다 — AI 기반 필드 인식이 들어간 구조화 데이터 추출 API라서, 선택자 유지보수 없이 쓸 수 있다.
Amazon 데이터에 대해 더 깊이 보고 싶다면, Amazon 제품과 리뷰를 스크래핑하는 방법과 Amazon 판매 데이터를 추출하고 분석하는 방법도 참고해보자.
Python으로 대규모 Amazon 리뷰 스크래핑할 때 유용한 팁
여러 ASIN을 대상으로 리뷰를 긁는다면, 아래 습관들이 큰 고생을 줄여준다:
- ASIN 단위로 배치 처리하고, 페이지 사이뿐 아니라 상품 사이에도 딜레이를 넣어라. 나는 ASIN 사이에 10~15초 정도 쉰다.
- 중복 제거는 강하게 하라. 여러 별점 필터와 정렬을 섞으면 같은 리뷰가 반복된다.
(title, author, date)튜플을 키로 쓰면 좋다. - 실패 로그를 남겨라. 어떤 ASIN + 페이지 + 필터 조합이 실패했는지 기록해두면, 전체를 다시 긁지 않고 그 부분만 재시도할 수 있다.
- 큰 프로젝트는 DB에 저장하라. 단순 SQLite 하나만 써도 계속 부풀어 오르는 CSV보다 훨씬 낫다:
import sqlite3
conn = sqlite3.connect("reviews.db")
df.to_sql("reviews", conn, if_exists="append", index=False)
- 반복 스크래핑은 예약 실행하라. 정기 모니터링용이면 cron job을 쓰거나 Thunderbit의 Scheduled Scraper를 쓰면 된다 — URL과 주기만 설정하면 나머지는 서버 없이 처리된다.
더 많은 방법은 최고의 자동 웹 스크래핑 도구와 웹사이트 데이터를 Excel로 스크래핑하는 방법 글도 참고하면 된다.
짧은 법적·윤리적 주의사항
Amazon의 이용약관은 로봇, spider, scraper, 또는 기타 자동화 수단으로 Amazon 서비스에 접근하는 것을 명시적으로 금지한다. 다만 최근 미국 판례는 공개 데이터 스크래핑에 우호적인 흐름을 보였다. Meta Platforms v. Bright Data(2024년 1월)에서 연방법원은 로그인하지 않은 상태로 공개 접근 가능한 데이터의 스크래핑은, 스크래퍼가 “사용자”가 아닐 경우 서비스 약관 위반이 아니라고 봤다.
중요한 뉘앙스가 있다: 로그인 뒤에서 하는 스크래핑(이 가이드가 다루는 방식)은 Amazon 계정 생성 시 ToS에 동의했기 때문에 계약법 영역에 더 깊이 들어간다. 반면 공개로 보이는 상단 리뷰만 긁는 것은 로그인 뒤의 전체 리뷰 페이지보다 법적 위험이 낮다.
실무적으로는 이렇게 생각하면 된다: 스크래핑한 데이터를 상업적으로 재배포하지 말 것, 공개된 범위를 넘어서는 개인정보를 긁지 말 것, robots.txt를 존중할 것, 대규모나 상업적 사용 전에는 법률 자문을 받을 것. 이건 법률 자문이 아니다. 더 자세한 법적 이슈는 웹 스크래핑의 법적 영향 정리를 참고하면 된다.
정리: Python으로 Amazon 리뷰를 스크래핑할까, 아니면 그냥 코드를 버릴까
오늘 다룬 내용을 빠르게 정리하면:
- 로그인 화면은 실제로 존재하지만, 브라우저에서 7개 쿠키를 복사해
requests.Session()에 넣으면 넘길 수 있다 - 몇 주마다 깨지는 CSS 클래스 대신
data-hook선택자를 써라 - 별점 필터와 정렬을 섞어서 10페이지 제한을 우회하면 상품당 500개 이상의 리뷰에 도달할 수 있다
- TextBlob으로 빠르게 감성 분석을 붙이거나, production 수준이면 Hugging Face Transformers를 써라
- 봇 방어에 대비해 속도 제한, User-Agent 로테이션, 지수 백오프, 대규모 작업 시 residential 프록시를 준비하라
Python은 완전한 제어권을 주고, 내부 동작을 이해하는 데 가장 좋은 방법이다. 하지만 네가 필요한 것이 “금요일까지 경쟁사 리뷰를 시트에 넣어야 해”이지 “production 데이터 파이프라인을 직접 만들고 싶어”가 아니라면, 맞춤형 스크래퍼 유지보수는 그냥 너무 비쌀 수 있다.
Thunderbit는 인증, 선택자, 페이지 넘김, 내보내기를 클릭 몇 번으로 처리한다 — 무료 플랜을 써보고 네 워크플로와 맞는지 확인해봐. Amazon이 봇 방어를 계속 강화하는 만큼, 실시간으로 적응하는 AI 기반 도구는 점점 더 있으면 좋은 옵션이 아니라 꼭 필요한 도구가 될 가능성이 크다.
Thunderbit YouTube 채널에서 스크래핑 과정을 영상으로도 볼 수 있다.
자주 묻는 질문
1. 로그인 없이 Amazon 리뷰를 스크래핑할 수 있나?
가능은 하지만, 상품 페이지(/dp/{ASIN}/)에 보이는 약 8개의 “상단 리뷰”만 가능하다. 정렬, 필터, 페이지 넘김이 있는 전체 리뷰 페이지는 2024년 말부터 인증이 필요하다. 대부분의 비즈니스 사용 사례에서는 로그인 화면을 처리해야 한다.
2. Amazon 리뷰를 스크래핑하는 건 합법인가?
Amazon 이용약관은 자동 스크래핑을 금지한다. 하지만 최근 미국 판례(Meta v. Bright Data, 2024; hiQ v. LinkedIn)는 공개 접근 데이터의 스크래핑에 우호적이다. 다만 로그인 뒤 스크래핑은 Amazon 약관에 동의한 상태이므로 법적 위험이 더 크다. 상업적 사용 전에는 법률 자문을 받아라.
3. 상품 하나당 Amazon 리뷰를 최대 몇 개까지 스크래핑할 수 있나?
Amazon은 리뷰 페이지를 별점 필터와 정렬 조합당 10페이지로 제한한다. 5개 별점 필터 × 2개 정렬을 모두 쓰면 상품당 최대 100페이지, 즉 약 1,000개 리뷰까지 갈 수 있다. 키워드 필터를 추가하면 이론상 더 늘어나지만, 중복도 많아진다.
4. Amazon 리뷰 스크래핑에 가장 좋은 Python 라이브러리는?
requests + BeautifulSoup 조합이 정적 HTML 파싱에는 가장 흔하고 믿을 만하다. JavaScript 렌더링이 필요하면 Selenium이 유용하다. 로그인 화면과 페이지 넘김을 자동으로 처리하는 노코드 대안으로는 Thunderbit를 써볼 수 있다.
5. Amazon에서 차단되지 않으려면 어떻게 해야 하나?
실제 브라우저 문자열 10개 이상에서 User-Agent를 돌리고, 요청 사이에 2~5초 랜덤 딜레이를 넣고, 503/429 에러에 지수 백오프를 적용하고, 대규모 작업에는 residential 프록시를 쓰고(데이터센터 IP는 선차단될 수 있다), 요청마다 쿠키 세션을 일관되게 유지하라. 유지보수 없는 방식이 필요하면 Thunderbit가 브라우저 세션을 통해 봇 방어를 자동으로 처리한다.
더 알아보기


