Как собрать данные Glassdoor на Python: вакансии, зарплаты и отзывы

Последнее обновление: July 9, 2026
Как собрать данные Glassdoor на Python: вакансии, зарплаты и отзывы

Если твой парсер Glassdoor отлично работал в 2022 году, а теперь возвращает одни 403, ты не одинок. На форумах снова и снова всплывает один и тот же вопрос: «Кто-нибудь знает, почему этот парсер больше не работает?»

Короткий ответ: Glassdoor полностью поменял правила игры. В июле 2025 года Recruit Holdings включила Glassdoor в экосистему Indeed, уволила 1 300 сотрудников и усилила антибот-защиту до такой степени, что обычные скрипты на Selenium и requests блокируются ещё до загрузки первого байта HTML. По состоянию на февраль 2026 года вход в Glassdoor полностью проходит через Indeed Login — так что любой туториал, где жёстко прописана отдельная форма входа Glassdoor, уже сломан на уровне архитектуры. При этом платформа всё ещё хранит более 180 миллионов отзывов, зарплат и инсайтов по 2,5 миллионам работодателей. Эти данные невероятно ценны для HR-аналитики, оценки конкурентов и поиска потенциальных клиентов — если, конечно, до них удастся добраться. Это руководство — рабочая версия после всех этих изменений. Здесь разобраны все три типа данных Glassdoor: вакансии, отзывы и зарплаты — в одном месте. Я покажу Python-подход с рабочим кодом на 2025 год, объясню, что именно тебя блокирует и как это обойти, а также покажу no-code альтернатива для тех, кто не хочет заниматься инженерией.

Зачем собирать данные Glassdoor на Python в 2025 году?

Glassdoor — это не просто сайт с вакансиями. Это одна из самых богатых баз по компаниям в интернете: ею пользуется примерно треть компаний из Fortune 500, а ежемесячная аудитория составляет около 55 миллионов уникальных посетителей. Данные, которые лежат за этими страницами, влияют на реальные бизнес-решения сразу в нескольких командах.

Вот как разные отделы используют данные Glassdoor на практике:

СценарийКакие данные нужныКому это полезно
Анализ зарплатДиапазоны зарплат, размер выборкиHR, компенсации и льготы, операционные команды
Отслеживание найма конкурентовСписок вакансий, скорость публикацийПродажи, стратегия, VC/корпоративное развитие
Мониторинг бренда работодателяТекст отзывов, динамика рейтинга, одобрение CEOHR, маркетинг, PR/коммуникации
Генерация лидов (растущие компании)Вакансии + информация о компанииКоманды продаж, SDR
Рыночные и академические исследованияВсе три типа данныхАналитики, консультанты, исследователи

glassdoor_stats_00937e478e.png

Когда BLS не смог опубликовать данные о вакансиях во время октябрьского шатдауна правительства США в 2025 году, собственная команда Glassdoor по экономическим исследованиям выпустила альтернативный отчёт по рынку труда на основе своей базы. Настолько серьёзно к этим данным теперь относятся аналитики уровня институтов.

Python по-прежнему остаётся языком по умолчанию: экосистема просто вне конкуренции — Playwright для автоматизации браузера, parsel/lxml для парсинга, curl_cffi для обхода TLS-фингерпринтинга, плюс огромное сообщество с рабочими паттернами. Проблема не в Python. Проблема в том, что Glassdoor стал намного сложнее для сбора.

Собирай данные Glassdoor с помощью AI Get Started Free

Если тебе нужен no-code вариант для извлечения данных Glassdoor, Thunderbit поможет собрать вакансии, отзывы и страницы с зарплатами без разработки и поддержки собственного Python-стека.

Какие данные Glassdoor вообще можно собрать?

Большинство туториалов покрывают только вакансии. Но по реальным запросам пользователей — если судить по форумам, GitHub issues и Reddit, за которыми я следил, — наибольший интерес вызывают два типа данных, которые почти никто не объясняет: отзывы и зарплаты. Ниже — полный разбор того, что реально можно извлечь по всем трём категориям.

Список вакансий

Самый доступный тип данных. Можно собрать: название вакансии, название компании, локацию, оценку зарплаты, рейтинг компании, дату публикации, бейдж easy apply и ссылку на вакансию. Списки вакансий частично доступны без входа, хотя после нескольких страниц Glassdoor может показать окно логина.

Отзывы о компании

Вот где начинается самое интересное для анализа бренда работодателя. Можно извлечь: общий рейтинг, подрейтинги (work-life balance, culture & values, diversity & inclusion, career opportunities, comp & benefits, senior management), текст плюсов, текст минусов, должность автора, дату отзыва и статус занятости. Полный текст отзыва защищён логином — ты увидишь лишь фрагмент, а полный блок pros/cons потребует авторизации.

Данные о зарплатах

