Как скрейпить YouTube с прокси: публичные данные, InnerTube API и ротация IP

Практическое руководство по извлечению публичных данных YouTube — метаданные видео, комментарии, транскрипты — с использованием InnerTube API и резидентных прокси для обхода блокировок Google.

Как скрейпить YouTube с прокси: публичные данные, InnerTube API и ротация IP

YouTube — второй по посещаемости сайт в мире и крупнейший публичный архив видео. Для исследователей медиа, аналитиков креатор-экономики и команд мониторинга брендов это бесценный источник: просмотры, тренды, комментарии, субтитры. Но извлечь эти данные масштабно — задача нетривиальная. Google защищает платформу агрессивно, а официальный API быстро упирается в квоты.

Важно: эта статья посвящена исключительно доступу к публичным данным. Соблюдайте Условия использования YouTube, применимое законодательство (CFAA в США, GDPR в ЕС) и права создателей контента. Никогда не распространяйте скрейпенные транскрипты или защищённый контент.

Когда YouTube Data API v3 достаточно — а когда нет

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

Квоты и стоимость

Каждый проект получает 10 000 единиц квоты в день. Разные методы стоят по-разному:

МетодСтоимость единицЗапросов/день при лимите 10K
videos.list1~10 000
search.list100~100
commentThreads.list1~10 000
playlistItems.list1~10 000

Проблема — search.list. Сто единиц за запрос означает, что вы можете сделать лишь ~100 поисковых запросов в день. Для мониторинга трендов в реальном времени этого катастрофически мало.

Где API подводит

  • Комментарии масштабно: API отдаёт до ~20 комментариев за запрос, требует пагинации, и для канала с миллионами комментариев вы исчерпаете квоту за часы.
  • Раннее обнаружение трендов: API кэширует данные и не даёт субминутного обновления. Скрейпинг страниц трендов быстрее.
  • Мониторинг рекламы: API не предоставляет данные о рекламных вставках — это доступно только через воспроизведение.
  • Транскрипты: API не отдаёт субтитры. Совсем.

Какие данные доступны без входа в аккаунт

YouTube рендерит значительную часть контента для неавторизованных посетителей. Вот что можно извлечь:

  • Метаданные видео: заголовок, описание, количество просмотров, лайков, дата публикации, длительность.
  • Страницы каналов: список видео, описание канала, количество подписчиков.
  • Потоки комментариев: первые ~20 комментариев и их ответы — через InnerTube API.
  • Транскрипты: автоматически сгенерированные и загруженные создателем субтитры.
  • Рекомендации и тренды: содержимое вкладок «В тренде», рекомендованные видео.

Данные, требующие входа: история просмотров, персональные рекомендации, приватные плейлисты, уведомления, данные о рекламе.

InnerTube API — скрытый интерфейс YouTube

YouTube использует внутренний API под названием InnerTube для всех запросов данных на фронтенде. Когда вы открываете страницу видео, браузер делает POST-запрос к эндпоинтам вроде /youtubei/v1/next и /youtubei/v1/player. Эти эндпоинты возвращают JSON с гораздо более богатыми данными, чем публичный API.

Ключевые эндпоинты

ЭндпоинтНазначениеМетод
/youtubei/v1/nextКомментарии, рекомендации, связанное содержимоеPOST
/youtubei/v1/playerМетаданные видео, форматы стримингаPOST
/youtubei/v1/searchРезультаты поискаPOST
/youtubei/v1/browseСтраницы каналов, плейлисты, трендыPOST

Continuation-токены

InnerTube использует continuation-токены для пагинации. Первый запрос к /youtubei/v1/next с ID видео возвращает первые ~20 комментариев и continuation-токен. Каждый последующий запрос с этим токеном отдаёт следующую порцию. Это позволяет обойти ограничения API и извлекать комментарии масштабно.

Почему нужны резидентные прокси

Google — один из самых агрессивных детекторов ботов. Если вы делаете сотни запросов к YouTube с дата-центерных IP-адресов, вы быстро столкнётесь с:

  • CAPTCHA — Google выдаёт страницу с капчей вместо JSON.
  • HTTP 429 — Rate limit, иногда на весь IP-диапазон.
  • Постоянная блокировка — IP попадает в чёрный список на часы или дни.

Google особенно строго фильтрует диапазоны дата-центров (AWS, GCP, Azure, Hetzner, OVH). Это не теория — это наблюдаемая практика. Запросы с DC-IP получают CAPTCHA в 5–10 раз чаще, чем с резидентных.

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

