← Назад в базу знаний

YouTube через IPv6 прокси: парсинг комментариев и аналитика каналов

YouTube через IPv6 прокси: парсинг комментариев и аналитика каналов

Почему YouTube и IPv6 — это отдельная история

YouTube отдаёт контент по IPv6 с 2012 года. Причём делает это агрессивно: если у клиента есть AAAA-запись и рабочий маршрут, трафик почти наверняка пойдёт по v6. Для парсинга это одновременно подарок и головная боль. Подарок — потому что IPv6-адресов у провайдера десятки миллионов, блокировки по IP размазываются тонким слоем. Головная боль — потому что Google видит v6-подсети крупными блоками и банит не отдельный адрес, а /64 или даже /48.

Разбираем, как выстроить сбор комментариев и статистики каналов через IPv6-прокси так, чтобы не ловить 429 на каждом втором запросе. С примерами кода, цифрами и граблями, на которые наступают все.

Что вообще отдаёт YouTube без API-ключа

Официальный Data API v3 даёт 10 000 units в день бесплатно. Один вызов `commentThreads.list` стоит 1 unit, `search.list` — 100 units. Хочешь собрать 5000 комментариев под роликом — это 50 запросов по 100 комментариев, то есть 50 units. Вроде немного. Но как только начинаешь мониторить сотни каналов, квота кончается за пару часов.

Отсюда два пути. Первый — платить Google за дополнительные квоты (дорого, \$0.005 за unit сверху, и не всегда дают). Второй — парсить внутренние эндпоинты `youtubei/v1/next`, которые отдают те же данные без ключа, но требуют валидный `context` и `visitorData`. Второй путь и есть вотчина прокси-пулов.

Внутренний API отвечает JSON с структурой `continuationCommand.token`. Токен живёт примерно 30-60 минут, потом протухает. Каждый следующий запрос за комментариями использует токен из предыдущего ответа. Это значит, что сессию нельзя размазывать по разным IP — токен привязан к visitor-сессии, и с чужого адреса Google отдаст 403.

Как Google детектит парсер по IPv6

Три главных маркера. Первый — плотность запросов с одной /64-подсети. Если с блока `2a01:4f8:1c1c:xxxx::/64` прилетает 200 запросов в минуту на разные видео, это аномалия. Домашний пользователь так не делает.

Второй — TLS-фингерпринт. Стандартный `requests` в Python шлёт JA3-хеш, который Google давно в чёрном списке. Нужен либо `curl_cffi` с имитацией Chrome, либо `httpx` с настройкой TLS.

Третий — отсутствие сопутствующих запросов. Реальный браузер перед загрузкой комментариев дёргает `/youtubei/v1/player`, `/youtubei/v1/browse`, тянет превью, статику с `ytimg.com`. Парсер, который ходит только в `next`, палится на пустом профиле.

Пример: сервер на Hetzner с /64-блоком, 50 параллельных потоков через `aiohttp`, дефолтный User-Agent. Через 8 минут — 429 на всех потоках. Смена UA на свежий Chrome не помогла: JA3 остался прежним. После перехода на `curl_cffi` с `impersonate="chrome120"` и раскидывания по 5 адресам из /64 — стабильно 40 минут без бана.

Схема пула: сколько адресов реально нужно

Один IPv6-адрес держит примерно 60-80 запросов к `youtubei` в час без риска. Дальше растёт вероятность 429. Если задача — собирать 10 000 комментариев в сутки с 200 видео, это около 100 запросов `next` плюс 200 `player`. Итого 300 запросов. Хватит 5-6 адресов, если размазать по времени.

Другое дело — аналитика каналов: парсинг `/videos`, `/about`, `/community` для сотни каналов раз в час. Это 300 запросов в час минимум. Нужен пул из 20-30 адресов с ротацией.

Таблица реальных лимитов, снятых с тестов на одном /64:

| Тип запроса | Запросов/час с 1 IP | Первый 429 |

|---|---|---|

| `player` | 120 | ~140 |

| `next` (комменты) | 80 | ~95 |

| `browse` (канал) | 100 | ~115 |

| `search` | 40 | ~50 |

Цифры плавают от региона и времени суток. Ночью по UTC лимиты мягче примерно на 15%.

Практика: запрос комментариев через прокси

Рабочий пример на Python с `curl_cffi` и IPv6-прокси. Прокси формата `http://[2a01:4f8:xxxx::1]:3128`.

```python

from curl_cffi import requests as cffi_requests

import json, time

PROXY = "http://[2a01:4f8:1c1c:abcd::1]:3128"

VIDEO_ID = "dQw4w9WgXcQ"

def fetch_comments(video_id, continuation=None):

url = "https://www.youtube.com/youtubei/v1/next?prettyPrint=false"

payload = {

"context": {

"client": {

"clientName": "WEB",

"clientVersion": "2.20240101.00.00",

"hl": "en",

"gl": "US"

}

},

"videoId": video_id

}

if continuation:

payload["continuation"] = continuation

else:

payload["continuation"] = None

r = cffi_requests.post(

url,

json=payload,

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

impersonate="chrome120",

timeout=20

)

if r.status_code == 429:

raise RuntimeError("rate limited")

return r.json()

def extract_continuation(data):

try:

actions = data["onResponseReceivedEndpoints"]

for a in actions:

if "appendContinuationItemsAction" in a:

items = a["appendContinuationItemsAction"]["continuationItems"]

for item in items:

if "continuationItemRenderer" in item:

return (item["continuationItemRenderer"]

["continuationEndpoint"]["continuationCommand"]["token"])

except (KeyError, TypeError):

pass

return None

```