Самый востребованный и одновременно самый проблемный тип данных. Можно извлечь: название должности, диапазон базовой ставки, общий диапазон компенсации, количество отчётов по зарплате и локацию. Но страницы зарплат полностью закрыты логином, а иногда Glassdoor добавляет ещё и сценарий "contribute to unlock", где нужно сначала отправить свою зарплату, чтобы увидеть чужие. Ни один конкурентный туториал не даёт для этого рабочий код — мы это исправим.

Что требует входа, а что нет

Эта таблица спасёт тебя от неприятного сюрприза, когда нужная страница вернёт пустые данные:

Тип данныхДоступно без входа?Примечания
Заголовки вакансий и базовая информацияВ основном даПосле нескольких страниц может появиться всплывающее окно
Полное описание вакансииЧастичноЧасто закрывается после 2–3 просмотров
Отзывы о компании (полный текст)Нет — нужен входВидна только выдержка, полный текст закрыт
Данные о зарплатахНет — нужен входМожет дополнительно требовать "contribute to unlock"

Почему твой старый парсер Glassdoor, скорее всего, сломался

glassdoor_defense_82a26cd8bd.png

Скажу прямо: если ты копируешь код из туториала 2021–2023 года, он не заработает. Самый популярный старый Selenium-парсер Glassdoor на GitHub (MatthewChatham/glassdoor-review-scraper, около 1,4k звёзд) имеет 12+ открытых нерешённых проблем — в том числе "Glassdoor new UI design", "Cloudflare anti-bot protection" и "NoSuchElementException". Репозиторий фактически заброшен. Актор glassdoor-jobs-scraper у Apify помечен как DEPRECATED. ScrapeOps оценивает сложность скрапинга Glassdoor в 9/10 и сложность обхода защиты в 8/10.

Вот что изменилось и почему старый код больше не работает:

Слой защитыЧто изменилосьКак это влияет на старые парсеры
Cloudflare Bot ManagementС 2024 года ужесточён JA3/JA4-фингерпринтингПростые requests/Selenium-скрипты сразу получают 403
Динамические CSS-классыИмена классов рандомизируются при каждом билдеСтарые CSS-селекторы из туториалов тихо перестают работать
Rate limiting + отслеживание сессийЖёстче ограничения по IP и по сессииБлокировка наступает уже после меньшего числа страниц
CAPTCHA-челленджи (вероятно Cloudflare Turnstile)Появляются чаще, особенно при пагинацииHeadless-браузеры провоцируют челленджи
Расширенная логин-стенаБольше типов страниц требует авторизациюСтраницы зарплат и отзывов возвращают пустые данные
Миграция на Indeed Login (февраль 2026)Форма входа Glassdoor полностью замененаЛюбой код, завязанный на старый DOM логина, мёртв

В гайде Scrapfly за 2026 год есть прямое предупреждение: "Glassdoor is known for its high blocking rate, so if you get None values while running the Python code, it's likely you're getting blocked." А пост на DEV.to от марта 2026 года говорит ещё жёстче: "Simple HTTP requests with requests or httpx get blocked instantly."

Меры обхода, которые я покажу ниже — Patchright (stealth-версия Playwright), селекторы по data-test, ротация residential-прокси и авторизованные persistent sessions — как раз и рассчитаны на каждый из этих уровней защиты.

Glassdoor API или Python-скрапинг: сначала выбери правильный путь

Во многих обсуждениях на форумах спрашивают: "Может, просто использовать Glassdoor API?" — и ответ такой: не получится.

Старый Glassdoor Partner API закрыт для новых заявок. Портал разработчика формально ещё существует, но возвращает HTTP 403. Публичного endpoint’а для отзывов никогда не было — именно поэтому MatthewChatham и сделал свой парсер: "потому что у Glassdoor нет API для отзывов." И никакого пути миграции для отзывов или зарплат через Indeed Publisher API тоже нет.

Вот честное сравнение:

ФакторGlassdoor Partner API v1Python-скрапингThunderbit (no-code)
ДоступЗакрыт для новых заявокОткрыт (нужно реализовать самому)Расширение для Chrome
Список вакансийОграничен / уходит в архивДоступен, но с усилиямиДоступен
Отзывы о компанииПублично никогда не былоДа (нужен вход)Да (через Browser Mode)
Данные о зарплатахПублично никогда не былоДа (нужен вход)Да
Rate limitsНе документированыТы контролируешь частотуПо кредитной модели
Сложность настройкиНельзя зарегистрировать новые приложенияОт часов до днейОколо 2 минут
Нагрузка на поддержкуН/ДВысокая (изменения HTML ломают код)Низкая (AI заново предлагает поля)

Если тебе нужны отзывы или данные о зарплатах — а большинству читателей именно они и нужны — у тебя по сути остаются только Python-скрапинг или no-code инструмент.