Для YouTube скрейпинга оптимальная стратегия — ротация IP на каждый запрос (per-request rotation), чтобы ни один IP не накапливал подозрительную активность.

Практика: скрейпинг YouTube с Python и резидентными прокси

Извлечение транскриптов с youtube-transcript-api

Библиотека youtube-transcript-api — самый простой способ получить субтитры. Но при массовом извлечении Google тоже блокирует. Подключаем прокси:

from youtube_transcript_api import YouTubeTranscriptApi
import random

# ProxyHat residential proxy with per-request rotation
PROXY_URL = "http://user-country-US:PASSWORD@gate.proxyhat.com:8080"

proxies = {
    "http": PROXY_URL,
    "https": PROXY_URL,
}

video_ids = ["dQw4w9WgXcQ", "jNQXAC9IVRw", "9bZkp7q19f0"]

for vid in video_ids:
    try:
        transcript = YouTubeTranscriptApi.get_transcript(
            vid,
            languages=["en", "ru"],
            proxies=proxies
        )
        full_text = " ".join([entry["text"] for entry in transcript])
        print(f"{vid}: {len(full_text)} chars")
    except Exception as e:
        print(f"{vid}: error — {e}")

Извлечение комментариев через InnerTube

Этот пример обращается к /youtubei/v1/next, извлекает первые комментарии и следует по continuation-токенам:

import requests
import json
import time

PROXY_URL = "http://user-country-US:PASSWORD@gate.proxyhat.com:8080"
proxies = {"http": PROXY_URL, "https": PROXY_URL}

INNER_TUBE_HEADERS = {
    "Content-Type": "application/json",
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
                  "AppleWebKit/537.36 (KHTML, like Gecko) "
                  "Chrome/125.0.0.0 Safari/537.36",
    "Origin": "https://www.youtube.com",
    "Referer": "https://www.youtube.com/",
}

INNER_TUBE_CONTEXT = {
    "context": {
        "client": {
            "clientName": "WEB",
            "clientVersion": "2.20240530.01.00",
            "hl": "en",
            "gl": "US",
        }
    }
}

def fetch_initial_comments(video_id, max_pages=5):
    """Fetch comments via InnerTube /youtubei/v1/next."""
    url = "https://www.youtube.com/youtubei/v1/next"
    payload = {**INNER_TUBE_CONTEXT, "videoId": video_id}
    session = requests.Session()
    session.proxies.update(proxies)

    resp = session.post(url, headers=INNER_TUBE_HEADERS,
                        json=payload, timeout=15)
    resp.raise_for_status()
    data = resp.json()

    comments = []
    continuation_token = None

    # Extract comments and continuation token from response
    for renderer in data.get("contents", {}).get(
        "twoColumnWatchNextResults", {}
    ).get("results", {}).get("results", {}).get("contents", []):
        if "itemSectionRenderer" in renderer:
            section = renderer["itemSectionRenderer"]
            for item in section.get("contents", []):
                if "commentThreadRenderer" in item:
                    cr = item["commentThreadRenderer"]["comment"][
                        "commentRenderer"
                    ]
                    comments.append({
                        "author": cr.get("authorText", {}).get("simpleText", ""),
                        "text": cr.get("contentText", {}).get("runs", [{}])[0].get("text", ""),
                        "likes": cr.get("voteCount", {}).get("simpleText", "0"),
                    })
                if "continuationItemRenderer" in item:
                    continuation_token = item[
                        "continuationItemRenderer"
                    ]["continuationEndpoint"][
                        "continuationCommand"
                    ]["token"]

    # Follow continuation tokens
    pages = 1
    while continuation_token and pages < max_pages:
        time.sleep(1.5)  # polite delay
        cont_payload = {
            **INNER_TUBE_CONTEXT,
            "continuation": continuation_token,
        }
        resp = session.post(url, headers=INNER_TUBE_HEADERS,
                            json=cont_payload, timeout=15)
        resp.raise_for_status()
        cdata = resp.json()

        for action in cdata.get("onResponseReceivedEndpoints", []):
            for item in (action.get("appendContinuationItemsAction", {})
                         .get("continuationItems", [])):
                if "commentThreadRenderer" in item:
                    cr = item["commentThreadRenderer"]["comment"][
                        "commentRenderer"
                    ]
                    comments.append({
                        "author": cr.get("authorText", {}).get("simpleText", ""),
                        "text": cr.get("contentText", {}).get("runs", [{}])[0].get("text", ""),
                        "likes": cr.get("voteCount", {}).get("simpleText", "0"),
                    })
                if "continuationItemRenderer" in item:
                    continuation_token = item[
                        "continuationItemRenderer"
                    ]["continuationEndpoint"][
                        "continuationCommand"
                    ]["token"]
                    break
            else:
                continuation_token = None

        pages += 1

    return comments

