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

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

Что вы построите

Небольшой Python-скрипт, который принимает публичный поисковый запрос или URL видео YouTube, получает полностью отрисованную страницу через Crawling API с JavaScript-токеном и разбирает несколько публичных, неличных полей для каждого результата:

  • Заголовок название видео, которое говорит о том, как тема представлена для ранжирования и привлечения кликов.
  • Канал название канала, опубликовавшего видео, полезное для определения того, кто владеет темой.
  • Просмотры публичное количество просмотров, приблизительный сигнал спроса по ключевому слову или теме.
  • Дата публикации относительная или абсолютная дата загрузки, показывающая свежесть результатов ранжирования.
  • Ссылка канонический URL просмотра каждого видео, чтобы вы могли вернуться к нему или обогатить его позже.

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

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

Запросите URL поиска YouTube с помощью простого HTTP-клиента, и вы получите ответ, который технически является успехом, а практически бесполезным. YouTube отрисовывает свои результаты на стороне клиента: исходный HTML является тонкой оболочкой, и реальный список видео появляется только после того, как JavaScript страницы запустится в браузере и гидратирует результаты. Кроме того, YouTube следит за автоматизированным трафиком. Диапазоны IP дата-центров, отсутствие поведения браузера и повторяющиеся паттерны запросов получают проверку или ограничение скорости задолго до загрузки интересного контента.

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

Почему нужен JS-токен

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

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

Сначала убедитесь в наличии нескольких вещей. Ни одна из них не займёт много времени.

Базовый Python. Вы должны уметь запускать скрипт и устанавливать пакеты с помощью pip. Если вы новичок в разборе HTML, наше руководство по использованию BeautifulSoup в Python охватывает сторону извлечения данных.

Python 3.8 или новее. Проверьте с помощью python --version. Если у вас его нет, установите с python.org.

Аккаунт Crawlbase и JS-токен. Зарегистрируйтесь, откройте панель управления и скопируйте JavaScript-токен (JS). Бесплатный тариф включает до 20 000 запросов, и вы платите только за успешные, что вполне достаточно для исследовательских прогонов в этом руководстве. Относитесь к токену как к паролю и не включайте его в систему контроля версий.

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

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

bash
python --version

python -m venv youtube_env
source youtube_env/bin/activate

pip install crawlbase beautifulsoup4

В Windows активируйте с помощью youtube_env\Scripts\activate вместо строки source. Две зависимости выполняют работу: crawlbase является официальным клиентом для Crawling API, а beautifulsoup4 разбирает возвращаемый HTML, чтобы вы могли извлекать отдельные поля по селектору. Стандартные модули json и csv обрабатывают экспорт, поэтому для этого ничего дополнительно устанавливать не нужно.

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

Начните с получения готовой страницы. Импортируйте CrawlingAPI, инициализируйте его с помощью JS-токена и запросите публичный URL страницы результатов поиска. Включите запрос в стандартный путь results?search_query= и проверьте код статуса перед разбором, чтобы сбои оставались явными, а не скрытыми.

python
from urllib.parse import quote_plus
from crawlbase import CrawlingAPI

api = CrawlingAPI({"token": "YOUR_CRAWLBASE_TOKEN"})

def crawl(page_url):
    options = {"ajax_wait": "true", "page_wait": 5000}
    response = api.get(page_url, options)
    if response["status_code"] == 200:
        return response["body"].decode("utf-8")
    print(f"Request failed: {response['status_code']}")
    return None

def search_url(query):
    return f"https://www.youtube.com/results?search_query={quote_plus(query)}"

if __name__ == "__main__":
    query = "data scraping tutorial"
    html = crawl(search_url(query))
    print(html[:500] if html else "No HTML returned")

Два параметра ожидания важны для цели с клиентской отрисовкой. ajax_wait говорит API дождаться завершения загрузки асинхронного контента, а page_wait выдерживает фиксированное количество миллисекунд после загрузки, чтобы список результатов с поздней отрисовкой появился до захвата страницы. Пять секунд является разумной отправной точкой; увеличьте, если результаты возвращаются пустыми. Запрос повторяет устаревший пример ("data scraping tutorial"), чтобы вы могли напрямую сравнить вывод. Запустите скрипт, и вы должны увидеть реальную разметку YouTube, что подтверждает работу отрисовки, прежде чем вы напишете хоть один селектор.

Crawlbase Crawling API

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

Шаг 2: Разбор публичных полей

Имея отрисованный HTML, наиболее стабильным сигналом на странице YouTube является встроенный объект JSON ytInitialData, который страница поставляет вместе со своими скриптами. Он содержит те же поля, которые YouTube использует для отрисовки списка результатов: заголовки, названия каналов, текст счётчика просмотров, текст времени публикации и идентификаторы видео. Разбор этого объекта значительно надёжнее, чем погоня за глубоко вложенными, часто переименовываемыми CSS-классами. Загрузите HTML в BeautifulSoup, извлеките скрипт, определяющий ytInitialData, и пройдитесь по нему в поисках отрисовщиков видео.

python
import json
import re
from bs4 import BeautifulSoup

