Публичный канал YouTube представляет собой компактный набор данных, который лежит на виду. Откройте вкладку «Видео» любого автора и вы увидите для каждого ролика: название, количество просмотров, дату публикации, продолжительность и ссылку на страницу просмотра. Собранные воедино по всему каналу, эти публичные метаданные открывают возможности для анализа контента конкурентов, исследования ритма публикаций и отслеживания трендов, причём без доступа ни к одному приватному аккаунту.

В этом руководстве показано, как построить YouTube channel scraper на JavaScript и Node.js. Вы создаёте небольшой запускаемый скрапер, который получает страницу «Видео» публичного канала через Crawling API с отрисовкой JavaScript, парсит каждую карточку видео с помощью cheerio и экспортирует результаты в JSON или CSV. Всё руководство ограничено публичными, неперсональными данными: списками видео на канале, доступными любому пользователю без входа в систему, но не приватными плейлистами, комментариями или чем-либо, требующим авторизации. Раздел о законодательстве в конце не является формальностью, так что прочитайте его, прежде чем направлять скрапер на реальные объёмы данных.

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

Скрипт Node.js, который принимает URL вкладки «Видео» публичного канала YouTube, получает отрисованный JavaScript HTML через Crawling API и извлекает структурированную запись для каждого видео на этой странице. В качестве рабочего примера используется вкладка «Видео» публичного канала, из которой извлекаются следующие поля:

  • Title название видео, как оно отображается на карточке, например «Official Trailer».
  • Views публичный текст с количеством просмотров, например «56K views».
  • Upload date относительная дата публикации, например «6 days ago».
  • Duration значок продолжительности на миниатюре, например «2:14».
  • Link абсолютный URL на страницу просмотра конкретного видео.

Также считывается немного контекста на уровне канала (название канала и хендл), чтобы каждый экспорт был самоописывающим, после чего список видео записывается в JSON и CSV.

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

Если запросить URL вкладки «Видео» канала обычным HTTP-клиентом, вы получите статус 200 и почти ни одного из нужных данных. YouTube строит сетку видео в браузере: исходный HTML представляет собой тонкую оболочку, а реальная разметка карточек добавляется JavaScript-кодом после того, как скрипты страницы выполнятся и загрузятся данные. Голый fetch захватывает страницу до того, как всё это произойдёт, поэтому cheerio обнаруживает пустую сетку.

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

Зачем отрисовывать страницу

Crawlbase предлагает два типа запросов. Обычный запрос получает статический HTML; JavaScript-запрос сначала отрисовывает страницу в настоящем браузере. YouTube строит сетку видео на стороне клиента, поэтому здесь именно JavaScript-запрос даёт заполненную страницу. Обычный запрос вернёт пустую оболочку, и cheerio не найдёт что парсить. Параметры ajax_wait и page_wait позволяют дождаться окончания загрузки сетки.

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

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

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

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

Аккаунт Crawlbase и токен. Зарегистрируйтесь, откройте панель управления и скопируйте токен для JavaScript-запросов со страницы документации аккаунта. Обращайтесь с токеном как с паролем: он аутентифицирует ваши запросы, поэтому не добавляйте его в систему контроля версий. У новых аккаунтов есть запас бесплатных запросов, и вы платите только за успешные, что вполне достаточно для прохождения этого руководства.

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

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

bash
node --version

mkdir youtube-channel-scraper && cd youtube-channel-scraper
npm init -y

npm install crawlbase cheerio

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

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

Начните с получения готовой страницы. Импортируйте класс CrawlingAPI, инициализируйте его своим токеном и запросите URL вкладки «Видео» канала. Поскольку сетка отрисовывается на стороне клиента, передайте ajax_wait и page_wait, чтобы поздно загружающиеся карточки успели появиться до захвата страницы. Проверка кода статуса перед парсингом делает сбои явными, а не молчаливыми.

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

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

async function crawl(pageUrl) {
  const options = { ajax_wait: 'true', page_wait: 7000 };
  const response = await api.get(pageUrl, options);
  if (response.statusCode === 200) {
    return response.body;
  }
  console.error(`Request failed: ${response.statusCode}`);
  return null;
}

const channelUrl = 'https://www.youtube.com/@Netflix/videos';
crawl(channelUrl).then((html) => {
  console.log(html ? html.slice(0, 500) : 'No HTML returned');
});

Два параметра ожидания важны для клиентской цели вроде этой. ajax_wait указывает API дождаться завершения загрузки асинхронного контента, а page_wait выдерживает фиксированное количество миллисекунд после загрузки, чтобы поздно отрисовываемая сетка видео появилась до захвата страницы. Семь секунд, разумная отправная точка для YouTube; увеличьте это значение, если сетка возвращается пустой. Запустите скрипт командой node scraper.js и вы должны увидеть реальную разметку канала, а не урезанную оболочку. Это подтверждает, что отрисовка работает, ещё до написания единого селектора.