comments = fetch_initial_comments("dQw4w9WgXcQ", max_pages=3)
print(f"Extracted {len(comments)} comments")

Метаданные видео через player-эндпоинт

def fetch_video_metadata(video_id):
    """Get video metadata via InnerTube /youtubei/v1/player."""
    url = "https://www.youtube.com/youtubei/v1/player"
    payload = {
        **INNER_TUBE_CONTEXT,
        "videoId": video_id,
    }
    session = requests.Session()
    session.proxies.update(proxies)

    resp = session.post(url, headers=INNER_TUBE_HEADERS,
                        json=payload, timeout=15)
    resp.raise_for_status()
    data = resp.json()

    video_details = data.get("videoDetails", {})
    return {
        "title": video_details.get("title", ""),
        "channel": video_details.get("author", ""),
        "views": video_details.get("viewCount", "0"),
        "length_seconds": video_details.get("lengthSeconds", "0"),
        "description": video_details.get("shortDescription", ""),
        "keywords": video_details.get("keywords", []),
        "is_live": video_details.get("isLiveContent", False),
    }

meta = fetch_video_metadata("dQw4w9WgXcQ")
print(json.dumps(meta, indent=2, ensure_ascii=False))

Node.js: скрейпинг комментариев с InnerTube

Для команд на JavaScript — аналогичный подход с node-fetch и прокси через HTTPS-агент:

import fetch from 'node-fetch';
import { HttpsProxyAgent } from 'https-proxy-agent';

const PROXY_URL = 'http://user-country-US:PASSWORD@gate.proxyhat.com:8080';
const agent = new HttpsProxyAgent(PROXY_URL);

const INNER_TUBE_CTX = {
  context: {
    client: {
      clientName: 'WEB',
      clientVersion: '2.20240530.01.00',
      hl: 'en',
      gl: 'US',
    },
  },
};

async function fetchComments(videoId, maxPages = 3) {
  const url = 'https://www.youtube.com/youtubei/v1/next';
  const headers = {
    'Content-Type': 'application/json',
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) '
      + 'AppleWebKit/537.36 Chrome/125.0.0.0 Safari/537.36',
    Origin: 'https://www.youtube.com',
    Referer: 'https://www.youtube.com/',
  };

  let payload = { ...INNER_TUBE_CTX, videoId };
  const comments = [];
  let continuationToken = null;

  for (let page = 0; page < maxPages; page++) {
    const resp = await fetch(url, {
      method: 'POST',
      headers,
      body: JSON.stringify(payload),
      agent,
    });
    const data = await resp.json();

    const endpoints = data.onResponseReceivedEndpoints
      || data.contents?.twoColumnWatchNextResults
          ?.results?.results?.contents || [];

    for (const endpoint of (Array.isArray(endpoints) ? endpoints : [endpoints])) {
      const items = endpoint.appendContinuationItemsAction
        ?.continuationItems
        || endpoint.itemSectionRenderer?.contents
        || [];
      for (const item of items) {
        if (item.commentThreadRenderer) {
          const cr = item.commentThreadRenderer.comment.commentRenderer;
          comments.push({
            author: cr.authorText?.simpleText ?? '',
            text: cr.contentText?.runs?.[0]?.text ?? '',
            likes: cr.voteCount?.simpleText ?? '0',
          });
        }
        if (item.continuationItemRenderer) {
          continuationToken = item.continuationItemRenderer
            .continuationEndpoint.continuationCommand.token;
        }
      }
    }

    if (!continuationToken) break;
    payload = { ...INNER_TUBE_CTX, continuation: continuationToken };
    await new Promise(r => setTimeout(r, 1500));
  }

  return comments;
}

const comments = await fetchComments('dQw4w9WgXcQ', 3);
console.log(`Extracted ${comments.length} comments`);

Стратегии ротации IP и обхода ограничений

Per-request ротация

Для YouTube оптимальна ротация на каждый запрос. ProxyHat поддерживает это по умолчанию — каждый HTTP-запрос через один и тот же аккаунт получает новый IP из пула резидентных адресов.

Если вам нужна sticky-сессия (например, для последовательного извлечения комментариев с одного IP, чтобы избежать несогласованности данных), используйте флаг сессии:

