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

В этом руководстве показано, как парсить данные о фильмах IMDb с помощью JavaScript и Node.js с использованием Cheerio. Вы создадите небольшой работающий парсер, который получает публичную страницу названия IMDb через Crawling API, извлекает название фильма, год, рейтинг IMDb, жанр, продолжительность и режиссёра, а затем экспортирует результат в JSON и CSV. Весь разбор ограничен публичными фактическими метаданными фильмов, а раздел о легальности в конце не является формальностью, поэтому прочитайте его перед запуском на реальных объёмах.

Что вы создадите

Node.js-скрипт, который принимает публичный URL названия IMDb, получает отрендеренный HTML через Crawling API и извлекает структурированную запись для этого фильма. В качестве примера используем The Shawshank Redemption и извлекаем следующие фактические поля для каждого названия:

  • Title основное название фильма, отображаемое в герое страницы, например "The Shawshank Redemption".
  • Year год выпуска, указанный рядом с названием.
  • Rating агрегированный пользовательский рейтинг IMDb из 10.
  • Genre жанровые теги, присвоенные IMDb этому названию, например "Drama".
  • Runtime указанная продолжительность фильма.
  • Director указанный режиссёр фильма.

Почему обычный запрос не работает на IMDb

Если отправить запрос к URL названия IMDb с помощью обычного HTTP-клиента, вы редко получите ожидаемые метаданные. Этому мешают два фактора. Во-первых, IMDb рендерит большую часть страницы названия в браузере с помощью JavaScript: исходный HTML является тонкой оболочкой до тех пор, пока скрипты страницы не запустятся и не заполнят рейтинг, кредиты и строки с деталями. Во-вторых, IMDb отслеживает автоматизированный трафик: IP-адреса дата-центров и паттерны запросов, непохожие на реальный браузер, подвергаются ограничению скорости или проверке ещё до получения отрендеренной страницы.

Поэтому рабочий парсер IMDb должен решать две задачи в одном запросе: браузер, который реально рендерит страницу, и IP-адрес, который платформа воспринимает как настоящего посетителя. Можно собрать такое решение самостоятельно из headless-браузера и пула ротирующихся резидентных прокси, но поддержание их в рабочем состоянии занимает большую часть времени. Crawling API объединяет оба компонента в одном вызове: вы передаёте URL, API рендерит страницу за доверенным IP и возвращает готовый HTML для парсинга с Cheerio.

Используйте JavaScript-токен

Crawling API предоставляет два токена: обычный и JavaScript. IMDb заполняет рейтинг и кредиты в браузере, поэтому используйте свой JavaScript-токен для каждого запроса в этом руководстве. Обычный токен возвращает необработанную оболочку, и ваши селекторы вернутся пустыми.

Предварительные требования

Перед написанием кода необходимо выполнить несколько условий. Это не займёт много времени.

Базовые знания JavaScript и Node.js. Вы должны уметь писать и запускать Node-скрипты, а также устанавливать пакеты через npm. Если вы только начинаете знакомство с Node, официальная документация и любой вводный курс выведут вас на уровень, который предполагает этот туториал. Для более подробного разбора наше руководство по созданию веб-парсера на Node.js охватывает основы.

Node.js 16 или выше. Проверьте версию командой node --version. Если она не установлена, скачайте её с сайта Node.js или через менеджер версий, например nvm.

Аккаунт Crawlbase и токен. Зарегистрируйтесь, откройте панель управления и скопируйте JavaScript-токен со страницы документации аккаунта. Бесплатный тариф даёт 1000 запросов без карты, и вы платите только за успешные запросы. Относитесь к токену как к паролю: он аутентифицирует ваши запросы, поэтому не добавляйте его в систему контроля версий.

Настройка проекта

Создайте папку проекта, инициализируйте её и установите две библиотеки, необходимые парсеру.

bash
node --version

mkdir imdb-scraper && cd imdb-scraper
npm init -y