def load_initial_data(html):
    soup = BeautifulSoup(html, "html.parser")
    for script in soup.find_all("script"):
        text = script.string or ""
        if "ytInitialData" in text:
            match = re.search(r"ytInitialData\s*=\s*(\{.*?\});", text, re.DOTALL)
            if match:
                return json.loads(match.group(1))
    return {}

def text_of(node):
    if not node:
        return None
    if "simpleText" in node:
        return node["simpleText"]
    runs = node.get("runs", [])
    return "".join(r["text"] for r in runs) if runs else None

Вспомогательная функция load_initial_data изолирует объект JSON с помощью нежадного регулярного выражения и разбирает его. Вспомогательная функция text_of обрабатывает два формата текста YouTube: некоторые поля являются обычной строкой simpleText, другие представляют собой список runs, которые нужно объединить. Имея эти две вспомогательные функции, извлечение каждого видео становится простым обходом по отрисовщикам поиска.

Шаг 3: Извлечение одной записи на видео

YouTube вкладывает результаты поиска под длинным путём из отрисовщиков разделов и элементов. Каждый воспроизводимый результат является videoRenderer, который содержит заголовок, название канала (ownerText или longBylineText), viewCountText, publishedTimeText и videoId. Обойдите структуру, соберите каждый videoRenderer и сопоставьте каждый с плоской записью.

python
def find_video_renderers(node, found):
    if isinstance(node, dict):
        if "videoRenderer" in node:
            found.append(node["videoRenderer"])
        for value in node.values():
            find_video_renderers(value, found)
    elif isinstance(node, list):
        for item in node:
            find_video_renderers(item, found)
    return found

def parse_search(html):
    data = load_initial_data(html)
    renderers = find_video_renderers(data, [])
    results = []
    for v in renderers:
        video_id = v.get("videoId")
        if not video_id:
            continue
        channel = text_of(v.get("ownerText")) or text_of(v.get("longBylineText"))
        results.append({
            "title": text_of(v.get("title")),
            "channel": channel,
            "views": text_of(v.get("viewCountText")),
            "published": text_of(v.get("publishedTimeText")),
            "link": f"https://www.youtube.com/watch?v={video_id}",
        })
    return results

Рекурсивный обход find_video_renderers позволяет избежать жёсткого кодирования точного пути вложенности, который YouTube периодически переупорядочивает; он просто собирает каждый videoRenderer, где бы он ни появлялся. Каждая запись содержит ровно пять публичных полей, которые вы изначально хотели собрать: заголовок, канал, просмотры, дата публикации и ссылка. Это сигналы о контенте и спросе, а не персональные данные о каком-либо зрителе.

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

YouTube меняет свою разметку и внутренние имена полей без предупреждения, именно поэтому этот код опирается на объект ytInitialData и имена отрисовщиков, а не на хрупкие вложенные CSS-классы. Когда поле возвращает None, повторно проверьте живую страницу в инструментах разработчика браузера и обновите ключ. Периодическое обслуживание является нормой для любого производственного скрапера, а не признаком того, что что-то сломалось.

Шаг 4: Собираем всё вместе и экспортируем в JSON и CSV

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

python
import csv
import json
import time
from urllib.parse import quote_plus
from crawlbase import CrawlingAPI

api = CrawlingAPI({"token": "YOUR_CRAWLBASE_TOKEN"})

def main():
    queries = ["data scraping tutorial", "python web scraping"]
    rows = []
    for query in queries:
        html = crawl(search_url(query))
        if not html:
            continue
        for record in parse_search(html)[:10]:
            record["query"] = query
            rows.append(record)
        time.sleep(3)

    with open("youtube_research.json", "w", encoding="utf-8") as f:
        json.dump(rows, f, indent=2, ensure_ascii=False)

    fields = ["query", "title", "channel", "views", "published", "link"]
    with open("youtube_research.csv", "w", newline="", encoding="utf-8") as f:
        writer = csv.DictWriter(f, fieldnames=fields)
        writer.writeheader()
        writer.writerows(rows)

    print(f"Saved {len(rows)} videos across {len(queries)} queries")

if __name__ == "__main__":
    main()

time.sleep(3) между запросами не является украшением. Пауза является единственным наиболее важным фактором того, останется ли прогон работоспособным, и мы вернёмся к этому. Срез [:10] отражает топ-10 результатов, которые выводил устаревший скрипт, и держит демонстрацию в фокусе. Объедините это с более ранними функциями crawl, search_url и parse_search в одном файле, и оно запустится от начала до конца.

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

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

json
[
  {
    "title": "Web Scraping Tutorial | Data Scraping from Websites to Excel",
    "channel": "Data Analytics",
    "views": "1.2M views",
    "published": "2 years ago",
    "link": "https://www.youtube.com/watch?v=aClnnoQK9G0",
    "query": "data scraping tutorial"
  },
  {
    "title": "Beginners Guide To Web Scraping with Python",
    "channel": "Coding Channel",
    "views": "480K views",
    "published": "1 year ago",
    "link": "https://www.youtube.com/watch?v=QhD015WUMxE",
    "query": "data scraping tutorial"
  }
]

