Glassdoor 회사 리뷰 및 연봉 데이터 스크래핑 가이드: BFF GraphQL, DataDome, 프록시 전략 (2026)

Glassdoor의 공개 리뷰와 연봉 데이터를 수집하는 실전 가이드입니다. DataDome 우회, BFF GraphQL 엔드포인트 활용, curl_cffi TLS 지문 모방, ProxyHat 회전 프록시 설정까지 단계별로 설명합니다.

How to Scrape Glassdoor Company Reviews and Salaries in 2026 (BFF GraphQL, DataDome, and Proxies)

Glassdoor 회사 리뷰 및 연봉 데이터 스크래핑은 HR 분석 및 노동시장 데이터 엔지니어에게 핵심 과제입니다. 기업 평점, 장단점 리뷰, 직무별 연봉 정보는 경쟁 분석, 채용 브랜딩, 보상 벤치마킹에 필수적이지만, Glassdoor는 DataDome과 Cloudflare Bot Management로 무장된 강력한 안티봇 스택을 운영합니다. 이 가이드에서는 공개 데이터에 한정해 합법적으로 접근하는 방법을 코드 예제와 함께 다룹니다.

⚠️ 법적 고지: 이 글은 Glassdoor의 공개 페이지에서 접근 가능한 집계 데이터만을 다룹니다. Glassdoor 이용약관(ToS)을 반드시 확인하세요. 미국에서는 CFAA(Computer Fraud and Abuse Act)가 무단 데이터 접근에 적용될 수 있으며, EU에서는 GDPR이 직원 관련 개인정보 보호를 규제합니다. 로그인이 필요한 페이지를 스크래핑하지 마세요. 공식 데이터 라이선스가 필요한 경우 Glassdoor에 직접 문의하세요.

Glassdoor 회사 리뷰 및 연봉 데이터 스크래핑: 공개 vs 로그인 게이트

Glassdoor의 데이터는 크게 두 영역으로 나뉩니다. 첫 번째는 로그인 없이 접근 가능한 공개 영역이고, 두 번째는 인증 뒤에 있는 게이트 영역입니다. 스크래핑 전략은 이 구분에서 출발합니다.

공개 접근 가능 데이터

  • 회사 개요 페이지: /Overview/Working-at-<company>-EI_IE<id>.htm — 산업, 규모, 본사 위치, 전체 평점.
  • 리뷰 목록 페이지: /Reviews/<company>-Reviews-E<id>.htm — 최근 리뷰의 장점/단점 요약, 직무명, 평점. 일부 리뷰는 텍스트가 잘려 있습니다.
  • 페이지당 약 10개의 리뷰가 표시되며, 페이지네이션으로 과거 리뷰에 순차 접근 가능.

로그인 뒤에 있는 데이터 (비추천)

  • 전체 연봉 분석: 직무/지역별 연봉 분포, 보너스, 주식 보상 상세.
  • 전체 리뷰 텍스트: 잘리지 않은 장단점 전문, 경영진 평가, 인터뷰 질문.
  • 개인 사용자 프로필: 리뷰 작성자의 직무 기간 등 (GDPR상 민감).

이 가이드는 공개 리뷰 페이지와 BFF GraphQL 엔드포인트에서 구조화된 리뷰 노드를 추출하는 것에 집중합니다. 연봉 상세 데이터는 로그인 뒤에 있으므로 제외합니다.

Glassdoor 안티봇 스택: DataDome + Cloudflare Bot Management

Glassdoor는 두 개의 엔터프라이즈급 안티봇 솔루션을 계층적으로 배포합니다. 이해 없이는 어떤 프록시도 소용이 없습니다.

DataDome

DataDome은 IP 평판, 디바이스 지문, 행동 패턴을 결합해 봇을 탐지합니다. 핵심 특징:

  • IP 스코어링: 데이터센터 IP 대역을 즉시 차단. 동일 IP에서 짧은 시간 내 다수 요청 시 플래그.
  • 쿠키 기반 세션 추적: datadome 쿠키를 발급하고, 이후 요청마다 검증. 쿠키가 없거나 변조되면 JS 챌린지 트리거.
  • JS 챌린지: 브라우저 환경에서만 풀 수 있는 난독화된 JavaScript를 실행시켜 헤드리스 브라우저와 curl을 걸러냅니다.

Cloudflare Bot Management + TLS 지문