npm install crawlbase cheerio

Две зависимости выполняют основную работу: crawlbase является официальным Node-клиентом для Crawling API, а cheerio парсит возвращаемый HTML с jQuery-подобным API, позволяя извлекать отдельные поля по CSS-селектору. Создайте файл scraper.js в этой папке и добавьте код из приведённых ниже шагов.

Шаг 1: Получение отрендеренной страницы названия

Начните с получения готовой страницы. Импортируйте класс CrawlingAPI, инициализируйте его JavaScript-токеном и запросите публичный URL названия IMDb. В этом примере используем The Shawshank Redemption по адресу https://www.imdb.com/title/tt0111161/. Проверка кода статуса перед парсингом позволяет выявлять ошибки явно, а не незаметно.

javascript
const { CrawlingAPI } = require('crawlbase');

const api = new CrawlingAPI({ token: 'YOUR_CRAWLBASE_TOKEN' });

const imdbPageURL = 'https://www.imdb.com/title/tt0111161/';

api
  .get(imdbPageURL)
  .then((response) => {
    if (response.statusCode === 200) {
      console.log(response.body.slice(0, 500));
    }
  })
  .catch((error) => console.error('API request error:', error));

Запустите скрипт командой node scraper.js, и вы должны увидеть реальную разметку названия IMDb в начале тела, а не упрощённую оболочку. Это подтверждает работу рендеринга до написания первого селектора. Crawling API использует предоставленный вами JavaScript-токен для рендеринга страницы в реальном браузере, поэтому рейтинг и кредиты присутствуют в возвращаемом HTML.

Crawlbase Crawling API

Этот первый запрос вернул полностью отрендеренную страницу названия IMDb без headless-браузера или прокси на вашей стороне. Crawling API запускает страницу в реальном браузере, ротирует резидентные IP на стороне сервера и обрабатывает проверки, которые IMDb применяет к автоматизированному трафику, возвращая вам готовый HTML из одного вызова. Начните с публичного названия на бесплатном тарифе, затем добавьте парсер.

Шаг 2: Парсинг полей фильма с Cheerio

Получив отрендеренный HTML, загрузите его в Cheerio и считайте каждое поле по его селектору. IMDb разметил большинство нужных вам метаданных стабильными атрибутами data-testid, которые удобнее в качестве целей, чем генерируемые имена классов. Мы извлекаем название и год из героя страницы, рейтинг из блока агрегированного рейтинга, жанр из списка тегов, а продолжительность и режиссёра из строк деталей названия. Защитное считывание каждого поля предотвращает сбой при одном отсутствующем значении.

javascript
const cheerio = require('cheerio');

function parseMovieFromHTML(html) {
  const $ = cheerio.load(html);

  const getText = (selector) => $(selector).first().text().trim();

  // Read every chip in a labelled metadata row, joined into one string
  const getRowItems = (selector) =>
    $(selector)
      .map((_, el) => $(el).text().trim())
      .get()
      .join(', ');

  const title = getText(
    '[data-testid="hero__pageTitle"] .hero__primary-text',
  );

  // The first metadata link under the hero title is the release year
  const year = getText(
    '[data-testid="hero__pageTitle"] + ul li:first-child a',
  );

  const rating = getText(
    '[data-testid="hero-rating-bar__aggregate-rating__score"] span',
  );

  const genre = getRowItems(
    '.ipc-chip-list--baseAlt .ipc-chip__text',
  );

  const runtime = getRowItems(
    '[data-testid="title-techspec_runtime"] .ipc-metadata-list-item__content-container',
  );

  const director = getRowItems(
    'li:contains("Director") a.ipc-metadata-list-item__list-content-item--link:first',
  );

  return { title, year, rating, genre, runtime, director };
}