# Sticky session — один IP на 10 минут
PROXY = "http://user-session-myvid01-country-US:PASSWORD@gate.proxyhat.com:8080"

Геотаргетинг

YouTube показывает разный контент в зависимости от страны. Для мониторинга трендов в конкретном регионе укажите гео-параметр:

# Тренды Германии
PROXY = "http://user-country-DE:PASSWORD@gate.proxyhat.com:8080"

Это особенно важно для SERP-трекинга и сравнения трендов между рынками.

Rate limiting: практические рекомендации

  • 1–2 секунды между запросами с одного IP — минимум вежливости.
  • Не более 50–100 запросов с одного IP за короткий период.
  • Ротируйте User-Agent — используйте пул реальных UA Chrome/Firefox.
  • Обрабатывайте 429 и CAPTCHA — экспоненциальная задержка и смена IP.

Риски фингерпринтинга

Google анализирует не только IP, но и паттерны запросов:

  • TLS-фингерпринт — библиотека requests на Python использует TLS-стек, отличающийся от Chrome. Google может это обнаружить. Используйте curl_cffi или tls_client для имитации реального браузера.
  • Порядок заголовков — InnerTube-запросы должны точно повторять порядок заголовков Chrome.
  • Паттерн доступа — если вы запрашиваете 100 видео подряд без единого клика по рекомендациям, это подозрительно. Вставляйте «шумовые» запросы.

Сравнение подходов к извлечению данных YouTube

МетодДанныеМасштабБлокировкиСложность
YouTube Data API v3Метаданные, поиск, комментарииОграничен квотамиНетНизкая
InnerTube API + проксиМетаданные, комментарии, рекомендации, трендыВысокийУмеренныеСредняя
youtube-transcript-api + проксиТранскриптыСреднийУмеренныеНизкая
Браузерная автоматизация (Puppeteer/Playwright)Все видимые данные + рекламаНизкийВысокиеВысокая
Официальные отчёты YouTube AnalyticsПолная аналитика собственного каналаНеограниченНетНизкая (только свои данные)

Этический скрейпинг: когда использовать официальные API

Скрейпинг — мощный инструмент, но не всегда правильный. Вот принципы, которых мы рекомендуем придерживаться:

  1. Сначала проверьте API. Если YouTube Data API v3 покрывает ваши потребности — используйте его. Это стабильнее, законнее и надёжнее.
  2. Не перераспределяйте скрейпенный контент. Транскрипты, описания и комментарии — интеллектуальная собственность создателей. Извлечение для анализа — одно, перепродажа или публикация — другое.
  3. Соблюдайте robots.txt. YouTube разрешает некоторые пути и запрещает другие. Уважайте эти правила.
  4. Не пытайтесь обойти paywall или авторизацию. Если данные требуют входа — они не являются публичными.
  5. Минимизируйте нагрузку. Не делайте запросов больше, чем нужно. Кэшируйте результаты.
  6. Учитывайте GDPR и CCPA. Комментарии пользователей содержат персональные данные. Если вы извлекаете комментарии из ЕС или Калифорнии — вы несёте ответственность за их обработку.

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

Подробнее об этике и практике скрейпинга — в нашем руководстве по веб-скрейпингу.

Key Takeaways

  • YouTube Data API v3 подходит для базовых задач, но квота в 10 000 единиц/день — жёсткое ограничение, особенно для поиска и масштабного извлечения комментариев.
  • InnerTube API (/youtubei/v1/next, /youtubei/v1/player, /youtubei/v1/browse) — более мощный и гибкий способ получения публичных данных, но требует имитации реального клиента.
  • Резидентные прокси необходимы для масштабного скрейпинга YouTube — Google агрессивно блокирует дата-центерные IP-диапазоны.
  • Ротация IP на каждый запрос — оптимальная стратегия для YouTube; sticky-сессии — для последовательного извлечения с одного IP.
  • Геотаргетинг позволяет видеть региональные тренды и рекомендации — критически важно для медиа-аналитики.
  • Транскрипты доступны через youtube-transcript-api с прокси, но не через официальный API.
  • Этика прежде масштаба: не перераспределяйте контент создателей, соблюдайте ToS, GDPR и CCPA, используйте API когда возможно.

Готовы начать извлечение данных YouTube с надёжными резидентными прокси? Ознакомьтесь с тарифами ProxyHat и доступными локациями — более 190 стран для точного геотаргетинга.

Готовы начать?

Доступ к более чем 50 млн резидентных IP в 148+ странах с AI-фильтрацией.

Смотреть ценыРезидентные прокси
← Вернуться в Блог