Glassdoor는 Cloudflare Bot Management도 사용합니다. Cloudflare는 TLS 핸드셰이크 단계에서 ClientHello 패킷을 분석해 JA3/JA4 지문을 생성합니다. 표준 Python requests 라이브러리는 OpenSSL 기반 TLS 스택을 사용하므로, Chrome의 BoringSSL 지문과 확연히 다릅니다. 결과적으로 requests.get() 한 번에 차단됩니다.

해결책: curl_cffi (Chrome TLS 모방)

curl_cffi는 libcurl의 TLS 지문 모방 기능을 Python에 바인딩합니다. impersonate="chrome" 옵션으로 Chrome 120의 TLS 핸드셰이크, HTTP/2 프레임 순서, 헤더 순서까지 재현합니다.

from curl_cffi import requests as cffi_requests

response = cffi_requests.get(
    "https://www.glassdoor.com/Reviews/Google-Reviews-E9079.htm",
    impersonate="chrome",
    proxies={"https": "http://user-country-US:pass@gate.proxyhat.com:8080"}
)
print(response.status_code)  # 200 또는 403

이것만으로 충분하지 않습니다. DataDome은 IP 평판도 동시에 검사하므로, residential 회전 프록시가 필수입니다.

BFF GraphQL 엔드포인트와 gd-csrf-token

Glassdoor 웹 페이지를 파싱하는 대신, 프론트엔드가 사용하는 미공개 GraphQL 엔드포인트를 직접 호출하면 구조화된 JSON을 받을 수 있습니다. 이 엔드포인트는 공개 페이지 로딩 시 브라우저가 자동으로 호출하는 것이므로, 공개 데이터 범주에 해당합니다.

엔드포인트 구조

  • BFF GraphQL: https://www.glassdoor.com/bff/graphql — POST 요청, JSON body에 query와 variables 전달.
  • 필수 헤더: gd-csrf-token (페이지 로드 시 HTML 또는 meta 태그에서 추출), Content-Type: application/json.
  • 쿠키: DataDome 쿠키가 유효해야 함. 최초 페이지 방문으로 쿠키를 획득한 후 GraphQL 호출에 재사용.

왜 회전 residential 프록시가 DataDome IP 스코어링을 이기는가

DataDome은 데이터센터 IP를 즉시 차단하지만, 실제 ISP가 부여한 residential IP는 신뢰 점수가 높습니다. ProxyHat의 residential 풀은 수백만 개의 실제 가입자 IP를 제공하며, 요청마다 다른 IP로 회전하면 단일 IP 기반 rate-limit를 우회할 수 있습니다. 단, DataDome 쿠키는 IP와 연결되므로 sticky session으로 동일 IP를 유지하면서 쿠키를 보존해야 합니다.

프록시 유형 DataDome 통과율 적합성 평균 지연
Datacenter 낮음 (~5%) 부적합 — 즉시 차단 50ms
Residential (회전) 높음 (~85%) 적합 — IP 스코어링 우회 200ms
Mobile (4G/5G) 매우 높음 (~95%) 최적이나 비용 높음 400ms

실전 Python 예제: BFF GraphQL로 리뷰 노드 추출

다음은 ProxyHat residential 프록시를 통해 Glassdoor BFF GraphQL 엔드포인트에 POST 요청을 보내고, 리뷰 노드에서 ratingOverall, pros, cons, jobTitle를 추출하는 완전한 예제입니다.

import json
import re
from curl_cffi import requests as cffi_requests

PROXY = "http://user-country-US-session-gd001:pass@gate.proxyhat.com:8080"
BASE = "https://www.glassdoor.com"

def get_csrf_and_cookies(employer_id: str, session_id: str):
    """공개 리뷰 페이지에서 CSRF 토큰과 DataDome 쿠키 획득"""
    proxy = f"http://user-country-US-session-{session_id}:pass@gate.proxyhat.com:8080"
    url = f"{BASE}/Reviews/Company-Re{employer_id}.htm"
    resp = cffi_requests.get(url, impersonate="chrome", proxies={"https": proxy, "http": proxy})
    if resp.status_code == 403:
        raise Exception(f"DataDome 차단: {resp.status_code}")
    # meta 태그 또는 인라인 JS에서 gd-csrf-token 추출
    match = re.search(r'gd-csrf-token["\']\s*[:=]\s*["\']([a-f0-9-]+)', resp.text)
    csrf_token = match.group(1) if match else ""
    return csrf_token, resp.cookies, proxy