Перед началом работы

  • Сложность: средняя (нужно уверенно чувствовать себя в Python и терминале)
  • Время: около 30–60 минут на полную настройку; затем примерно 10 минут на каждый тип данных
  • Что понадобится:
    • Python 3.10+ (рекомендуются 3.11 или 3.12)
    • Установленный браузер Chrome
    • Аккаунт Glassdoor (бесплатный — нужен для данных по зарплатам и отзывам)
    • Rotating residential proxies (если нужно собирать больше нескольких страниц)
    • Опционально: расширение Thunderbit для Chrome, если хочешь пойти без кода

Инструменты и библиотеки для сбора данных Glassdoor на Python в 2025 году

Ландшафт инструментов сильно изменился. Ниже — то, что реально работает против текущей защиты Glassdoor.

Почему Patchright — лучший выбор для Glassdoor

Patchright — это stealth-форк Playwright, который исправляет утечку Runtime.Enable в CDP, то есть конкретную техническую причину, почему обычный Playwright ломается на сайтах под Cloudflare. Он использует тот же API, что и Playwright, поэтому если ты умеешь работать с Playwright, ты поймёшь и Patchright. Текущая версия 1.58.2 (март 2026) активно поддерживается.

По сравнению с альтернативами:

  • Обычный Playwright: Glassdoor обнаруживает его на странице входа из-за утечки Runtime.Enable
  • Selenium + undetected-chromedriver: последний релиз undetected-chromedriver был в феврале 2024 года — это уже почти legacy. В бенчмарке Scrapfly он "failed on every domain in our test"
  • requests + BeautifulSoup: не умеют рендерить JavaScript и сразу блокируются TLS-фингерпринтингом Cloudflare
  • curl_cffi: отличный быстрый вариант (в 10–20 раз быстрее браузера), когда страницы отдают __NEXT_DATA__ прямо в исходном HTML, но он не справится с логином и промежуточными челленджами

Поддерживающие библиотеки

  • parsel (1.11.0) или lxml (6.0.4): быстрый HTML/XPath-парсинг
  • csv или pandas: экспорт данных
  • asyncio: асинхронный скрапинг для более быстрой пагинации

Прокси: только residential

Cloudflare в Glassdoor очень агрессивно относится к datacenter ASN. Сообщается, что residential-прокси снижают долю блокировок с 20–30% до менее чем 5%. Стартовые цены — около $1.75/GB у IPRoyal (по акции) или $3.00/GB у Decodo. Для production-скрапинга закладывай $3–8/GB в зависимости от объёма.

Случайные паузы между запросами (минимум 3–8 секунд, 5–15 секунд для длинных прогонов) обязательны независимо от качества прокси.

Шаг 1: Настрой окружение Python

Создай папку проекта и установи рекомендуемый стек:

mkdir glassdoor-scraper && cd glassdoor-scraper
python3.11 -m venv .venv
source .venv/bin/activate
pip install --upgrade pip

# Основной стек
pip install patchright==1.58.2 parsel==1.11.0

# Установка бинарников браузера
patchright install chromium

# Опционально: быстрый путь для извлечения __NEXT_DATA__
pip install "curl_cffi==0.15.0"

Patchright должен скачать Chromium-бинарник. Если patchright install chromium не сработает, проверь, хватает ли места на диске (около 300 МБ), и убедись, что версия Python — 3.10+.

Шаг 2: Запусти Patchright и открой Glassdoor

Ниже — базовый шаблон запуска, который работает против защиты Cloudflare у Glassdoor:

from patchright.sync_api import sync_playwright
import random, time

with sync_playwright() as p:
    browser = p.chromium.launch(
        headless=False,          # headless по-прежнему легче обнаружить
        channel="chrome",        # используем настоящий Chrome, а не bundled Chromium
    )
    context = browser.new_context(
        viewport={"width": 1440, "height": 900},
        locale="en-US",
        timezone_id="America/New_York",
        user_agent=(
            "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) "
            "AppleWebKit/537.36 (KHTML, like Gecko) "
            "Chrome/134.0.0.0 Safari/537.36"
        ),
    )
    page = context.new_page()
    page.goto(
        "https://www.glassdoor.com/Job/new-york-data-engineer-jobs-"
        "SRCH_IL.0,8_IC1132348_KO9,22.htm"
    )

    # Убираем окно логина — контент при этом остаётся в DOM
    page.add_style_tag(content="""
        #HardsellOverlay, .LoginModal { display: none !important; }
        body { overflow: auto !important; position: initial !important; }
    """)

    page.wait_for_selector("[data-test='jobListing']")
    print("Страница загружена — карточки вакансий видны.")