Crawlbase Crawling API

Для сетки YouTube нужна отрисованная страница за надёжным IP-адресом, и всё это в одном вызове. Crawling API принимает ваш токен, запускает страницу в настоящем браузере, выжидает окно ajax_wait и page_wait, которое вы только что задали, ротирует резидентные IP-адреса на стороне сервера и отдаёт готовый HTML, избавляя вас от необходимости самостоятельно запускать флот headless-браузеров и пул прокси. Начните с публичного канала на бесплатном уровне.

Шаг 2: парсинг каждого видео с помощью cheerio

Имея отрисованный HTML, загрузите его в cheerio и пройдитесь по карточкам видео. Отрисованная вкладка «Видео» размещает каждую загрузку в повторяющемся grid renderer, поэтому вы выбираете каждую карточку, затем считываете из неё название, просмотры, дату загрузки, продолжительность и ссылку для просмотра. Защитное считывание каждого поля предотвращает сбой всего прогона из-за одного отсутствующего значения, а относительный URL на анкоре заголовка необходимо преобразовать в абсолютный.

javascript
const cheerio = require('cheerio');

function parseChannel(html) {
  const $ = cheerio.load(html);
  const channel = {
    title: $('#inner-header-container .ytd-channel-name .ytd-channel-name:first').text().trim(),
    channelHandle: $('.meta-item #channel-handle').text().trim(),
    videos: [],
  };

  $('#contents ytd-rich-item-renderer').each((_, el) => {
    const card = $(el);
    const title = card.find('#video-title').text().trim();
    if (!title) return;

    const meta = card.find('#metadata-line span');
    const href = card.find('a#video-title-link').attr('href')
      || card.find('a#thumbnail').attr('href');

    channel.videos.push({
      title,
      views: $(meta).eq(0).text().trim() || null,
      uploadDate: $(meta).eq(1).text().trim() || null,
      duration: card.find('#overlays #text').text().trim() || null,
      link: href ? new URL(href, 'https://www.youtube.com').href : null,
    });
  });

  return channel;
}

Несколько деталей делают этот код устойчивым. Сетка видео использует карточки YouTube ytd-rich-item-renderer, внутри каждой из которых #video-title содержит заголовок, а #metadata-line span содержит два метаданных-спана: первый, количество просмотров, второй, относительная дата загрузки. Значок продолжительности находится в оверлее миниатюры в #overlays #text. Ссылка для просмотра считывается из атрибута href анкора через attr, а не из его текста, затем передаётся через конструктор URL, чтобы относительный путь /watch?v=... стал абсолютной ссылкой. Каждое поле возвращает null, если элемент отсутствует.

Селекторы устаревают