def fetch_reviews_bff(employer_id: str, cursor: str = None, session_id: str = "gd001"):
    """BFF GraphQL 엔드포인트로 리뷰 목록 조회"""
    csrf_token, cookies, proxy = get_csrf_and_cookies(employer_id, session_id)
    
    query = """
    query EmployerReviews($employerId: ID!, $cursor: String) {
      employer(employerId: $employerId) {
        reviews(cursor: $cursor) {
          nodes {
            ratingOverall
            pros
            cons
            jobTitle { label }
            reviewDateTime
          }
          pageInfo { nextCursor hasNextPage }
        }
      }
    }"""
    
    variables = {"employerId": employer_id, "cursor": cursor}
    
    headers = {
        "Content-Type": "application/json",
        "gd-csrf-token": csrf_token,
        "Origin": BASE,
        "Referer": f"{BASE}/Reviews/Company-Re{employer_id}.htm",
    }
    
    resp = cffi_requests.post(
        f"{BASE}/bff/graphql",
        json={"query": query, "variables": variables},
        headers=headers,
        cookies=cookies,
        impersonate="chrome",
        proxies={"https": proxy, "http": proxy}
    )
    
    data = resp.json()
    reviews = data.get("data", {}).get("employer", {}).get("reviews", {})
    
    for node in reviews.get("nodes", []):
        print(f"평점: {node['ratingOverall']} | 직무: {node['jobTitle']['label']}")
        print(f"  장점: {node['pros'][:80]}...")
        print(f"  단점: {node['cons'][:80]}...")
    
    return reviews.get("pageInfo", {})

# 실행
page_info = fetch_reviews_bff("9079", session_id="gd-google-1")
print(f"다음 페이지: {page_info}")

핵심 포인트: session-gd-google-1 플래그를 username에 추가하면 ProxyHat이 sticky session을 생성합니다. 동일 세션 ID로 보내는 모든 요청이 같은 residential IP로 라우팅되므로, DataDome 쿠키가 유효하게 유지됩니다.

페이지네이션, 페이싱, 챌린지 재시도 로직

커서 기반 페이지네이션

Glassdoor BFF GraphQL은 cursor 기반 페이지네이션을 사용합니다. 응답의 pageInfo.nextCursor를 다음 요청의 variables.cursor로 전달하면 됩니다. hasNextPagefalse일 때까지 반복합니다.

페이싱 전략

  • 요청 간격: 페이지당 최소 3–5초 대기. 분당 20–30 요청 이하 유지.
  • 세션 전환: 50–100개 리뷰(5–10페이지)마다 새 session_id로 전환해 IP를 회전. DataDome 쿠키도 새로 획득.
  • 지역 분산: user-country-US, user-country-GB, user-country-DE를 순환하면 단일 국가 IP 풀 소진을 방지합니다. ProxyHat 위치 목록에서 전체 국가 코드를 확인하세요.

챌린지 재시도 로직

import time
import random

def scrape_all_reviews(employer_id: str, max_pages: int = 50):
    cursor = None
    for page in range(max_pages):
        session_id = f"gd-{employer_id}-{page // 10}"
        try:
            page_info = fetch_reviews_bff(employer_id, cursor, session_id)
            if not page_info.get("hasNextPage"):
                break
            cursor = page_info["nextCursor"]
            time.sleep(random.uniform(3, 7))  # 무작위 지연
        except Exception as e:
            print(f"페이지 {page} 실패: {e}. 30초 후 재시도.")
            time.sleep(30)
            # 새 세션으로 재시도
            session_id = f"gd-{employer_id}-retry-{page}"
            try:
                page_info = fetch_reviews_bff(employer_id, cursor, session_id)
                cursor = page_info.get("nextCursor", cursor)
            except Exception:
                print(f"재시도 실패. 다음 페이지로 건너뜀.")
                continue

Node.js 예제: 커서 페이지네이션 전체 파이프라인

Node.js 환경에서는 curl-impersonate 바인딩인 cycletls 또는 node-libcurl을 사용할 수 있습니다. 다음은 ProxyHat 프록시를 통한 기본 요청 예제입니다.

const { Curl } = require('node-libcurl');