На что здесь стоит обратить внимание. Флаг channel="chrome" заставляет Patchright использовать установленный у тебя Chrome, а не свой Chromium — это даёт более правдоподобный браузерный отпечаток. Приём с add_style_tag скрывает модальное окно логина Glassdoor (#HardsellOverlay) без необходимости что-либо нажимать. Scrapfly подтверждает, что "весь контент всё ещё там, он просто перекрыт оверлеем" — HTML содержит данные независимо от того, показано ли окно.

Ты должен увидеть, как окно Chrome открывает страницу поиска вакансий Glassdoor и показывает карточки вакансий без мешающего попапа входа.

Шаг 3: Собираем список вакансий Glassdoor

Находим стабильные селекторы

Glassdoor рандомизирует CSS-классы при каждом билде — поэтому селектор .jobCard_xyz123 из туториала 2023 года сегодня тихо вернёт пустоту. Вместо этого используй атрибуты data-test, которые являются внутренней QA-конвенцией Glassdoor и остаются стабильными между деплоями.

Вот справочник селекторов для полей вакансий:

ПолеСелектор
Контейнер карточки вакансии[data-test="jobListing"]
Название вакансии[data-test="job-title"]
Ссылка на вакансиюa[data-test="job-link"]
Название компании[data-test="employer-name"]
Локация[data-test="emp-location"]
Диапазон зарплаты[data-test="detailSalary"]
Рейтинг компании[data-test="rating"]
Дата публикации[data-test="job-age"]
Следующая страница пагинации[data-test="pagination-next"]

Извлекаем данные по вакансиям

from parsel import Selector
import csv, random, time

def scrape_jobs(page, max_pages=5):
    all_jobs = []

    for page_num in range(1, max_pages + 1):
        html = page.content()
        sel = Selector(text=html)
        cards = sel.css('[data-test="jobListing"]')

        if not cards:
            print(f"Страница {page_num}: карточки не найдены — возможно, блокировка или изменился селектор.")
            break

        for card in cards:
            job = {
                "title": card.css('[data-test="job-title"]::text').get("").strip(),
                "company": card.css('[data-test="employer-name"]::text').get("").strip(),
                "location": card.css('[data-test="emp-location"]::text').get("").strip(),
                "salary": card.css('[data-test="detailSalary"]::text').get("").strip(),
                "rating": card.css('[data-test="rating"]::text').get("").strip(),
                "link": card.css('a[data-test="job-link"]::attr(href)').get(""),
                "posted": card.css('[data-test="job-age"]::text').get("").strip(),
            }
            if job["link"] and not job["link"].startswith("http"):
                job["link"] = "https://www.glassdoor.com" + job["link"]
            all_jobs.append(job)

        print(f"Страница {page_num}: собрано {len(cards)} вакансий")

        # Пагинация
        next_btn = page.query_selector('[data-test="pagination-next"]')
        if next_btn and page_num < max_pages:
            next_btn.click()
            time.sleep(random.uniform(3, 8))
            page.wait_for_selector("[data-test='jobListing']")
        else:
            break

    return all_jobs

Сохраняем в CSV

def save_to_csv(jobs, filename="glassdoor_jobs.csv"):
    if not jobs:
        print("Нет данных для сохранения.")
        return
    keys = jobs[0].keys()
    with open(filename, "w", newline="", encoding="utf-8") as f:
        writer = csv.DictWriter(f, fieldnames=keys)
        writer.writeheader()
        writer.writerows(jobs)
    print(f"Сохранено {len(jobs)} вакансий в {filename}")

Небольшое замечание про ограничения пагинации: Glassdoor ограничивает результаты поиска примерно 30 страницами независимо от общего числа результатов. Если тебе нужно больше охвата, лучше использовать фильтры (локация, тип работы, диапазон зарплаты), чем пытаться листать дальше лимита.

По моим тестам, сбор 5 страниц вакансий (примерно 75 вакансий) занял около 45 секунд с рандомными паузами. Вручную на это ушло бы минимум 20 минут копипаста.

Шаг 4: Собираем отзывы о компаниях Glassdoor

Это раздел, для которого ни один другой туториал не даёт рабочего кода. Именно в отзывах находится настоящая аналитика по работодателю: тональность, сигналы о культуре, красные флаги в управлении.

Переходим на страницу отзывов

URL отзывов имеют такой формат: /Reviews/{Company}-Reviews-E{id}.htm. ID работодателя можно найти, открыв компанию в Glassdoor и посмотрев URL.

def navigate_to_reviews(page, company_reviews_url):
    page.goto(company_reviews_url)
    page.add_style_tag(content="""
        #HardsellOverlay, .LoginModal { display: none !important; }
        body { overflow: auto !important; position: initial !important; }
    """)
    page.wait_for_selector('[data-test="review"]', timeout=15000)

Скрытый BFF-endpoint (самый чистый путь)

Вот главное открытие моего исследования: у отзывов Glassdoor есть рабочий внутренний JSON API, который полностью обходится без HTML-парсинга. Репозиторий Scrapfly с парсерами документирует этот endpoint, и он гораздо надёжнее, чем парсинг DOM.

import json, re, requests

def get_review_ids(page):
    """Извлекает employerId и dynamicProfileId из HTML страницы отзывов."""
    html = page.content()
    sel = Selector(text=html)
    script_text = sel.xpath(
        "//script[contains(text(), 'profileId')]/text()"
    ).get("")
    employer_match = re.search(r'"employer"\s*:\s*(\{[^}]+\})', script_text)
    if employer_match:
        meta = json.loads(employer_match.group(1))
        return meta.get("id"), meta.get("profileId")
    return None, None

def fetch_reviews_bff(page, employer_id, profile_id, max_pages=5):
    """Вызывает внутренний BFF-endpoint Glassdoor для структурированных данных об отзывах."""
    all_reviews = []
    cookies = {c["name"]: c["value"] for c in page.context.cookies()}

    for pg in range(1, max_pages + 1):
        payload = {
            "applyDefaultCriteria": True,
            "employerId": employer_id,
            "dynamicProfileId": profile_id,
            "employmentStatuses": ["REGULAR", "PART_TIME"],
            "language": "eng",
            "onlyCurrentEmployees": False,
            "page": pg,
            "pageSize": 10,
            "sort": "DATE",
            "textSearch": "",
        }
        resp = requests.post(
            "https://www.glassdoor.com/bff/employer-profile-mono/employer-reviews",
            json=payload,
            cookies=cookies,
            headers={"Content-Type": "application/json"},
        )
        if resp.status_code != 200:
            print(f"BFF вернул {resp.status_code} на странице {pg}")
            break

        data = resp.json()
        reviews = data.get("data", {}).get("employerReviews", {}).get("reviews", [])
        total_pages = data.get("data", {}).get("employerReviews", {}).get("numberOfPages", 1)

        for r in reviews:
            all_reviews.append({
                "title": r.get("summary", ""),
                "rating": r.get("ratingOverall"),
                "pros": r.get("pros", ""),
                "cons": r.get("cons", ""),
                "author_role": r.get("jobTitle", {}).get("text", ""),
                "date": r.get("reviewDateTime", ""),
                "recommend": r.get("isRecommend"),
            })

        print(f"Страница отзывов {pg}/{total_pages}: получено {len(reviews)} отзывов")
        if pg >= total_pages:
            break
        time.sleep(random.uniform(3, 6))

    return all_reviews

BFF-endpoint даёт чистый JSON со всеми полями отзывов — без HTML-парсинга и без риска поломки CSS-селекторов. Тебе нужны session cookies из авторизованного Playwright-контекста (см. шаг 6 ниже), а также сначала нужно вытащить employerId и dynamicProfileId из HTML страницы отзывов.

Fallback-селекторы для отзывов через HTML

Если BFF-endpoint изменится или ты предпочитаешь DOM-парсинг, вот стабильные data-test селекторы:

ПолеСелектор
Контейнер отзыва[data-test="review"]
Заголовок[data-test="review-title"]
Общий рейтинг[data-test="overall-rating"]
Плюсы[data-test="pros"]
Минусы[data-test="cons"]
Дата[data-test="review-date"]
Должность автора[data-test="author-jobTitle"]

Шаг 5: Собираем данные о зарплатах Glassdoor

Страницы зарплат полностью закрыты логином. Прежде чем этот код начнёт возвращать реальные данные, у тебя должна быть авторизованная сессия (шаг 6).

Переходим на страницу зарплат

URL зарплат имеют вид: /Salary/{Company}-Salaries-E{id}.htm, а пагинация добавляется как _P{n}.htm.

def scrape_salaries(page, salary_url, max_pages=3):
    all_salaries = []

    for pg in range(1, max_pages + 1):
        url = salary_url if pg == 1 else salary_url.replace(".htm", f"_P{pg}.htm")
        page.goto(url)
        page.add_style_tag(content="""
            #HardsellOverlay { display: none !important; }
            body { overflow: auto !important; position: initial !important; }
        """)
        time.sleep(random.uniform(3, 7))

        html = page.content()
        sel = Selector(text=html)
        items = sel.css('[data-test="salary-item"]')

        if not items:
            print(f"Страница зарплат {pg}: элементов нет — возможно, блокировка или логин-стена.")
            break

        for item in items:
            salary = {
                "job_title": item.css('[class*="SalaryItem_jobTitle__"]::text').get("").strip(),
                "salary_range": item.css('[class*="SalaryItem_salaryRange__"]::text').get("").strip(),
                "count": item.css('[class*="SalaryItem_salaryCount__"]::text').get("").strip(),
            }
            all_salaries.append(salary)

        print(f"Страница зарплат {pg}: собрано {len(items)} записей")

    return all_salaries

Обрати внимание на паттерн [class*="SalaryItem_jobTitle__"] по префиксу. На странице зарплат Glassdoor использует CSS-module-хэши (например, SalaryItem_jobTitle__XWGpT), и суффикс-хэш меняется при каждом деплое. Префикс остаётся стабильным — хэш нет. Никогда не хардкодь полное имя класса.

Шаг 6: Обходим логин-стену Glassdoor

Это критически важный шаг, который открывает доступ к данным о зарплатах и полным текстам отзывов. Подход такой: один раз вручную войти в видимом браузере, сохранить состояние авторизованной сессии, а затем переиспользовать его во всех следующих запусках.

Сохраняем авторизованную сессию

Запусти этот скрипт один раз. Он открывает окно Chrome, переходит на страницу входа Glassdoor (которая теперь перенаправляет на Indeed Login) и ждёт, пока ты войдёшь вручную:

import asyncio
from pathlib import Path
from patchright.async_api import async_playwright

STATE_FILE = Path("glassdoor_state.json")

async def login_and_save():
    async with async_playwright() as p:
        browser = await p.chromium.launch(headless=False, channel="chrome")
        context = await browser.new_context(
            viewport={"width": 1366, "height": 800},
            locale="en-US",
        )
        page = await context.new_page()
        await page.goto("https://www.glassdoor.com/profile/login_input.htm")
        print("Войди в браузере, затем нажми Enter здесь...")
        input()
        await context.storage_state(path=str(STATE_FILE))
        print(f"Сессия сохранена в {STATE_FILE}")
        await browser.close()

asyncio.run(login_and_save())

После входа и нажатия Enter Patchright сохраняет все cookies и local storage в glassdoor_state.json. В этом файле будут gdId, GSESSIONID, cf_clearance и auth tokens.

Переиспользуем сессию для скрапинга

Каждый следующий запуск загружает сохранённое состояние — ручной вход уже не нужен:

async def scrape_with_auth(target_url):
    async with async_playwright() as p:
        browser = await p.chromium.launch(headless=True, channel="chrome")
        context = await browser.new_context(
            storage_state="glassdoor_state.json"
        )
        page = await context.new_page()
        await page.goto(target_url)
        await page.add_style_tag(
            content="#HardsellOverlay{display:none!important}"
        )
        await page.wait_for_load_state("networkidle")
        html = await page.content()
        await browser.close()
        return html

Обычно сохранённая сессия живёт 20–30 минут активного использования, после чего Glassdoor снова запускает проверку. Для более длинных прогонов добавь проверку: если страница, на которой точно должен быть контент, возвращает ноль результатов, просто заново запусти скрипт входа и обнови файл состояния.

Как обнаружить и закрыть всплывающее окно логина

Для частично закрытых страниц — например, список вакансий с данными под модальным окном — помогает CSS-инъекция из предыдущих шагов:

page.add_style_tag(content="""
    #HardsellOverlay, .LoginModal { display: none !important; }
    body { overflow: auto !important; position: initial !important; }
""")

Это работает только тогда, когда HTML уже содержит данные под оверлеем. Для полностью серверно закрытых страниц — зарплат, глубоких страниц с отзывами — единственный путь это авторизованная сессия из шага 6.

Советы, чтобы твой парсер Glassdoor продолжал работать

Glassdoor часто обновляет фронтенд. Вот как сделать парсер более устойчивым.

Предпочитай атрибуты data-test, а не CSS-классы

Glassdoor рандомизирует CSS-классы, но data-test обычно остаются стабильными. Всегда лучше использовать [data-test="jobListing"], чем .jobCard_abc123. Если data-test недоступен (как в случае полей зарплаты), используй поиск по префиксу: [class*="SalaryItem_jobTitle__"].

Ротуйте прокси и добавляй случайные паузы

Используй rotating residential proxies — datacenter IP блокируются почти сразу. Добавляй случайные задержки 3–8 секунд между загрузками страниц (5–15 секунд для длинных прогонов). По возможности не скрапь в рабочие часы США, когда поведенческая детекция Cloudflare работает агрессивнее всего.

Отслеживай поломки

Добавь в парсер простую проверку: если страница, на которой данные точно есть, возвращает ноль записей, считай это ошибкой селектора, а не пустым результатом, и сразу оповещай себя. Раз в неделю запускай небольшой тестовый сбор, чтобы ловить поломки заранее — Glassdoor выкатывает изменения фронтенда без предупреждения.

Используй быстрый путь через __NEXT_DATA__, когда это возможно

Glassdoor — это приложение на Next.js + Apollo GraphQL. Многие страницы отдают <script id="__NEXT_DATA__">, внутри которого весь GraphQL cache лежит в JSON. Парсить это намного надёжнее, чем DOM, и это полностью обходит Hardsell overlay:

import json

def extract_next_data(html):
    sel = Selector(text=html)
    raw = sel.css("script#__NEXT_DATA__::text").get()
    if raw:
        return json.loads(raw)["props"]["pageProps"].get("apolloCache", {})
    return None

Такой подход возвращает структурированный Apollo cache со всеми полями вакансий, отзывов и зарплат — без CSS-селекторов. Это самый устойчивый способ извлечения данных, потому что ты работаешь с тем же источником, который использует React-фронтенд Glassdoor.

Обойдём код: собираем данные Glassdoor через Thunderbit (без Python)

Не все, кто читает этот материал, — разработчики. HR-командам, рекрутерам, sales ops-аналитикам и исследователям рынка Glassdoor тоже нужен — и им не стоит управлять Playwright-контекстами и ротацией прокси ради этого.

Thunderbit — это AI Web Scraper расширение для Chrome, которое может извлекать те же вакансии, отзывы и данные о зарплатах без единой строки кода. Я работаю в команде Thunderbit, поэтому скажу об этом прямо — но причина, по которой я включаю его сюда, в том, что он действительно решает две самые сложные проблемы скрапинга Glassdoor.

Как работает Thunderbit на Glassdoor

Процесс занимает два клика:

  1. Открой любую страницу Glassdoor в Chrome (поиск вакансий, отзывы о компании, страница зарплат)
  2. Нажми AI Suggest Fields в боковой панели Thunderbit — AI прочитает DOM страницы и предложит колонки (название вакансии, компания, рейтинг, диапазон зарплаты, плюсы, минусы и т. д.)
  3. Нажми Scrape — данные извлекаются в таблицу без CSS-селекторов и кода для автоматизации браузера

У Thunderbit есть готовый шаблон парсера компаний Glassdoor, который извлекает более 23 полей по компании за один запуск. Для вакансий, отзывов или зарплат универсальный сценарий AI Suggest Fields подходит под любой URL Glassdoor.

Как пройти логин-стену без кода

Именно здесь у Thunderbit появляется структурное преимущество для Glassdoor. Browser Mode работает внутри твоей собственной Chrome-сессии — если ты уже вошёл в Glassdoor в Chrome, Thunderbit автоматически использует те же cookies. Логин-стена на зарплатах и отзывах, которая блокирует серверные скрапер-скрипты, просто не мешает. Никакого управления cookies, никаких persistent contexts, никакого кода для сессий.

Скрапинг подстраниц для обогащения данных

Начни со списка (например, 30 компаний из поиска), пусть Thunderbit перечислит строки, затем включи scraping подстраниц, чтобы заходить на страницу отзывов или зарплат каждой компании и дополнять таблицу полными описаниями, текстом отзывов или данными о зарплатах.

Экспорт в бизнес-инструменты

В отличие от Python-скриптов, которые обычно сохраняют данные в CSV или JSON, Thunderbit экспортирует напрямую в Google Sheets, Airtable, Notion или Excel — и это бесплатно на любом тарифе. Это особенно удобно для команд, которым важно совместно делиться и анализировать данные.

Python или Thunderbit: когда что использовать

СценарийРекомендуемый подход
Построение регулярного потока данныхPython + Patchright
Разовая аналитика или небольшой проект командыThunderbit
Нужен программный контроль над каждым полемPython
Неразработчик, которому Glassdoor нужен уже сегодняThunderbit
Сбор 1000+ страниц за один запускPython + прокси
Сбор 30 компаний с обогащением данныхПодойдут оба варианта — Thunderbit быстрее на старте

Стоимость Thunderbit начинается с бесплатного тарифа (6 страниц в месяц), а тариф Pro стоит $38/месяц и даёт 3 000 кредитов. При расходе 1 кредит на строку результата (2 кредита для scraping подстраниц) этого хватает примерно на 33 запуска по 30 обогащённых компаний в месяц.

Попробовать Thunderbit для сбора данных Glassdoor

Законно ли собирать данные Glassdoor?

Скажу коротко и по фактам. Условия использования Glassdoor прямо запрещают автоматизированный сбор данных: "You may not use any robot, spider, scraper... to access the Services for any purpose without our express written permission."

Но юридическая картина сложнее, чем одна строка в ToS:

  • Meta v. Bright Data (N.D. Cal., январь 2024): суд решил, что если ты никогда не входил в систему, то не соглашался с ToS, а публичный сбор данных без входа не нарушает их
  • hiQ Labs v. LinkedIn (9-й округ): CFAA не применяется к автоматическому сбору общедоступных данных — но фейковые аккаунты и сбор данных в авторизованной сессии — это уже другое дело
  • Van Buren v. United States (Верховный суд, 2021): сузил трактовку "exceeds authorized access" в рамках CFAA

Практический вывод: сбор публичных вакансий без входа в систему находится в сравнительно более безопасной правовой зоне. А вот скрапинг через вошедшую в систему сессию означает, что ты принял ToS при регистрации, и там автоматизированный сбор прямо запрещён. Это одинаково относится и к Python-скриптам, и к Browser Mode Thunderbit.

Этические рекомендации, которых стоит придерживаться в любом случае:

  • Ограничивай частоту запросов значительно ниже человеческой скорости
  • Не собирай и не перепродавай персонально идентифицируемые данные авторов отзывов
  • Уважай правила robots.txt
  • Забирай только те поля, которые действительно нужны

Итог: какой способ подходит именно тебе?

В этом руководстве мы разобрали все три типа данных Glassdoor — вакансии, отзывы и зарплаты — и использовали рабочий код 2025 года, который учитывает миграцию на Indeed Login, Cloudflare Bot Management и ротацию CSS-module классов, сломавшую все старые туториалы.

Вот как выбрать подход:

Ваша ситуацияЛучший путь
Разработчик, строящий data pipelinePython + Patchright (следуй пошаговому гайду выше)
Разовая аналитика или регулярные небольшие выгрузкиThunderbit (без кода, через браузер)
Нужны только базовые вакансии в небольшом объёмеСначала проверь, доступен ли вообще Glassdoor API (скорее всего, нет)
Нужны именно данные по зарплатам или отзывамПридётся использовать Python-скрапинг или Thunderbit — API этого никогда не покрывал
Команда без разработчиков, которой нужны общие данныеThunderbit → экспорт в Google Sheets

Защита Glassdoor будет и дальше меняться. Селекторы будут ломаться. Появятся новые проверки. Сохрани это руководство в закладки — а если хочешь глубже разобраться в инструментах и техниках веб-скрапинга, посмотри наши материалы про лучшие инструменты для автоматического веб-скрапинга, как собрать данные с сайта на Python и лучшие инструменты для сбора вакансий. Также можно посмотреть разборы на Thunderbit YouTube Channel.

Попробуй Thunderbit для извлечения данных Glassdoor Get Started Free

FAQ

1. Можно ли собирать данные Glassdoor без входа в систему?

Да, для большинства данных по вакансиям и верхнеуровневых рейтингов компаний. Нет, если нужны полные разбивки зарплат или полный текст отзывов дальше первых нескольких страниц. #HardsellOverlay — это модальное окно только на CSS; базовый HTML всё ещё содержит данные первой страницы, но более глубокий контент закрыт серверной "give-to-get" стеной Glassdoor.

2. Какая Python-библиотека лучше всего подходит для Glassdoor в 2025 году?

Patchright (stealth-форк Playwright) — базовая рекомендация. Он исправляет утечку Runtime.Enable в CDP, которая есть в обычном Playwright и которую Cloudflare явно проверяет. Для страниц со списками, где в исходном HTML уже есть __NEXT_DATA__, curl_cffi с impersonate="chrome124" работает в 10–20 раз быстрее, но не справится со страницами, закрытыми логином.

3. Как не попасть под блокировку при сборе данных Glassdoor?

Используй Patchright или rebrowser-playwright, а не обычный Playwright и не Selenium. Ротуйте residential-прокси — datacenter IP блокируются почти сразу. Добавляй случайные паузы 3–8 секунд между страницами. Сохраняй cookies (gdId, cf_clearance, GSESSIONID) между запросами. Ожидай, что через 20–30 минут сессию придётся подтверждать заново.

4. Есть ли у Glassdoor API, который можно использовать вместо скрапинга?

Практически нет. Старый Partner API закрыт для новых заявок, публичного endpoint’а для отзывов никогда не было, и через Indeed Publisher API нет пути миграции. Для отзывов и зарплат реально остаются только скрапинг или no-code-инструмент вроде Thunderbit.

5. Как часто ломаются парсеры Glassdoor?

Часто. Glassdoor выкатывает изменения фронтенда без предупреждения, а хэши CSS-module классов меняются при каждом билде. Самые устойчивые стратегии извлечения данных: (1) селекторы по data-test, (2) JSON-блок __NEXT_DATA__, (3) внутренний BFF-endpoint для отзывов. Добавляй проверку на нулевой результат и запускай небольшой тестовый сбор каждую неделю, чтобы ловить поломки как можно раньше.

Узнать больше

Ke
Ke
Технический директор в Thunderbit | Senior Data Scientist и эксперт по ML Имея почти десятилетний опыт в машинном обучении и data science, Кэ Шэнь — выпускник Колумбийского университета и бывший Senior Data Scientist в Walmart Labs. Обладая глубокой, признанной коллегами экспертизой в Python, R, Java и статистике, он делится проверенными на практике наблюдениями о том, как переводить сложные AI-алгоритмы из теории в production-grade архитектуру.
Содержание

Собирай страницу, просто задав вопрос

Скажи, что тебе нужно, простыми словами. А ещё лучше — ничего не говори.

Попробовать Thunderbit бесплатно
Извлекай данные с помощью ИИ
Легко передавай данные в Google Sheets, Airtable или Notion
Chrome Store Rating
PRODUCT HUNT#1 Product of the Week