Количество просмотров и строки времени публикации приходят прямо из YouTube как отображаемый текст ("1.2M views", "2 years ago"). Для анализа нормализуйте их в последующем проходе: удалите "views" и преобразуйте суффиксы M и K в целые числа, а относительные даты переведите в приближённые абсолютные. Хранение необработанных строк в экспорте означает, что вы никогда не потеряете исходный сигнал.

Превращение данных в контентные и SEO-исследования

Смысл этого скрапинга не в сырых строках, а в том, что они говорят вам о теме. Несколько практических способов чтения:

  • Шаблоны заголовков, которые ранжируются. Группируйте лучшие результаты по запросу и смотрите, как сформулированы победившие заголовки: модификаторы, скобки, цифры, обещание. Это язык, на который аудитория нажимает для данного ключевого слова.
  • Спрос по количеству просмотров. Сортируйте по просмотрам, чтобы увидеть, какие подтемы привлекают наибольшее внимание. Высокое количество просмотров у старых видео без недавних конкурентов часто сигнализирует о возможности для свежего контента.
  • Пробелы в актуальности. Столбец с датой публикации показывает, насколько стары результаты ранжирования. Запрос, в котором доминируют видео многолетней давности, является кандидатом для актуальной подачи материала.
  • Владение темой. Подсчёт того, как часто каждый канал появляется в ваших запросах, показывает, кто уже владеет темой, что помогает как в конкурентном анализе, так и в поиске идей для партнёрства.

Это естественно сочетается с вашей более широкой работой с ключевыми словами. Если вы строите исследовательский конвейер, наши руководства по использованию данных для улучшения SEO и извлечению и анализу данных Google SEO описывают, как включить такой источник в полную картину.

Масштабирование и пагинация

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

Поддерживайте объём пропорционально исследовательскому вопросу. Вам редко нужны все результаты по запросу; лучшие результаты несут большую часть сигнала, а небольшой, хорошо выбранный набор запросов превосходит исчерпывающий краулинг как по качеству, так и по добросовестности.

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

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

  • Делайте паузы между запросами. Обработка страниц в плотном цикле является самым быстрым способом получить ограничение скорости. Добавьте реальные задержки, как в time.sleep выше, и противьтесь желанию активно параллелизировать.
  • Опирайтесь на ротацию. Пул резидентских IP распределяет запросы по многим адресам реальных пользователей, чтобы ни один из них не превысил лимит скорости. Crawling API делает это за вас; если вы строите собственный стек, именно эту часть нужно сделать правильно.
  • Следите за кодами статуса. Прогон, который начинает возвращать проверки или ошибки, сообщает вам, что текущая скорость или уровень IP уже недостаточны. Снижайте скорость, а не наращивайте её.
  • Поддерживайте небольшой объём и разнообразие запросов. Исследование контента не требует исчерпывающего сканирования YouTube. Делайте выборку по важным запросам и останавливайтесь.

Более широкую инструкцию смотрите в нашем руководстве о том, как скрапить сайты без блокировки, и в подробном обзоре о том, как скрапить JavaScript-страницы с помощью Python.

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

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

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

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

Итоги

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

  • YouTube отрисовывается на стороне клиента и защищён от ботов. Обычный запрос возвращает пустую оболочку, поэтому страницу необходимо отрисовать перед разбором.
  • Отрисовка и доверенный IP должны быть в одном вызове. Crawling API с JS-токеном делает оба; ajax_wait и page_wait контролируют, как долго он ждёт контента.
  • Разбирайте встроенный JSON. Объект ytInitialData и имена отрисовщиков значительно надёжнее, чем хрупкие вложенные CSS-классы.
  • Пять публичных полей движут исследованием. Заголовок, канал, просмотры, дата публикации и ссылка являются сигналами о контенте и спросе, а не персональными данными о зрителях.
  • Делайте паузы, ротируйте и предпочитайте Data API. Поддерживайте небольшой объём, опирайтесь на резидентскую ротацию и используйте официальный YouTube Data API для всего реального или коммерческого.

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

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

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

Какой токен мне нужен для YouTube: обычный или JS?

JS-токен. Обычный токен получает статический HTML, который на YouTube является той же пустой оболочкой, что и обычный запрос. JS-токен отрисовывает страницу в настоящем браузере перед возвратом HTML, поэтому встроенный объект ytInitialData и описываемые им результаты присутствуют при их разборе.

Какие данные YouTube безопасно скрапить для SEO-исследований?

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

Как превратить собранные данные в исследование ключевых слов?

Группируйте результаты по запросу и изучайте паттерны. Формулировка заголовков лучших результатов показывает язык, который ранжируется для ключевого слова; количество просмотров ранжирует подтемы по спросу; даты публикации обнаруживают пробелы в актуальности, которые вы можете заполнить; а частота появления каналов показывает, кто уже владеет темой. Экспортируйте в CSV, и анализ представляет собой несколько сортировок в таблице.

Следует ли мне использовать официальный YouTube Data API или скрапить сайт?

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

Как избежать блокировки при скрапинге YouTube?

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

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

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

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

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