Несколько деталей обеспечивают точность передачи страницы. Название берётся из элемента героя [data-testid="hero__pageTitle"] .hero__primary-text, а год, из первой ссылки метаданных непосредственно после него. Агрегированный рейтинг IMDb находится в [data-testid="hero-rating-bar__aggregate-rating__score"], теги жанров в списке .ipc-chip-list--baseAlt .ipc-chip__text, а продолжительность в строке детали title-techspec_runtime. Режиссёр считывается из строки кредитов, содержащей метку "Director", принимая первое связанное имя. Объединение элементов строки в одну строку делает вывод плоским и удобным для хранения.

Селекторы меняются

Генерируемые имена классов IMDb (суффиксы ipc-* и хэшированные) изменяются без предупреждения; атрибуты data-testid более стабильны, но не гарантированы. Рассматривайте селекторы как начальный шаблон, а не как неизменный контракт. Когда поле возвращается пустым, заново проинспектируйте живую страницу в инструментах разработчика браузера и обновите селектор. Периодическое обслуживание селекторов нормально для любого рабочего парсера, это не признак неисправности.

Шаг 3: Сборка полного скрипта с экспортом в JSON и CSV

Теперь соедините запрос и парсинг в один работающий скрипт, затем запишите запись на диск в виде JSON и CSV. Простой скрипт минимизирует движущиеся части; позже можно обернуть его в эндпоинт при необходимости.

javascript
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(row) {
  const headers = [
    'title',
    'year',
    'rating',
    'genre',
    'runtime',
    'director',
  ];
  const escape = (value) =>
    `"${String(value).replace(/"/g, '""')}"`;
  const values = headers.map((h) => escape(row[h]));
  return [headers.join(','), values.join(',')].join('\n');
}

async function main() {
  const url = 'https://www.imdb.com/title/tt0111161/';
  const html = await crawl(url);
  if (!html) return;

  const movie = parseMovieFromHTML(html);
  fs.writeFileSync('movie.json', JSON.stringify(movie, null, 2));
  fs.writeFileSync('movie.csv', toCsv(movie));
  console.log(`Saved ${movie.title} to JSON and CSV`);
}

main();

Вставьте функцию parseMovieFromHTML из шага 2 в тот же файл, чтобы main мог её вызвать. Запустите командой node scraper.js и вы получите два файла: movie.json с полной структурированной записью и movie.csv, готовый для открытия в таблице. Вспомогательная функция toCsv заключает каждое поле в кавычки и удваивает любые встроенные кавычки, что важно, поскольку названия и списки жанров часто содержат запятые.

Как выглядят результаты

Файл JSON содержит один объект с названием, годом, рейтингом IMDb, жанром, продолжительностью и режиссёром.

json
{
  "title": "The Shawshank Redemption",
  "year": "1994",
  "rating": "9.3",
  "genre": "Drama",
  "runtime": "2h 22m",
  "director": "Frank Darabont"
}

CSV отражает ту же запись со строкой заголовков, поэтому она сразу открывается в Excel, Google Sheets или любом конвейере данных, читающем файлы с разделителями.

csv
title,year,rating,genre,runtime,director
"The Shawshank Redemption","1994","9.3","Drama","2h 22m","Frank Darabont"

Масштабирование на множество названий

Одна страница названия, это демонстрация; реальная задача собирает метаданные по списку фильмов. Поскольку каждая страница названия IMDb имеет одинаковую структуру героя и строк деталей, уже написанный парсер работает для всех без изменений. Ведите список URL названий, получайте каждый через Crawling API, парсите той же функцией и собирайте записи. Добавляйте небольшую задержку между запросами, чтобы не превысить лимиты IMDb.

javascript
async function scrapeTitles(urls) {
  const movies = [];

  for (const url of urls) {
    const html = await crawl(url);
    if (!html) continue;

    const movie = parseMovieFromHTML(html);
    movies.push(movie);
    console.log(`Parsed ${movie.title || url}`);

    // Pace requests so you stay under the rate limit
    await new Promise((r) => setTimeout(r, 2000));
  }

  return movies;
}

