법적 고지: 이 가이드는 Glassdoor의 공개적으로 접근 가능한 데이터 수집만을 다룹니다. Glassdoor의 이용약관(ToS)을 반드시 확인하고 준수해야 하며, 미국에서는 CFAA(컴퓨터 사기 및 남용법) 위반 위험이, 유럽에서는 GDPR 위반 위험이 있을 수 있습니다. 로그인이 필요한 데이터를 스크래핑하지 마세요. 이 가이드는 교육 및 합법적인 공개 데이터 접근 목적으로만 제공됩니다.
HR 분석팀과 노동시장 데이터 엔지니어에게 Glassdoor는 기업 문화, 직원 만족도, 급여 트렌드를 파악할 수 있는 가장 풍부한 공개 데이터 소스 중 하나입니다. 하지만 Glassdoor는 DataDome과 Cloudflare Bot Management를 결합한 강력한 안티봇 스택을 운영하고 있어, 단순한 HTTP 클라이언트로는 수집이 거의 불가능합니다. 이 가이드에서는 Glassdoor 기업 리뷰 및 급여 데이터 스크래핑을 위한 실전 구현 방법을 단계별로 설명합니다.
Glassdoor 기업 리뷰 및 급여 데이터 스크래핑: 접근 가능 영역과 제한 영역
Glassdoor의 모든 데이터가 동일한 접근 수준을 가지는 것은 아닙니다. 수집 전략을 세우기 전에 공개 데이터와 인증 뒤 데이터를 명확히 구분해야 합니다.
로그인 없이 접근 가능한 공개 데이터
- 기업 개요 페이지 — 회사명, 산업, 규모, 본사 위치, 웹사이트 URL
- 잘린 리뷰 —
/Reviews/<company>-Reviews-E<id>.htm경로에서 리뷱 텍스트 앞부분(약 200~300자), 전체 평점, 직무명, 날짜 - 평점 분포 — 5점 만점 기준 별점 분포 요약
- 면접 리뷰 요약 — 공개 면접 경험의 잘린 버전
인증 벽 뒤의 제한 데이터 (로그인 필요)
- 전체 급여 분석 — 직무별 급여 분포, 보너스, 주식 옵션 세부 내역
- 전체 리뷰 텍스트 — 잘리지 않은 장문 리뷰
- 개인 급여 제출 데이터 — 개별 사용자가 제출한 급여 정보
- 상세 혜택 정보 — 의료, 휴가, 401(k) 등 세부 항목
이 가이드에서는 공개 리뷰 데이터만 수집하는 방법에 집중합니다. 로그인이 필요한 급여 데이터를 스크래핑하는 것은 ToS 위반이며 법적 위험이 큽니다.
핵심 원칙: 공개 페이지에서 수집 가능한 잘린 리뷰와 평점 데이터만 사용하고, 집계된 비개인 정보로만 분석에 활용하세요.
Glassdoor 안티봇 스택: DataDome + Cloudflare Bot Management
Glassdoor는 두 개의 엔터프라이즈급 봇 차단 시스템을 동시에 운영합니다. 이를 이해하지 못하면 모든 수집 시도가 첫 요청에서 차단됩니다.
DataDome: IP 평가 및 행동 분석
DataDome은 실시간 IP 평가, 디바이스 핑거프린팅, 행동 분석을 결합한 봇 관리 솔루션입니다. Glassdoor에 요청을 보내면 DataDome은 다음을 평가합니다:
- IP 평판 — 데이터센터 IP 대역, 알려진 프록시/VPN IP, 과거 악성 행동 이력
- 디바이스 일관성 — User-Agent, Accept 헤더, TLS 지문 간의 일치 여부
- 요청 패턴 — 속도, 간격, 페이지 간 이동 경로의 자연스러움
- 쿠키 유효성 — 이전 요청에서 발급된
datadome쿠키의 유효성
데이터센터 IP로 Glassdoor에 접근하면 DataDome은 평균 200ms 이내에 403 또는 챌린지 페이지를 반환합니다. 주거용 IP를 사용하더라도 TLS 지문이 브라우저와 다르면 동일하게 차단됩니다.
Cloudflare Bot Management: TLS 핑거프린팅과 JS 챌린지
Glassdoor는 또한 Cloudflare Bot Management를 통해 TLS 핑거프린팅과 JavaScript 챌린지를 수행합니다. Python의 requests 라이브러리가 생성하는 TLS Client Hello 메시지는 Chrome의 것과 확연히 다르기 때문에, Cloudflare는 첫 번째 패킷만 보고도 봇을 식별할 수 있습니다.
이것이 curl_cffi가 필요한 이유입니다. curl_cffi는 libcurl의 TLS 지문을 Chrome, Safari, Edge 등 실제 브라우저와 동일하게 모방하는 Python 라이브러리입니다.
| 접근 방식 | TLS 지문 | DataDome 통과율 | 적합 프록시 유형 |
|---|---|---|---|
| Python requests | Python 기본 (차단) | < 5% | 없음 |
| requests + 데이터센터 프록시 | Python 기본 | < 2% | 부적합 |
| curl_cffi + 데이터센터 프록시 | Chrome 모방 | 10~30% | 부적합 |
| curl_cffi + 주거용 프록시 | Chrome 모방 | 70~90% | 최적 |
| curl_cffi + 모바일 프록시 | Chrome 모방 | 85~95% | 적합 (고비용) |
BFF GraphQL 엔드포인트: 구조화된 리뷰 데이터 수집
Glassdoor의 공개 리뷰 페이지를 HTML로 스크래핑하는 것도 가능하지만, 파싱이 번거롭고 구조가 자주 변경됩니다. 더 나은 방법은 Glassdoor가 내부적으로 사용하는 비공개 GraphQL 엔드포인트를 활용하는 것입니다.
엔드포인트 구조
Glassdoor의 프론트엔드는 두 개의 JSON 엔드포인트를 통해 데이터를 로드합니다:
https://www.glassdoor.com/graph— 메인 GraphQL 엔드포인트https://www.glassdoor.com/bff/— BFF(Backend for Frontend) GraphQL 엔드포인트, 리뷰 데이터에 더 적합
이 엔드포인트에 POST 요청을 보내면 JSON 형태의 구조화된 리뷰 데이터를 받을 수 있습니다. 필수 헤더는 다음과 같습니다:
Content-Type: application/jsongd-csrf-token— Glassdoor 페이지에서 추출한 CSRF 토큰User-Agent— Chrome과 일치하는 UA 문자열Cookie— 유효한gdId및datadome쿠키
gd-csrf-token 획득 방법
CSRF 토큰은 공개 리뷰 페이지의 HTML 내 <script> 태그 또는 메타 태그에 포함되어 있습니다. 먼저 공개 페이지를 로드한 후, 정규식으로 토큰을 추출합니다:
import re
def extract_csrf_token(html: str) -> str:
pattern = r'gd-csrf-token["\']?\s*[:=]\s*["\']([a-f0-9-]+)["\']'
match = re.search(pattern, html)
if not match:
raise ValueError('CSRF token not found')
return match.group(1)
ProxyHat 주거용 프록시 연동: 실전 Python 예제
이제 모든 구성 요소를 결합하여 Glassdoor BFF GraphQL 엔드포인트에서 리뷰 데이터를 수집하는 완전한 Python 예제를 작성해보겠습니다.
1단계: 페이지 로드 및 CSRF 토큰 추출
from curl_cffi import requests as cffi_requests
import re
import json
# ProxyHat 주거용 프록시 - 스티키 세션으로 DataDome 쿠키 유지
PROXY_URL = 'http://user-country-US-session-gd001:YOUR_PASSWORD@gate.proxyhat.com:8080'
HEADERS = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) '
'AppleWebKit/537.36 (KHTML, like Gecko) '
'Chrome/120.0.0.0 Safari/537.36',
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'Accept-Language': 'en-US,en;q=0.9',
}
def load_review_page(employer_id: int, session_id: str):
proxy = f'http://user-country-US-session-{session_id}:YOUR_PASSWORD@gate.proxyhat.com:8080'
url = f'https://www.glassdoor.com/Reviews/Company-E{employer_id}.htm'
response = cffi_requests.get(
url,
headers=HEADERS,
proxies={'http': proxy, 'https': proxy},
impersonate='chrome120',
timeout=30,
)
if response.status_code == 403:
raise Exception('DataDome block — rotate session/proxy')
# CSRF 토큰 추출
token_match = re.search(r'gd-csrf-token["\']?\s*[:=]\s*["\']([a-f0-9-]+)', response.text)
csrf_token = token_match.group(1) if token_match else None
return {
'html': response.text,
'csrf_token': csrf_token,
'cookies': dict(response.cookies),
'proxy': proxy,
}
2단계: BFF GraphQL에 POST 요청하여 리뷰 데이터 수집
def fetch_reviews_bff(employer_id: int, page_data: dict, cursor: str = None):
graphql_url = 'https://www.glassdoor.com/bff/'
query = '''
query EmployerReviews($employerId: Long!, $cursor: String) {
employer(employerId: $employerId) {
reviews(cursor: $cursor) {
nodes {
id
ratingOverall
pros
cons
jobTitle
date
}
pageInfo {
nextCursor
hasNextPage
}
}
}
}'''
variables = {
'employerId': employer_id,
'cursor': cursor,
}
bff_headers = {
**HEADERS,
'Content-Type': 'application/json',
'gd-csrf-token': page_data['csrf_token'],
'Origin': 'https://www.glassdoor.com',
'Referer': f'https://www.glassdoor.com/Reviews/Company-E{employer_id}.htm',
}
response = cffi_requests.post(
graphql_url,
headers=bff_headers,
json={'query': query, 'variables': variables},
proxies={'http': page_data['proxy'], 'https': page_data['proxy']},
cookies=page_data['cookies'],
impersonate='chrome120',
timeout=30,
)
if response.status_code == 403:
raise Exception('DataDome block on BFF endpoint')
return response.json()
# 사용 예시
page = load_review_page(6056, 'gd001') # 6056 = Google employer ID
result = fetch_reviews_bff(6056, page)
for review in result['data']['employer']['reviews']['nodes']:
print(f"평점: {review['ratingOverall']}/5")
print(f"직무: {review['jobTitle']}")
print(f"장점: {review['pros'][:100]}...")
print(f"단점: {review['cons'][:100]}...")
print('---')
3단계: Node.js 예제 (Axios + proxy-agent)
const axios = require('axios');
const { HttpsProxyAgent } = require('https-proxy-agent');
const proxyAgent = new HttpsProxyAgent(
'http://user-country-US-session-gd002:YOUR_PASSWORD@gate.proxyhat.com:8080'
);
async function fetchGlassdoorReviews(employerId) {
const pageUrl = `https://www.glassdoor.com/Reviews/Company-E${employerId}.htm`;
const pageRes = await axios.get(pageUrl, {
httpsAgent: proxyAgent,
headers: {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) '
+ 'AppleWebKit/537.36 (KHTML, like Gecko) '
+ 'Chrome/120.0.0.0 Safari/537.36',
'Accept-Language': 'en-US,en;q=0.9',
},
timeout: 30000,
});
const csrfMatch = pageRes.data.match(/gd-csrf-token["']?\s*[:=]\s*["']([a-f0-9-]+)/);
const csrfToken = csrfMatch ? csrfMatch[1] : null;
const cookies = pageRes.headers['set-cookie']?.join('; ') || '';
const bffRes = await axios.post('https://www.glassdoor.com/bff/', {
query: `query EmployerReviews($eid: Long!, $cursor: String) {
employer(employerId: $eid) { reviews(cursor: $cursor) {
nodes { ratingOverall pros cons jobTitle date }
pageInfo { nextCursor hasNextPage }
} } }`,
variables: { eid: employerId, cursor: null },
}, {
httpsAgent: proxyAgent,
headers: {
'Content-Type': 'application/json',
'gd-csrf-token': csrfToken,
'Cookie': cookies,
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) '
+ 'AppleWebKit/537.36 (KHTML, like Gecko) '
+ 'Chrome/120.0.0.0 Safari/537.36',
},
timeout: 30000,
});
return bffRes.data;
}
fetchGlassdoorReviews(6056).then(console.log).catch(console.error);
페이지네이션, 스티키 세션, 페이싱 전략
대기업은 수천 건의 리뷰를 가지고 있으므로 페이지네이션 처리가 필수입니다. DataDome 쿠키를 유지하면서 안정적으로 수집하려면 다음 전략을 결합해야 합니다.
커서 기반 페이지네이션
Glassdoor BFF GraphQL은 커서 기반 페이지네이션을 사용합니다. 각 응답의 pageInfo.nextCursor 값을 다음 요청의 cursor 변수로 전달합니다:
import time
import random
def scrape_all_reviews(employer_id: int, max_pages: int = 50):
session_id = f'gd{employer_id}'
page_data = load_review_page(employer_id, session_id)
all_reviews = []
cursor = None
for page_num in range(max_pages):
try:
result = fetch_reviews_bff(employer_id, page_data, cursor)
reviews = result['data']['employer']['reviews']
all_reviews.extend(reviews['nodes'])
if not reviews['pageInfo']['hasNextPage']:
break
cursor = reviews['pageInfo']['nextCursor']
# 페이싱: 3~7초 랜덤 대기
time.sleep(random.uniform(3, 7))
except Exception as e:
print(f'Page {page_num} error: {e}')
# 세션 교체 후 재시도
session_id = f'gd{employer_id}_retry{page_num}'
page_data = load_review_page(employer_id, session_id)
time.sleep(10)
continue
return all_reviews
스티키 세션으로 DataDome 쿠키 유지
ProxyHat의 -session- 플래그는 동일한 세션 ID에 대해 동일한 출구 IP를 유지합니다. 이것이 중요한 이유는 DataDome이 IP + 쿠키 조합으로 세션을 추적하기 때문입니다. 페이지 로드 시 얻은 datadome 쿠키는 해당 IP에 바인딩되어 있으므로, IP가 바뀌면 쿠키가 무효화됩니다.
ProxyHat 스티키 세션 사용법:
# 세션 ID로 동일 IP 유지
http://user-country-US-session-gd-google-001:PASSWORD@gate.proxyhat.com:8080
# 도시 타겟팅 + 세션
http://user-country-US-city-san-francisco-session-gd-001:PASSWORD@gate.proxyhat.com:8080
요청 속도 제한 (Rate Limiting)
안정적인 수집을 위해 다음 페이싱 규칙을 권장합니다:
- 페이지 로드: 세션당 시간당 최대 50회
- BFF GraphQL 요청: 세션당 시간당 최대 100회
- 전체 수집량: 프록시 풀당 시간당 500~1,000건
- 요청 간격: 3~7초 랜덤 대기 (고정 간격 피하기)
- 동시 세션: 최대 20~50개 동시 세션으로 분산
429 및 챌린지 응답 처리
def retry_with_backoff(func, max_retries=3):
for attempt in range(max_retries):
try:
return func()
except Exception as e:
if '403' in str(e) or '429' in str(e):
wait = (2 ** attempt) * 5 # 5s, 10s, 20s
print(f'Blocked, waiting {wait}s before retry {attempt + 1}')
time.sleep(wait)
# 새 세션으로 프록시 교체
continue
raise
raise Exception(f'Failed after {max_retries} retries')
curl을 활용한 빠른 테스트
Python 스크립트를 작성하기 전에 curl로 연결을 테스트하는 것이 유용합니다:
curl -x http://user-country-US-session-test01:PASSWORD@gate.proxyhat.com:8080 \
-H 'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36' \
-H 'Accept-Language: en-US,en;q=0.9' \
'https://www.glassdoor.com/Reviews/Company-E6056.htm' \
-o glassdoor_page.html -w '%{http_code}'
HTTP 200이 반환되면 프록시와 헤더 조합이 DataDome을 통과한 것입니다. 403이 반환되면 세션 ID를 변경하거나 다른 국가의 주거용 IP로 시도하세요.
프록시 유형 비교: Glassdoor 수집에 가장 적합한 선택
| 프록시 유형 | DataDome 통과율 | 세션 안정성 | 비용 (GB당) | 적합도 |
|---|---|---|---|---|
| 데이터센터 | 매우 낮음 (< 5%) | 불안정 | $0.5~1 | 부적합 |
| 주거용 (회전) | 높음 (70~90%) | 중간 | $3~8 | 적합 |
| 주거용 (스티키) | 높음 (75~90%) | 높음 | $3~8 | 최적 |
| 모바일 (4G/5G) | 매우 높음 (85~95%) | 높음 | $15~30 | 고예산 시 적합 |
ProxyHat 주거용 프록시는 프록시 요금제에서 확인할 수 있으며, 스티키 세션을 기본 지원합니다. 프록시 위치 페이지에서 90개 이상 국가의 IP 가용성을 확인할 수 있습니다.
윤리적 스크래핑과 공식 API 사용 시기
기술적으로 가능하다고 해서 항상 해야 하는 것은 아닙니다. Glassdoor 데이터 수집 시 다음 윤리 및 법적 가이드라인을 따르세요.
수집 원칙
- 비개인 집계 데이터만 수집 — 리뷰 작성자의 실명, 이메일, 개인 식별 정보는 수집하지 마세요. Glassdoor 리뷰는 기본적으로 익명이지만, 직무명 + 위치 + 날짜 조합으로 개인을 식별할 수 있는 경우가 있습니다.
- 로그인 뒤 데이터 미수집 — 전체 급여 데이터, 상세 혜택 정보 등 인증이 필요한 데이터는 수집하지 마세요. 이는 Glassdoor ToS 위반이며 CFAA 적용 대상이 될 수 있습니다.
- robots.txt 준수 — Glassdoor의
robots.txt를 확인하고 수집이 허용된 경로인지 검증하세요. - GDPR 고려사항 — 유럽 직원의 리뷰 데이터를 수집할 경우, 리뷰 텍스트에 개인 데이터(예: 관리자 이름)가 포함되어 있을 수 있으므로 GDPR Article 15(데이터 접근권) 및 Article 17(삭제권) 관련 의무가 발생할 수 있습니다.
- 수집량 최소화 — 분석에 필요한 최소한의 데이터만 수집하고, 수집 후에는 집계 통계로만 보관하세요.
공식 데이터 라이선스가 적합한 경우
다음 상황에서는 스크래핑 대신 Glassdoor의 공식 데이터 파트너십이나 API 라이선스를 검토해야 합니다:
- 상업적 데이터 제품 — 수집한 데이터를 유료 서비스나 제품에 통합할 경우
- 대규모 급여 데이터 — 전체 급여 분석이 필요한 경우 (공개 수집 불가)
- 법적 보장 필요 — 감사나 규제 목적으로 데이터 출처가 법적으로 보장되어야 하는 경우
- 실시간 모니터링 — 99.9% 이상의 안정성이 필요한 지속적 모니터링의 경우
자세한 웹 스크래핑 모범 사례는 웹 스크래핑 사용 사례 페이지를 참조하세요. SERP 추적 관련 작업이 있다면 SERP 추적 사용 사례도 유용합니다.
ProxyHat 설정 가이드
ProxyHat 주거용 프록시를 사용하려면 ProxyHat 문서를 참조하여 계정을 설정하세요. 기본 연결 정보는 다음과 같습니다:
- 게이트웨이:
gate.proxyhat.com - HTTP 포트:
8080 - SOCKS5 포트:
1080 - 사용자명 형식:
user-country-US-session-YOUR_ID:PASSWORD
SOCKS5가 필요한 경우 포트를 1080으로 변경하세요:
socks5://user-country-US-session-gd001:PASSWORD@gate.proxyhat.com:1080
핵심 요약 (Key Takeaways)
- 공개 데이터만 수집 — Glassdoor의 /Reviews/ 페이지와 BFF GraphQL 엔드포인트에서 로그인 없이 접근 가능한 잘린 리뷰와 평점만 수집하세요. 전체 급여 데이터는 인증 벽 뒤에 있습니다.
- curl_cffi + 주거용 프록시 필수 — DataDome과 Cloudflare의 TLS 핑거프린팅을 우회하려면 Chrome TLS 지문 모방(curl_cffi)과 주거용 IP(ProxyHat) 조합이 필요합니다. 데이터센터 IP는 통과율이 5% 미만입니다.
- 스티키 세션으로 쿠키 유지 — ProxyHat의
-session-플래그로 동일 출구 IP를 유지하여 DataDome 쿠키가 무효화되지 않도록 하세요. - 페이싱과 재시도 로직 — 시간당 500~1,000건 이하로 제한하고, 429/403 응답 시 지수 백오프로 재시도하세요. 요청 간 3~7초 랜덤 대기를 권장합니다.
- 윤리와 법률 준수 — 비개인 집계 데이터만 수집하고, 로그인 뒤 데이터는 수집하지 마세요. CFAA(미국)와 GDPR(유럽)을 반드시 고려하세요. 상업적 사용 시 공식 데이터 라이선스를 검토하세요.
FAQ
Glassdoor 리뷰 스크래핑이란 무엇인가요?
Glassdoor 리뷰 스크래핑은 Glassdoor 웹사이트의 공개 기업 리뷰 페이지에서 리뷰 텍스트, 평점, 직무명 등의 데이터를 프로그래밍 방식으로 추출하는 작업입니다. 로그인 없이 접근 가능한 /Reviews/ 페이지의 잘린 리뷰와 BFF GraphQL 엔드포인트를 통해 구조화된 JSON 데이터를 수집할 수 있습니다.
Glassdoor 스크래핑에 어떤 프록시 유형이 가장 적합하나요?
DataDome의 IP 평가 시스템을 우회하려면 주거용 프록시가 가장 적합합니다. 데이터센터 IP는 DataDome이 즉시 차단할 가능성이 높고, 모바일 프록시는 비용이 높습니다. 주거용 프록시는 실제 ISP IP를 사용하므로 IP 평가 점수가 높고, 세션 스티키 기능으로 DataDome 쿠키를 유지하면서 안정적으로 데이터를 수집할 수 있습니다.
Glassdoor 스크래핑 시 차단을 피하려면 어떻게 해야 하나요?
차단을 피하려면 세 가지 전략을 결합해야 합니다. 첫째, curl_cffi로 Chrome TLS 지문을 모방하여 Cloudflare의 TLS 핑거프린팅을 통과합니다. 둘째, 주거용 프록시를 회전시키면서 각 세션에 스티키 세션 ID를 부여하여 DataDome 쿠키를 유지합니다. 셋째, 요청 속도를 시간당 500~1,000건 이하로 제한하고 429 응답 시 지수 백오프 재시도 로직을 구현합니다.
Glassdoor 급여 데이터는 로그인 없이 수집할 수 있나요?
Glassdoor의 전체 급여 분석 데이터는 인증 벽 뒤에 있어 로그인 없이는 접근할 수 없습니다. 공개 페이지에서는 잘린 리뷰와 기업 개요만 볼 수 있습니다. 로그인이 필요한 데이터를 스크래핑하는 것은 Glassdoor 이용약관 위반이며 CFAA(미국) 및 GDPR(유럽) 관련 법적 위험이 있으므로, 공개 데이터만 수집하고 공식 데이터 라이선스를 검토하는 것이 권장됩니다.