async function fetchGlassdoorPage(employerId, sessionId) {
  const proxyUrl = `http://user-country-US-session-${sessionId}:pass@gate.proxyhat.com:8080`;
  const targetUrl = `https://www.glassdoor.com/Reviews/Company-Re${employerId}.htm`;
  
  const curl = new Curl();
  curl.setOpt('URL', targetUrl);
  curl.setOpt('PROXY', proxyUrl);
  curl.setOpt('FOLLOWLOCATION', true);
  curl.setOpt('HTTP_VERSION', 'CURL_HTTP_VERSION_2_0');
  // Chrome TLS 지문 모방을 위한 impersonate 옵션 (cycletls 사용 시)
  
  return new Promise((resolve, reject) => {
    curl.on('end', (statusCode, body) => {
      curl.close();
      resolve({ statusCode, body });
    });
    curl.on('error', (err) => {
      curl.close();
      reject(err);
    });
    curl.perform();
  });
}

// 사용
fetchGlassdoorPage('9079', 'gd-node-1')
  .then(({ statusCode, body }) => console.log(`상태: ${statusCode}, 길이: ${body.length}`))
  .catch(console.error);

ProxyHat 설정 및 내부 링크

ProxyHat residential 프록시는 gate.proxyhat.com:8080(HTTP) 또는 :1080(SOCKS5) 게이트웨이로 접근합니다. username에 국가, 도시, 세션 플래그를 조합해 지역 타겟팅과 sticky session을 제어합니다.

  • 국가 타겟팅: user-country-US:pass — 미국 residential IP
  • 도시 타겟팅: user-country-US-city-sanfrancisco:pass
  • Sticky session: user-session-gd-google-1:pass — 동일 IP 유지
  • 조합: user-country-US-session-gd001:pass

자세한 설정은 ProxyHat 문서를 참조하세요. 가격 정보는 프록시 가격 페이지에서, 웹 스크래핑 활용 사례는 웹 스크래핑 사용 사례에서 확인할 수 있습니다. SERP 추적과 결합하려면 SERP 추적 사용 사례도 참고하세요.

흔한 실수와 엣지 케이스

1. 표준 requests 라이브러리 사용

requests.get()은 TLS 지문이 Chrome과 달라 Cloudflare에서 즉시 403을 반환합니다. 반드시 curl_cffiimpersonate="chrome"을 사용하세요.

2. DataDome 쿠키 재사용 없이 매 요청마다 새 세션

쿠키 없이 GraphQL 엔드포인트를 직접 호출하면 403 Forbidden. 먼저 공개 HTML 페이지를 로드해 쿠키를 획득한 후, 같은 프록시 세션(sticky)으로 GraphQL을 호출해야 합니다.

3. gd-csrf-token 누락

BFF GraphQL 요청에 gd-csrf-token 헤더가 없으면 400 Bad Request. 토큰은 페이지 HTML 내 인라인 JavaScript 또는 <meta> 태그에서 정규식으로 추출합니다.

4. 과도한 동시성

100개 이상의 동시 요청은 DataDome 행동 분석을 트리거합니다. 동시 연결을 5–10개로 제한하고, 요청 간 무작위 지연(3–7초)을 삽입하세요.

5. 로그인 뒤 데이터 스크래핑

연봉 상세 분석, 전체 리뷰 텍스트는 로그인 뒤에 있습니다. 이 데이터를 자동화된 수단으로 가져오는 것은 ToS 위반이며 CFAA 위험을 초래합니다. 공식 데이터 라이선스를 검토하세요.

윤리적 스크래핑: 언제 API를 써야 하는가

Glassdoor 리뷰 데이터는 작성자가 익명이지만, 직무명과 부서 정보를 조합하면 특정 개인을 식별할 수 있습니다. EU에서는 이것이 GDPR의 개인정보 정의에 해당할 수 있습니다. 다음 원칙을 지키세요:

  • 집계 데이터만 수집: 개별 리뷰 전문이 아닌, 평점 분포, 장단점 키워드 빈도, 직무별 평균 평점 같은 집계 통계만 추출.
  • 개인 식별 정보 제외: 작성자 ID, 이메일, 특정 부서 좁은 직무명 등 식별 가능한 필드는 저장하지 않음.
  • robots.txt 확인: https://www.glassdoor.com/robots.txt를 확인해 허용된 경로만 접근.
  • rate-limit 존중: 분당 30 요청 이하 유지, 서버 부하 최소화.
  • 데이터 보관 기간 제한: 수집 후 30일 이내 분석 완료 및 원본 삭제, 집계 결과만 보관.