Логика простая: первый вызов без токена возвращает первую порцию и токен для следующей. Дальше крутишь цикл, пока токен не кончится. Каждые 10 запросов — смена прокси из пула. Важно: токен привязан к IP, с которого пришёл. Сменил прокси — начни сессию заново с `videoId`, не с токена.

Ротация: sticky vs per-request

Два режима. Sticky — один IP держится на всю сессию парсинга одного видео. Нужен, когда листаешь комментарии по токену. Per-request — новый IP на каждый запрос. Годится для независимых вызовов `player` или `browse`.

На практике удобно держать два пула. Sticky-пул на 10-15 адресов для глубокого листания комментов. Round-robin пул на 50+ адресов для параллельного сбора метаданных по списку видео.

Если сервис прокси даёт /64-блок целиком, ротация внутри блока бесплатна. Меняешь последние 64 бита — получаешь новый адрес. Но Google видит /64 как одну подсеть и суммирует репутацию. Так что реальная ротация — это разные /64, а не разные адреса внутри одного /64.

Кейс: парсинг 40 000 комментариев с канала-миллионника

Задача — собрать все комментарии под 30 последними видео крупного канала. Суммарно около 40 000 штук. Первая попытка: один IPv6-адрес, `aiohttp`, 20 потоков. Через 12 минут — сплошные 429, собрано 3 200 комментариев.

Причина: 20 потоков с одного адреса = 20 запросов `next` в секунду в пике. Google обрабатывает это как атаку. Плюс `aiohttp` шлёт JA3, несовпадающий с заявленным Chrome UA — расхождение ловится на TLS-уровне.

Решение: пул из 12 разных /64-подсетей, sticky-сессии по 8 запросов на адрес, `curl_cffi` с `impersonate="chrome120"`, задержка 1.5-2 секунды между запросами внутри сессии. Собрали 38 700 комментариев за 4 часа 20 минут. Потерь около 3% — на видео с отключёнными комментариями и удалёнными ветками. 429 встретился 14 раз, каждый раз лечился сменой подсети и рестартом сессии с начала видео.

Аналитика каналов: что тянем и откуда

Метаданные канала лежат в `browse` с `browseId=UCxxxx`. Оттуда достаём: количество подписчиков, описание, ссылки, список вкладок. Список видео — через `browse` с параметром `params`, закодированным base64. Вкладка Videos кодируется как `EgZ2aWRlb3PyBgQKAjoA`.

```bash

curl -x "http://[2a01:4f8:1c1c:abcd::5]:3128" \

-X POST "https://www.youtube.com/youtubei/v1/browse?prettyPrint=false" \

-H "Content-Type: application/json" \

-H "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36" \

-d '{

"context": {"client": {"clientName": "WEB", "clientVersion": "2.20240101.00.00"}},

"browseId": "UC_x5XG1OV2P6uZZ5FSM9Ttw",

"params": "EgZ2aWRlb3PyBgQKAjoA"

}' -o channel_videos.json

```

Ответ — JSON с `richItemRenderer` для каждого видео: `videoId`, `title`, `viewCountText`, `publishedTimeText`. Пагинация — через `continuationCommand.token`, тот же механизм, что с комментариями.

Тонкость: `viewCountText` приходит строкой вида `"1.2M views"`. Парсить надо с учётом локали — при `hl=ru` будет `"1,2 млн просмотров"`. Фиксируй `hl=en` в context, иначе словишь зоопарк форматов.

Ошибки, которые ломают весь пайплайн

Самая частая — игнорирование `visitorData`. Google выдаёт его в первом ответе на `player` или `browse` в поле `responseContext.visitorData`. Если не передавать его в следующих запросах, сессия считается невалидной и токены протухают быстрее. Всегда сохраняй visitorData и суй в `context.client.visitorData`.

Вторая — параллельные запросы с одного IP на разные видео. Даже с валидным visitorData это выглядит как бот. Один адрес — одно видео за раз.

Третья — использование HTTP/1.1. YouTube по v6 почти всегда отдаёт HTTP/2. Клиент на HTTP/1.1 с тем же JA3 палится моментально. `curl_cffi` и `httpx` умеют HTTP/2, `requests` — нет.

Когда прокси недостаточно

Если задача — собирать данные с тысяч каналов ежедневно, чистого IPv6-пула мало. Нужны: ротация User-Agent по реальным версиям Chrome (раз в 2-3 недели Google выкатывает новую), эмуляция полного профиля (cookies `CONSENT`, `VISITOR_INFO1_LIVE`), рандомизация таймингов. Прокси-слой решает только проблему IP-репутации, остальное — на клиенте.

Для средних задач (до 100 000 запросов в сутки) хватает пула на 30-40 /64-подсетей и дисциплины в клиенте. Провайдер вроде lexic.ml отдаёт /64-блоки с возможностью ротации внутри, что удобно для sticky-сессий — не нужно дёргать API за новым адресом на каждый запрос.

Итог по цифрам

Средний пайплайн на 50 000 комментариев в сутки: 15-20 /64-подсетей, sticky по 6-10 запросов, `curl_cffi`, задержка 1.5-2 с. Укладывается в 3-4 часа при 10 параллельных воркерах. Без прокси с одного адреса — 3000 комментариев и бан через 10 минут. Разница в 15 раз по объёму и в 40 раз по времени до первого 429.

Главное — не гнаться за скоростью. YouTube банит не за объём, а за ритм. Ровный поток с паузами живёт часами. Рваный пик в 50 rps убивает сессию за минуту.

✔️Купить прокси