ID элементов YouTube и теги renderer (ytd-rich-item-renderer, #video-title, #metadata-line и другие) меняются без предупреждения, и разметка отличается для вкладок «Видео», «Shorts» и главной страницы канала. Считайте приведённые выше селекторы начальным шаблоном, а не постоянным контрактом. Если поле возвращается как null, заново проинспектируйте живую отрисованную страницу в инструментах разработчика браузера и обновите селектор. Периодическое обновление селекторов, норма для любого продакшн-скрапера, а не признак поломки.

Шаг 3: собираем всё вместе

Теперь соедините получение и парсинг в один запускаемый скрипт. Получите отрисованный HTML, передайте его парсеру и выведите структурированную запись о канале.

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

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

async function crawl(pageUrl) {
  const options = { ajax_wait: 'true', page_wait: 7000 };
  const response = await api.get(pageUrl, options);
  if (response.statusCode === 200) return response.body;
  console.error(`Request failed: ${response.statusCode}`);
  return null;
}

function parseChannel(html) {
  const $ = cheerio.load(html);
  const channel = {
    title: $('#inner-header-container .ytd-channel-name .ytd-channel-name:first').text().trim(),
    channelHandle: $('.meta-item #channel-handle').text().trim(),
    videos: [],
  };
  $('#contents ytd-rich-item-renderer').each((_, el) => {
    const card = $(el);
    const title = card.find('#video-title').text().trim();
    if (!title) return;
    const meta = card.find('#metadata-line span');
    const href = card.find('a#video-title-link').attr('href')
      || card.find('a#thumbnail').attr('href');
    channel.videos.push({
      title,
      views: $(meta).eq(0).text().trim() || null,
      uploadDate: $(meta).eq(1).text().trim() || null,
      duration: card.find('#overlays #text').text().trim() || null,
      link: href ? new URL(href, 'https://www.youtube.com').href : null,
    });
  });
  return channel;
}

async function main() {
  const channelUrl = 'https://www.youtube.com/@Netflix/videos';
  const html = await crawl(channelUrl);
  if (!html) return;
  const channel = parseChannel(html);
  console.log(`${channel.title} (${channel.channelHandle}): ${channel.videos.length} videos`);
  console.log(JSON.stringify(channel.videos.slice(0, 3), null, 2));
}

main();

Как выглядит вывод

Запустите полный скрипт командой node scraper.js и получите чистый массив записей, по одной на видео, готовый к записи в JSON, CSV или базу данных. Количество просмотров и даты загрузки представлены публичными строками точно так, как их отображает YouTube.

json
[
  {
    "title": "Ilary Blasi: The one and only | Official Trailer | Netflix",
    "views": "56K views",
    "uploadDate": "6 days ago",
    "duration": "2:14",
    "link": "https://www.youtube.com/watch?v=pNY3NkGX6e8"
  },
  {
    "title": "Verified Stand-Up | Official Trailer | Netflix",
    "views": "50K views",
    "uploadDate": "11 days ago",
    "duration": "1:58",
    "link": "https://www.youtube.com/watch?v=gMIvGpHd2dk"
  }
]

Экспорт в JSON и CSV

Вывод в консоль хорош для быстрой проверки, но обычно данные нужны на диске. Запись JSON, это однострочник; небольшой CSV-писатель размещает каждое видео в отдельной строке с экранированием полей, чтобы запятые в названии не ломали столбцы.

javascript
const fs = require('fs');

function saveJson(channel, file) {
  fs.writeFileSync(file, JSON.stringify(channel, null, 2));
}

function saveCsv(videos, file) {
  const headers = ['title', 'views', 'uploadDate', 'duration', 'link'];
  const cell = (v) => `"${(v ?? '').replace(/"/g, '""')}"`;
  const rows = videos.map((v) => headers.map((h) => cell(v[h])).join(','));
  fs.writeFileSync(file, [headers.join(','), ...rows].join('\n'));
}

// in main(), after parseChannel():
saveJson(channel, 'channel.json');
saveCsv(channel.videos, 'channel.csv');

Вспомогательная функция cell оборачивает каждое значение в кавычки и удваивает встроенные кавычки, это стандартное экранирование CSV, поэтому название с запятой или кавычкой остаётся в одном столбце. JSON сохраняет вложенный объект канала; CSV разворачивает только строки видео, что является форматом, ожидаемым большинством таблиц и BI-инструментов.

Работа с полным списком видео канала

Отрисованная страница «Видео» даёт вам последнюю порцию загрузок, а не весь архив, поскольку YouTube подгружает дополнительные карточки по мере прокрутки. Одна отрисованная страница, хорошая демонстрация, и зачастую этого достаточно для исследования недавней активности. Чтобы углубиться в архив канала, есть несколько подходов, сохраняющих тот же паттерн «получение + парсинг».

  • Прокрутка при отрисовке. Передайте более длинный page_wait и используйте параметры прокрутки Crawling API, чтобы страница загрузила больше строк перед захватом, затем запустите тот же parseChannel по расширенной сетке.
  • Обход ссылок на отдельные видео. Берите каждую link из разобранного списка и получайте эту страницу просмотра через ту же функцию crawl, чтобы обогатить строку публичными деталями со страницы видео, а затем напишите небольшой парсер для этого макета.

В любом случае структура не меняется: отрисовка, затем парсинг. Держите объём запросов умеренным, чтобы читать канал, а не нагружать его.

Сохранение доступа

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

  • Дозируйте запросы. Атака на каналы в плотном цикле, самый быстрый способ получить ограничение скорости. Распределяйте запросы во времени и чередуйте каналы вместо того, чтобы краулить один путь на полной скорости.
  • Опирайтесь на ротацию. Пул резидентных IP-адресов распределяет запросы по множеству адресов реальных пользователей, чтобы ни один из них не превысил лимит скорости. Crawling API делает это за вас; если вы строите собственный стек, именно эта часть требует особого внимания.
  • Читайте коды статусов. Прогон, который начинает возвращать блокировки или ошибки, сигнализирует о том, что текущая частота или уровень IP больше недостаточны. Воспринимайте это как сигнал снизить активность, а не как шум для игнорирования.

Более широкие практики описаны в руководстве о том, как скрапить сайты, не попадая под блокировки. Если вы предпочитаете направлять собственный трафик через ротируемый пул, а не использовать управляемый API, Smart AI Proxy предоставляет ту же ротацию резидентных IP-адресов в виде прокси-эндпоинта для прямой замены. Для другого формата данных YouTube, видео и результатов поиска, а не сетки канала, смотрите наше руководство о том, как скрапить данные YouTube.

Законно ли скрапить YouTube?

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

Держите область применения узкой. Собирайте только публичные, неперсональные данные: названия видео, количество просмотров, даты загрузки, продолжительность и ссылки для просмотра, которые любой может увидеть на публичном канале без авторизации. По возможности агрегируйте данные (ритм публикаций, распределение просмотров, тематические тренды), а не стройте профиль конкретного автора. Не трогайте ничего за логином, приватные или скрытые видео, комментарии или персональные данные зрителей и авторов. Там, где речь идёт о персональных данных, применяются законы о конфиденциальности: GDPR и CCPA. Вам нужно законное основание для обработки данных и возможность выполнять запросы на удаление и доступ. Не распространяйте защищённый авторским правом видеоконтент, на который ведут ваши ссылки; ссылка на публичную страницу просмотра, это не лицензия на переразмещение медиа.

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

Итоги

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

  • YouTube отрисовывает сетку на стороне клиента. Обычный запрос возвращает пустую оболочку, поэтому перед парсингом необходимо отрисовать страницу «Видео».
  • Нужны отрисовка и доверенный IP вместе. Crawling API с JavaScript-запросом делает оба шага в одном вызове; ajax_wait и page_wait управляют временем ожидания карточек.
  • cheerio выполняет извлечение. Выбирайте каждую карточку ytd-rich-item-renderer, затем сопоставляйте название, просмотры, дату загрузки, продолжительность и ссылку для просмотра с актуальными селекторами, и ожидайте их смены.
  • Экспортируйте и масштабируйте осторожно. Пишите JSON для структуры и CSV для таблиц, и уходите глубже в архив канала с помощью более длинных отрисовок или отдельных получений видео с разумным темпом.
  • Оставайтесь в рамках публичных данных. Уважайте Условия использования YouTube и robots.txt, предпочитайте официальный YouTube Data API для объёмного или коммерческого использования, учитывайте GDPR и CCPA при работе с любыми персональными данными и никогда не касайтесь логинов, приватных видео или комментариев.

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

Почему обычный запрос возвращает пустую сетку видео с YouTube?

Потому что YouTube строит сетку видео в браузере с помощью JavaScript. Исходный HTML представляет собой тонкую оболочку, и реальная разметка карточек добавляется только после выполнения скриптов страницы и загрузки данных, поэтому голый HTTP-запрос возвращает статус 200 с пустой сеткой. Чтобы получить заполненную страницу, её необходимо сначала отрисовать, что и делает JavaScript-запрос Crawling API.

Мне нужен обычный или JavaScript-запрос для YouTube?

Используйте JavaScript-запрос. Обычный запрос получает статический HTML, который на канале YouTube возвращается как пустая оболочка без карточек. JavaScript-запрос отрисовывает страницу в настоящем браузере перед возвратом HTML, а параметры ajax_wait и page_wait дают сетке время завершить загрузку, чтобы cheerio было что парсить.

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

Скорее всего, разметка YouTube. Теги renderer и ID элементов (ytd-rich-item-renderer, #video-title, #metadata-line и другие) меняются без предупреждения, и они отличаются для вкладок «Видео», «Shorts» и главной страницы канала, поэтому селекторы, работавшие в прошлом месяце, могут сломаться. Заново проинспектируйте живую отрисованную страницу в инструментах разработчика браузера и обновите селекторы. Периодическое обслуживание селекторов нормально для любого продакшн-скрапера.

Как получить все видео, а не только последнюю порцию?

Первая отрисовка возвращает самые свежие загрузки, поскольку YouTube подгружает карточки по мере прокрутки. Чтобы добраться дальше в архив, передайте более длинный page_wait с параметрами прокрутки Crawling API, чтобы больше строк загрузилось до захвата, а затем запустите тот же парсер по расширенной сетке. Для глубоких архивов каналов официальный YouTube Data API с постраничной разбивкой загрузок канала подходит значительно лучше.

Что лучше: YouTube Data API или скрапинг сайта?

Если вам нужны объём, гарантированная структура или права на коммерческое использование, используйте официальный YouTube Data API. Он создан именно для этого и позволяет оставаться в рамках условий YouTube. Скрапинг публичных списков каналов с подходом из этого руководства подходит для небольших исследований публичных данных без API-доступа, при условии соблюдения Условий использования, robots.txt и лимитов скорости.

Можно ли скрапить комментарии или данные зрителей канала?

Нет, и это руководство не охватывает подобного. Комментарии, это персональный контент, написанный пользователями, а данные зрителей не являются публичными, поэтому оба типа выходят за рамки публичных, неперсональных данных, о которых идёт речь. Там, где речь идёт о персональных данных, применяются GDPR и CCPA, и вам нужно законное основание плюс способ выполнять запросы на удаление. Для санкционированного доступа к такому типу данных правильным путём является YouTube Data API с надлежащим согласием и условиями.

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

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

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

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