공식 데이터 라이선스가 필요한 경우

대규모 연봉 벤치마킹 리포트, 상업적 HR 분석 SaaS, 또는 로그인 뒤 연봉 상세 데이터가 필요한 경우, Glassdoor의 공식 파트너십/데이터 라이선스 프로그램을 통해 합법적으로 데이터를 구매하는 것이 올바른 접근입니다. 스크래핑은 공개 데이터의 소규모 분석에만 적합합니다.

Key Takeaways

  • Glassdoor 공개 리뷰 페이지(/Reviews/...E<id>.htm)는 로그인 없이 접근 가능. 연봉 상세는 로그인 뒤에 있으므로 제외.
  • DataDome + Cloudflare Bot Management를 우회하려면 curl_cffi(Chrome TLS 모방)과 residential 회전 프록시가 필수.
  • BFF GraphQL 엔드포인트(/bff/graphql)로 구조화된 JSON 리뷰 노드를 직접 수신. gd-csrf-token 헤더 필수.
  • ProxyHat sticky session(user-session-xxx)으로 DataDome 쿠키를 유지하면서 페이지네이션 커서를 따라 이동.
  • 페이싱: 분당 20–30 요청, 50–100 리뷰마다 세션 전환, 3–7초 무작위 지연.
  • 윤리: 집계 데이터만 수집, 개인 식별 정보 제외, GDPR 준수, 상업적 대규모 사용은 공식 라이선스 검토.

FAQ

Glassdoor 리뷰 스크래핑이란 무엇인가요?

Glassdoor 리뷰 스크래핑은 Glassdoor의 공개 회사 리뷰 페이지에서 평점, 장단점, 직무명 등의 구조화된 데이터를 자동화된 방식으로 수집하는 작업입니다. 로그인 없이 접근 가능한 공개 페이지에 한정하며, BFF GraphQL 엔드포인트를 활용해 HTML 파싱 대신 JSON을 직접 수신할 수 있습니다. 연봉 상세 데이터는 로그인 뒤에 있으므로 제외해야 합니다.

왜 Glassdoor 연봉 데이터 스크래핑에 프록시가 필요한가요?

Glassdoor는 DataDome과 Cloudflare Bot Management를 운영하여 데이터센터 IP를 즉시 차단하고, 동일 IP의 다수 요청을 rate-limit합니다. Residential 프록시는 실제 ISP IP를 제공하므로 DataDome의 IP 스코어링을 통과할 수 있습니다. 또한 요청마다 IP를 회전하거나 sticky session으로 쿠키를 유지하면서 차단을 회피할 수 있습니다.

어떤 프록시 유형이 Glassdoor 스크래핑에 가장 적합한가요?

Residential 회전 프록시가 가장 적합합니다. 데이터센터 프록시는 DataDome에서 약 5% 통과율로 실질적 사용이 불가능하며, mobile 프록시는 통과율이 약 95%로 가장 높지만 비용이 상대적으로 높습니다. Residential 프록시는 약 85% 통과율에 200ms 수준의 지연으로 비용과 성능의 균형이 좋습니다. ProxyHat residential 프록시는 gate.proxyhat.com:8080으로 접근합니다.

Glassdoor 스크래핑 시 차단을 피하려면 어떻게 하나요?

세 가지를 결합해야 합니다: 첫째, curl_cffiimpersonate="chrome"으로 Chrome TLS 지문을 모방. 둘째, ProxyHat residential 프록시로 IP를 회전하되 sticky session으로 DataDome 쿠키 유지. 셋째, 분당 20–30 요청 이하로 페이싱하고 3–7초 무작위 지연을 삽입. 403 응답 시 30초 대기 후 새 세션 ID로 재시도하는 로직을 구현하세요.

Glassdoor BFF GraphQL 엔드포인트는 공개 데이터인가요?

네, BFF GraphQL 엔드포인트(/bff/graphql)는 공개 리뷰 페이지 로딩 시 브라우저가 자동으로 호출하는 엔드포인트입니다. 로그인 없이 접근 가능한 공개 리뷰 데이터를 구조화된 JSON으로 반환합니다. 단, gd-csrf-token 헤더와 유효한 DataDome 쿠키가 필요하며, 로그인 뒤 연봉 상세 데이터는 이 엔드포인트로도 접근할 수 없습니다.

시작할 준비가 되셨나요?

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

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