Для большого бэклога названий, которые вы не хотите ждать синхронно, асинхронный Crawler позволяет отправлять URL и собирать результаты без удержания соединения открытым для каждого запроса. Подробнее об отрендеренных страницах с активным JavaScript, подобных этим, читайте в нашем руководстве по краулингу JavaScript-сайтов.

Как оставаться незаблокированным

Даже при наличии рендеринга IMDb отслеживает трафик, похожий на парсер. Несколько привычек позволяют поддерживать запуск в рабочем состоянии, и они применимы к любому крупному публичному сайту.

  • Регулируйте скорость запросов. Вводите задержку между запросами, а не отправляйте их в плотном цикле. Распределение запросов является наиболее значимым фактором для соблюдения лимитов IMDb.
  • Используйте ротацию. Пул резидентных IP распределяет запросы по множеству реальных пользовательских адресов, чтобы ни один не превысил лимит. Crawling API выполняет это за вас; если вы используете собственный стек, это ключевая часть, которую нужно реализовать правильно.
  • Следите за кодами статуса. Запуск, который начинает возвращать проверки или ответы не 200, сигнализирует о том, что текущая скорость или уровень IP больше недостаточны. Воспринимайте это как сигнал для снижения активности, а не как шум, который можно игнорировать.

Подробный сценарий работы описан в руководстве о том, как парсить сайты, не получая блокировок. Если вы хотите похожие метаданные из других источников о развлечениях, тот же паттерн запрос-парсинг напрямую переносится на парсинг Rotten Tomatoes и рейтингов Goodreads.

Законен ли парсинг IMDb?

Допустимость парсинга IMDb зависит от Условий использования IMDb, вашей юрисдикции и того, что вы делаете с данными. Условия IMDb ограничивают автоматизированный доступ и повторное использование контента, поэтому парсинг может противоречить этим условиям независимо от аккуратности используемых инструментов. Ни один из приведённых здесь кодов не меняет этого; он лишь делает техническую часть работоспособной. Прочитайте Условия использования IMDb и его robots.txt, соблюдайте любые заявленные ожидания по скорости, и рассматривайте оба документа как границу того, что вы собираете. Ограниченный сбор публичных фактических полей для личных исследований, это совершенно другое, чем масштабное или коммерческое извлечение, которое IMDb не разрешает без явного согласия.

Это руководство намеренно ограничено публичными фактическими метаданными фильмов: названием, годом выпуска, агрегированным пользовательским рейтингом, жанром, продолжительностью и кредитованным режиссёром, которые любой может видеть на публичной странице названия без входа в систему. Это фактические каталогические данные, а не персональные данные, и это безопасная область для работы. Что не охватывается, это защищённый авторским правом материал на тех же страницах. Описания сюжетов, пользовательские рецензии, редакционные тексты, постеры и кадры, это защищённый контент. Не распространяйте рецензии, описания или изображения оптом, и не публикуйте их повторно, как если бы они были вашими. Ограничивайте использование небольшим набором фактических полей и поддерживайте умеренный объём.

Если вашему проекту нужно больше, чем несколько публичных полей, санкционированный путь является правильным, а не более хитроумный парсер. IMDb публикует официальные лицензируемые наборы данных для некоммерческого использования и осуществляет коммерческое лицензирование данных через IMDb и его материнскую компанию для производственных нужд. Это правильные инструменты, когда вам нужны большие объёмы, гарантированная структура или право на коммерческое повторное использование данных, и они поставляются с чёткими условиями использования и атрибуции. Когда вы не уверены в допустимости использования, заключите соглашение о данных, а не предполагайте, что молчание означает согласие.

Итоги

