Glassdoor, одна из крупнейших платформ для поиска работы и исследования компаний в открытом интернете. Публичные страницы листингов на ней содержат много структурированной информации: должности, нанимающие компании, местонахождение вакансий и звёздные рейтинги, которые сотрудники дают этим компаниям. Рекрутеры используют их для бенчмаркинга спроса, аналитики изучают тренды найма в отраслях, а соискатели сравнивают открытые вакансии и рейтинги работодателей. Всё это находится на публичной странице результатов поиска в предсказуемом формате.
В этом руководстве показано, как парсить Glassdoor с помощью JavaScript и Node.js, используя Cheerio. Вы создадите небольшой рабочий скрипт, который получает публичную страницу поиска вакансий Glassdoor через Crawling API, парсит должность, компанию, местоположение, рейтинг компании, оценку зарплаты и ссылку для каждого объявления, обрабатывает пагинацию и экспортирует результат в JSON и CSV. Всё руководство ограничено публичными данными о вакансиях и компаниях, а раздел о легальности в конце, не шаблонный текст, поэтому прочитайте его, прежде чем направить это на реальный объём.
Что вы создадите
Node.js-скрипт, который принимает публичный URL поиска вакансий Glassdoor, получает отрисованный HTML через Crawling API и извлекает структурированную запись для каждой карточки вакансии на странице результатов. В качестве сквозного примера используем поиск вакансий разработчика и извлекаем следующие поля для каждого объявления:
- Title должность, указанная на карточке, например «React Native Developer».
- Company название нанимающего работодателя.
- Rating публичный звёздный рейтинг компании, если Glassdoor его показывает для данного работодателя.
- Location город и регион, где находится вакансия.
- Salary предполагаемый диапазон зарплаты, если он присутствует на карточке.
- Post date как давно появилось объявление, например «30d+».
- Link URL на отдельное объявление о вакансии.
Почему обычный запрос не работает на Glassdoor
Если запросить URL поиска Glassdoor с помощью обычного HTTP-клиента, карточки вакансий вряд ли вернутся. Против вас работают два фактора. Во-первых, Glassdoor отрисовывает список результатов в браузере с помощью JavaScript, поэтому исходный HTML, почти пустая оболочка до выполнения скриптов страницы. Во-вторых, Glassdoor агрессивно обнаруживает автоматизированный трафик: IP дата-центров и паттерны запросов, не похожие на реальный браузер, получают задание CAPTCHA, ограничение скорости или блокировку ещё до отрисованных листингов.
Поэтому рабочий парсер Glassdoor должен объединять в одном запросе две вещи: браузер, который действительно отрисовывает страницу, и IP, воспринимаемый платформой как реальный посетитель. Можно собрать такой стек самостоятельно с помощью headless-браузера и пула ротирующих резидентных прокси, но склеивать их вместе и поддерживать в рабочем состоянии, это большая часть работы. Crawling API объединяет оба компонента в одном вызове: вы отправляете URL, API отрисовывает страницу за доверенным IP и возвращает готовый HTML для парсинга с помощью Cheerio.
Crawling API предоставляет два токена: обычный и JavaScript. Glassdoor требует отрисовки страницы в реальном браузере, поэтому для каждого запроса в этом руководстве используйте JavaScript-токен. Обычный токен возвращает неотрисованную оболочку, и ваши селекторы будут возвращать пустые значения.
Требования
Перед написанием кода необходимо подготовить несколько вещей. Это займёт немного времени.
Базовые знания JavaScript и Node.js. Вы должны уметь писать и запускать Node-скрипты, а также устанавливать пакеты через npm. Если вы новичок в Node, официальная документация и любой вводный курс охватывают уровень, предполагаемый данным руководством. Для более полного руководства наша статья о создании веб-парсера с Node.js охватывает основы.
Node.js 16 или новее. Проверьте версию командой node --version. Если Node.js не установлен, установите его с сайта Node.js или через менеджер версий, например nvm.
Аккаунт Crawlbase и токен. Зарегистрируйтесь, откройте дашборд и скопируйте свой JavaScript-токен со страницы документации аккаунта. Бесплатный тариф даёт до 5 000 запросов без привязки карты, и вы платите только за успешные запросы. Относитесь к токену как к паролю: он аутентифицирует ваши запросы, поэтому не храните его в системе контроля версий.
Настройка проекта
Создайте папку проекта, инициализируйте её и установите две библиотеки, необходимые парсеру.
node --version mkdir glassdoor-scraper && cd glassdoor-scraper npm init -y npm install crawlbase cheerio
Две зависимости выполняют работу: crawlbase, официальный Node-клиент для Crawling API, а cheerio парсит возвращённый HTML с jQuery-подобным API, позволяя извлекать отдельные поля по CSS-селектору. Создайте в этой папке файл scraper.js и добавьте код из следующих шагов.
Шаг 1: получение отрисованной страницы поиска
Начните с получения готовой страницы. Импортируйте класс CrawlingAPI, инициализируйте его с помощью JavaScript-токена и запросите публичный URL поиска Glassdoor. Проверка кода статуса перед парсингом позволяет обнаруживать ошибки явно, а не молча.
const { CrawlingAPI } = require('crawlbase'); const api = new CrawlingAPI({ token: 'YOUR_CRAWLBASE_TOKEN' }); const glassdoorPageURL = 'https://www.glassdoor.com/Job/new-york-ny-react-native-developer-jobs-SRCH_IL.0,11_IC1132348_KO12,34.htm'; api .get(glassdoorPageURL) .then((response) => { if (response.statusCode === 200) { console.log(response.body.slice(0, 500)); } }) .catch((error) => console.error('API request error:', error));
Запустите скрипт командой node scraper.js и вы должны увидеть реальную разметку вакансий Glassdoor в начале тела ответа, а не усечённую оболочку. Это подтверждает работоспособность отрисовки, прежде чем вы напишете хоть один селектор. Crawling API использует предоставленный JavaScript-токен для отрисовки страницы в реальном браузере, поэтому карточки вакансий присутствуют в возвращаемом HTML.
Этот первый запрос только что вернул полностью отрисованную страницу поиска Glassdoor без headless-браузера или прокси на вашей стороне. Crawling API запускает страницу в реальном браузере, ротирует резидентные IP на стороне сервера и обрабатывает CAPTCHA, которые Glassdoor бросает парсерам, возвращая вам готовый HTML из одного вызова. Начните с публичного поиска вакансий на бесплатном тарифе, затем добавьте свой парсер.
Шаг 2: парсинг каждой карточки вакансии с помощью Cheerio
Получив отрисованный HTML, загрузите его в Cheerio и пройдитесь по карточкам вакансий. Glassdoor размещает результаты внутри контейнера «Jobs List», с каждым объявлением в своей карточке. Выберите каждую карточку, затем считайте должность, компанию, рейтинг, местоположение, зарплату, дату публикации и ссылку из её содержимого. Защитное считывание каждого поля не позволяет одному отсутствующему значению прервать процесс.
const cheerio = require('cheerio'); function parseDataFromHTML(html) { const $ = cheerio.load(html); const searchResults = { resultInfo: '', jobs: [], }; // Result summary (for example "1,200 React Native Developer Jobs") searchResults.resultInfo = $('.SearchResultsHeader_jobCount__12dWB') .text() .trim(); // One record per job card $('ul[aria-label="Jobs List"] .jobCard').each((_, element) => { const card = $(element); const title = card.find('.JobCard_seoLink__WdqHZ').text().trim(); const company = card .find('.EmployerProfile_employerName__Xemli') .text() .trim(); const rating = card .find('.EmployerProfile_ratingContainer__N4hxE') .text() .trim(); const location = card.find('.JobCard_location__N_iYE').text().trim(); const postDate = card .find('.JobCard_listingAge__KuaxZ') .text() .trim(); const salary = card .find('.JobCard_salaryEstimate___m9kY') .text() .trim(); let link = card.find('.JobCard_seoLink__WdqHZ').attr('href'); if (link && link.startsWith('/')) { link = new URL(link, 'https://www.glassdoor.com').href; } if (title) { searchResults.jobs.push({ title, company, rating: rating || 'Rating not available', location, salary, postDate, link: link || '', }); } }); return searchResults; }
Несколько деталей обеспечивают точность работы. Сводка результатов приходит из .SearchResultsHeader_jobCount__12dWB, каждое объявление находится в .jobCard внутри контейнера ul[aria-label="Jobs List"]. Внутри карточки должность и её ссылка берутся из якоря .JobCard_seoLink__WdqHZ, компания из .EmployerProfile_employerName__Xemli, публичный рейтинг компании из .EmployerProfile_ratingContainer__N4hxE, местоположение из .JobCard_location__N_iYE, дата публикации из .JobCard_listingAge__KuaxZ, а оценка зарплаты из .JobCard_salaryEstimate___m9kY. Ссылка считывается из атрибута href якоря и преобразуется в абсолютный URL, чтобы она работала вне контекста страницы.
Имена классов Glassdoor (суффиксы JobCard_* и EmployerProfile_* выше) генерируются и меняются без предупреждения. Относитесь к селекторам как к начальному шаблону, а не к контракту. Если поле возвращается пустым, проверьте живую страницу в инструментах разработчика браузера и обновите селектор. Периодическое обслуживание селекторов, это норма для любого производственного парсера, а не признак неисправности.
Шаг 3: сборка полного скрипта с экспортом в JSON и CSV
Теперь соедините получение и парсинг в один запускаемый скрипт, затем запишите записи на диск в виде JSON и CSV. Оригинальное руководство использовало Express-эндпоинт для запуска обхода, но простой скрипт сокращает движущихся частей; позднее можно обернуть в эндпоинт при желании.
const fs = require('fs'); const { CrawlingAPI } = require('crawlbase'); const cheerio = require('cheerio'); const api = new CrawlingAPI({ token: 'YOUR_CRAWLBASE_TOKEN' }); async function crawl(pageUrl) { const response = await api.get(pageUrl); if (response.statusCode === 200) return response.body; console.error(`Request failed: ${response.statusCode}`); return null; } function toCsv(rows) { const headers = [ 'title', 'company', 'rating', 'location', 'salary', 'postDate', 'link', ]; const escape = (value) => `"${String(value).replace(/"/g, '""')}"`; const lines = [headers.join(',')]; for (const row of rows) { lines.push(headers.map((h) => escape(row[h])).join(',')); } return lines.join('\n'); } async function main() { const url = 'https://www.glassdoor.com/Job/new-york-ny-react-native-developer-jobs-SRCH_IL.0,11_IC1132348_KO12,34.htm'; const html = await crawl(url); if (!html) return; const data = parseDataFromHTML(html); fs.writeFileSync('glassdoor.json', JSON.stringify(data, null, 2)); fs.writeFileSync('glassdoor.csv', toCsv(data.jobs)); console.log(`Saved ${data.jobs.length} jobs to JSON and CSV`); } main();
Вставьте функцию parseDataFromHTML из шага 2 в тот же файл, чтобы main могла её вызвать. Запустите командой node scraper.js и получите два файла: glassdoor.json с полными структурированными записями и glassdoor.csv, готовый для открытия в таблице. Вспомогательная функция toCsv заключает каждое поле в кавычки и удваивает встроенные кавычки, что важно, поскольку должности и местоположения часто содержат запятые.
Как выглядят результаты
JSON-файл содержит сводку результатов плюс один объект на вакансию с должностью, компанией, публичным рейтингом, местоположением, оценкой зарплаты, датой публикации и ссылкой.
{ "resultInfo": "React Native Developer Jobs in New York, NY", "jobs": [ { "title": "React Native Developer", "company": "Example Tech Inc", "rating": "4.1", "location": "New York, NY", "salary": "$110K - $140K (Employer est.)", "postDate": "30d+", "link": "https://www.glassdoor.com/job-listing/react-native-developer" }, { "title": "Senior Mobile Engineer", "company": "Acme Software", "rating": "3.8", "location": "Remote", "salary": "$130K - $160K (Glassdoor est.)", "postDate": "5d", "link": "https://www.glassdoor.com/job-listing/senior-mobile-engineer" } ] }
CSV отражает те же строки вакансий с заголовочной строкой, поэтому файл сразу открывается в Excel, Google Sheets или любом конвейере данных, который читает файлы с разделителями.
title,company,rating,location,salary,postDate,link "React Native Developer","Example Tech Inc","4.1","New York, NY","$110K - $140K (Employer est.)","30d+","https://www.glassdoor.com/job-listing/react-native-developer" "Senior Mobile Engineer","Acme Software","3.8","Remote","$130K - $160K (Glassdoor est.)","5d","https://www.glassdoor.com/job-listing/senior-mobile-engineer"
Обработка пагинации
Одна страница поиска, это демонстрация; реальная задача охватывает каждую страницу результатов. Glassdoor разбивает URL поиска на страницы, добавляя сегмент страницы, поэтому можно зациклиться по номерам страниц, получать каждую через Crawling API, парсить той же функцией и останавливаться, когда страница не вернёт карточек. Поскольку все страницы результатов имеют одинаковую структуру карточек, уже написанный парсер работает со всеми ними без изменений.
async function scrapeAllPages(baseUrl, maxPages) { const allJobs = []; for (let page = 1; page <= maxPages; page++) { // Glassdoor adds the page number before the .htm extension const pageUrl = baseUrl.replace('.htm', `_IP${page}.htm`); const html = await crawl(pageUrl); if (!html) break; const { jobs } = parseDataFromHTML(html); if (jobs.length === 0) break; // no more results allJobs.push(...jobs); console.log(`Page ${page}: ${jobs.length} jobs`); // Pace requests so you stay under the rate limit await new Promise((r) => setTimeout(r, 2000)); } return allJobs; }
Точный токен пагинации в URL может меняться, поэтому проверьте несколько реальных ссылок «следующая страница» в браузере и сопоставьте паттерн. Важные привычки применимы к любому ресурсу: зацикливайтесь до исчерпания результатов и добавляйте короткую задержку между запросами, чтобы не перегружать сайт. Подробнее об отрисованных страницах с большим количеством JavaScript, подобных этой, читайте в нашей статье как обходить JavaScript-сайты.
Как оставаться незаблокированным
Даже при обработке отрисовки Glassdoor отслеживает трафик, характерный для парсеров. Несколько привычек помогают поддерживать работоспособность парсера и применимы к любому жёсткому коммерческому ресурсу.
- Задавайте темп запросов. Добавляйте задержку между запросами страниц, а не нагружайте поиск в плотном цикле. Распределение запросов, главный фактор в удержании под ограничениями частоты Glassdoor.
- Опирайтесь на ротацию. Пул резидентных IP распределяет запросы по множеству реальных пользовательских адресов, чтобы ни один из них не активировал ограничение или CAPTCHA. Crawling API берёт это на себя; если вы создаёте собственный стек, именно это место стоит сделать правильно.
- Читайте коды статусов. Запуск, при котором начинают возвращаться задания или ответы не с кодом 200, сигнализирует о том, что текущая частота или уровень IP уже недостаточны. Относитесь к этому как к сигналу снизить нагрузку, а не как к шуму, который нужно игнорировать.
Более широкий план описан в статье как парсить сайты без блокировок. Если вам нужны аналогичные данные о вакансиях с другой платформы, тот же паттерн получение-парсинг напрямую переносится на парсинг вакансий Indeed и парсинг вакансий Monster с Python.
Законно ли парсить Glassdoor?
Допустимость парсинга Glassdoor зависит от условий использования Glassdoor, вашей юрисдикции и того, что вы делаете с данными. Условия Glassdoor ограничивают автоматизированный доступ, поэтому парсинг может нарушать эти условия независимо от тщательности вашего подхода. Ни один из приведённых здесь кодов этого не меняет, он лишь обеспечивает техническую работоспособность. Ознакомьтесь с Условиями использования Glassdoor и его robots.txt, соблюдайте заявленные ожидания по частоте запросов и относитесь к обоим как к границам того, что можно собирать.
Это руководство намеренно ограничено публичными данными о вакансиях и компаниях: должностью, нанимающей компанией, местоположением, оценкой зарплаты, датой публикации, ссылкой и публичным звёздным рейтингом компании, которые любой пользователь может видеть на странице поиска без авторизации. Это отличается от персональных данных на платформе. Индивидуальные отзывы сотрудников, отчёты об интервью и люди, их написавшие, являются персональными данными. Относитесь к рейтингам компаний как к агрегированному сигналу о работодателе, никогда не составляйте профили отдельных рецензентов и не публикуйте отзыв человека, связанный с его личностью. Всё, что находится за авторизационной стеной, собирается в масштабе или относится к идентифицируемым лицам, подпадает под законодательство о конфиденциальности, например GDPR и CCPA, что выходит за рамки данного руководства.
Если ваш проект требует больше, чем публичные листинги, правильный путь, санкционированный, а не более умный парсер. Glassdoor и её материнская компания располагают официальными партнёрскими программами и API, предоставляющими данные работодателей и листингов с чёткими условиями использования, правилами атрибуции и коммерческими правами. Это правильные инструменты, когда вам нужны большие объёмы, гарантированная структура или право на коммерческое использование данных. В случае сомнений в допустимости использования, получите разрешение или соглашение о данных, а не считайте, что молчание означает согласие.
Ключевые выводы
- Glassdoor отрисовывает листинги на стороне клиента и жёстко блокирует. Обычный запрос возвращает пустую оболочку или CAPTCHA, поэтому необходимо отрисовать страницу за доверенным IP с JavaScript-токеном перед парсингом.
- Crawling API делает оба в одном вызове. Он отрисовывает страницу в реальном браузере, ротирует резидентные IP и обрабатывает CAPTCHA, возвращая готовый HTML для парсинга с помощью Cheerio.
-
Cheerio извлекает поля. Выберите каждый
.jobCardв Jobs List, затем считайте должность, компанию, рейтинг, местоположение, зарплату, дату публикации и ссылку, учитывая возможное изменение генерируемых имён классов. - Применяйте пагинацию и экспортируйте. Зацикливайтесь по сегментам страниц Glassdoor до исчерпания результатов, задавайте темп запросов и записывайте структурированные записи в JSON и CSV.
- Оставайтесь в рамках публичных данных. Собирайте только публичные данные о вакансиях и компаниях, относитесь к индивидуальным отзывам и рецензентам как к персональным данным, соблюдайте Условия использования и robots.txt и предпочитайте официальный API Glassdoor или партнёрскую программу для объёмного или коммерческого использования.
Часто задаваемые вопросы
Могу ли я создать парсер Glassdoor на языке, отличном от JavaScript?
Да. В этом руководстве используется JavaScript с Cheerio, но тот же подход работает на любом языке. Crawling API имеет библиотеки и SDK для нескольких языков, поэтому отрисованный HTML получается одним способом и парсится любым HTML-парсером, предпочтительным для вашего стека, например BeautifulSoup на Python. Селекторы и поля остаются теми же; меняется только синтаксис парсинга.
Почему обычный запрос возвращает неполные данные с Glassdoor?
Потому что Glassdoor отрисовывает список вакансий на стороне клиента с помощью JavaScript и реагирует на автоматизированный трафик CAPTCHA. Прямой HTTP-запрос с IP дата-центра обычно возвращает пустую оболочку или страницу блокировки, а не карточки вакансий. Чтобы получить полную страницу, необходимо отрисовать её за доверенным IP, именно это обеспечивает Crawling API при использовании JavaScript-токена.
Мои селекторы возвращают пустые значения. Что изменилось?
Почти наверняка разметка Glassdoor. Его генерируемые имена классов, например JobCard_seoLink__WdqHZ, меняются без предупреждения, поэтому селекторы, работавшие в прошлом месяце, могут перестать работать. Проверьте живую страницу в инструментах разработчика браузера, обновите селекторы в parseDataFromHTML и всё снова заработает. Периодическое обслуживание селекторов, это норма для любого производственного парсера.
Буду ли я заблокирован при парсинге Glassdoor?
Это возможно, если отправлять слишком много запросов слишком быстро с одного адреса. Crawling API снижает этот риск, ротируя через резидентные IP и обрабатывая CAPTCHA, но вам всё равно следует задавать темп запросов, добавлять задержки между страницами и следить за кодами статусов, чтобы снизить нагрузку при появлении заданий. Эти привычки важны для любого жёсткого коммерческого ресурса.
Можно ли парсить индивидуальные отзывы сотрудников и имена рецензентов?
Это выходит за рамки данного руководства, и на то есть веские причины. Индивидуальные отзывы и люди, их написавшие, являются персональными данными, что подпадает под законодательство о конфиденциальности, например GDPR и CCPA. Используйте публичный рейтинг компании как агрегированный сигнал о работодателе, не составляйте профили отдельных рецензентов и не публикуйте отзыв человека, связанный с его личностью. Для данных, помимо публичных листингов, используйте официальный API Glassdoor или партнёрскую программу.
Есть ли у Glassdoor официальный API?
Glassdoor и её материнская компания располагают официальными партнёрскими программами и API, предоставляющими данные работодателей и листингов на чётких условиях с правилами атрибуции и определёнными коммерческими правами. Если вам нужны большие объёмы, гарантированная структура или право на коммерческое использование данных, этот санкционированный путь является правильным. Данный парсер публичных данных лучше подходит для исследований, прототипирования и небольшого анализа, где официальное соглашение нецелесообразно.
Обходите любой сайт в масштабе, без борьбы с инфраструктурой.
Crawlbase берёт на себя прокси, отпечатки и CAPTCHA, чтобы ваша команда выпускала конвейеры данных вместо поддержки обвязки краулинга. 1 000 запросов бесплатно, без карты.