Ключевые выводы

  • IMDb рендерит метаданные на стороне клиента. Обычный запрос возвращает тонкую оболочку, поэтому необходимо отрендерить страницу за доверенным IP с использованием JavaScript-токена, прежде чем парсить её.
  • Crawling API делает оба в одном вызове. Он рендерит страницу в реальном браузере и ротирует резидентные IP, возвращая готовый HTML, который вы парсите с Cheerio.
  • Cheerio извлекает поля. Целевой элемент героя с названием, блок агрегированного рейтинга, теги жанров, строки деталей продолжительности и режиссёра, предпочитая атрибуты data-testid и ожидая дрейфа генерируемых имён классов.
  • Масштабируйте и экспортируйте. Используйте тот же парсер для списка URL названий, регулируйте скорость запросов и записывайте структурированные записи в JSON и CSV.
  • Оставайтесь в рамках публичных фактических данных. Собирайте только название, год, рейтинг, жанр, продолжительность и режиссёра, никогда не распространяйте рецензии, описания или изображения, соблюдайте Условия использования и robots.txt, и предпочитайте официальный набор данных IMDb или лицензированный фид для объёмного или коммерческого использования.

Часто задаваемые вопросы

Можно ли создать парсер IMDb на другом языке, а не JavaScript?

Да. Это руководство использует JavaScript с Cheerio, но тот же подход работает на любом языке. Crawling API имеет библиотеки и SDK для нескольких языков, поэтому вы получаете отрендеренный HTML тем же способом и парсите его любым HTML-парсером, предпочтительным для вашего стека, например BeautifulSoup в Python. Селекторы и поля остаются теми же; меняется только синтаксис парсинга.

Почему обычный запрос возвращает неполные данные с IMDb?

Потому что IMDb заполняет значительную часть страницы названия в браузере с помощью JavaScript и отслеживает автоматизированный трафик. Необработанный HTTP-запрос с IP дата-центра обычно возвращает тонкую оболочку без рейтинга и кредитов, или страницу с проверкой. Чтобы получить полную страницу, необходимо отрендерить её за доверенным IP, что обеспечивает Crawling API при использовании JavaScript-токена.

Мои селекторы возвращают пустые значения. Что изменилось?

Почти наверняка разметка IMDb. Генерируемые имена классов ipc-* изменяются без предупреждения, поэтому селекторы, работавшие в прошлом месяце, могут перестать работать. Предпочитайте более стабильные атрибуты data-testid там, где они существуют, заново проинспектируйте живую страницу в инструментах разработчика браузера, обновите селекторы в parseMovieFromHTML, и вы снова в деле. Периодическое обслуживание селекторов нормально для любого рабочего парсера.

Есть ли у IMDb официальный API или набор данных?

IMDb не предлагает публичный API общего назначения, но публикует официальные наборы данных для загрузки в целях личного и некоммерческого использования, а также лицензирует данные коммерчески через IMDb и его материнскую компанию. Для производственных нужд, больших объёмов или коммерческого повторного использования лицензированный набор данных или фид является правильным, санкционированным путём. Этот парсер публичных данных лучше всего подходит для исследований, прототипирования и анализа меньшего масштаба, где официальное соглашение не требуется.

Можно ли также парсить рецензии, описания сюжетов и постеры?

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

Буду ли я заблокирован при парсинге IMDb?

Это возможно, если вы отправляете слишком много запросов слишком быстро с одного адреса. Crawling API снижает этот риск, ротируя резидентные IP за вас, но вам всё равно следует регулировать скорость запросов, добавлять задержки между ними и следить за кодами статуса, чтобы снижать активность при появлении проверок. Эти привычки важны на любом крупном публичном сайте.

Начать создавать

Обходите любой сайт в масштабе, без борьбы с инфраструктурой.

Crawlbase берёт на себя прокси, отпечатки и CAPTCHA, чтобы ваша команда выпускала конвейеры данных вместо поддержки обвязки краулинга. 1 000 запросов бесплатно, без карты.

Самообслуживание · Звонок отдела продаж не требуется · Доступны корпоративные объёмы краулинга