Итак, в своей предыдущей статье я подробно описал, как я парсил Ютуб и как спарсил более 300к видео за примерно 4 дня используя официальную документацию АПИ. Подробно можете ознакомиться с этой статьей по ссылке — парсинг Youtube.
Теперь пришло время разобраться, что же со всем этим спаршеным добром делать. Вот у меня порядка 17 заполненых столобцов в 300+к строках и с ними нужно что то делать, не проверять же их вручную, насколько каждое видео соответсвует ключевому запросу, по которому он был собран.
Как говориться:
Ну я на самом деле уже придумал и реализовал, у меня получилась двухступенчатая система проверки, но в дальнейшем я решил остановиться на первой, как менее затратной, а вторую просто не стал использовать. Там еще правда были проблемы со скачиванием видео, но обо всем по порядку, я обязательно дойду до третьей части, а сейчас мы с вами находимся только на второй. Не мнее интересной, как мне кажется.
Итак, я решил пойти по пути проверки тайтлов и дескрипшнов у каждого видео, для чего был создан скрипт, который выполняет проверку каждого видео. Теперь давайте подробно рассмотрим что из себя представляет данный скрипт. Кстати, скрипт уже доступен в моем Github — если вдруг интересно поюзать — добро пожаловать!
- Разбор скрипта для проверки релевантности видео
- Назначение и общая схема работы
- Конфигурация через .env — что должно быть в файле, чтобы скрипт заработал
- Авторизация и загрузка данных
- Нормализация и разметка спама
- Вычисление Relevance
- Контекстная модификация ключа и RelevanceContextual
- Запись результатов
- Логирование
- Зависимости
Разбор скрипта для проверки релевантности видео
Скрипт загружает данные с листа Google Sheets, нормализует текст роликов YouTube, отсеивает нерелевантные записи (спам-тематика, музыкальные клипы), рассчитывает две метрики релевантности — Relevance и RelevanceContextual (при наличии правил контекстной подстановки ключевого слова) — и сохраняет результаты обратно в тот же лист. Все параметры (ID таблицы, пути к учётным данным, наборы стоп-слов, контекстные правила) задаются через .env.
Вот результат работы данного скрипта — два последних столбца — это score который скрипт вычислил для каждого видео:

Назначение и общая схема работы
- Чтение конфигурации из
.env. - Авторизация в Google Sheets по сервисному аккаунту.
- Загрузка данных в
pandas.DataFrame. - Нормализация текстовых полей и маркировка спам-строк.
- Расчёт базовой метрики
Relevance. - (Опционально) модификация ключевого слова с учётом контекста и расчёт
RelevanceContextual. - Запись новых столбцов в лист одной пакетной операцией.
- Логирование всех этапов и времени выполнения.
Конфигурация через .env — что должно быть в файле, чтобы скрипт заработал
| Переменная | Назначение |
|---|---|
SHEET_ID | ID таблицы Google Sheets |
WORKSHEET_NAME | Имя листа (worksheet) |
CREDENTIALS_JSON_PATH | Путь к JSON-файлу сервис-аккаунта |
SPAM_KEYWORDS | Список ключевых слов спама, через запятую |
CONTEXT_COLUMN_NAME | Колонка, содержащая контекст (например, Country) |
CONTEXT_TRIGGER_WORDS | Слова-триггеры, которые подлежат замене/дополнению |
CONTEXT_DEFAULT_APPEND_WORD | Слово для добавления, если замена не найдена |
CONTEXT_REPLACEMENT_<context> | Пары «контекст → слово-замена» (например, CONTEXT_REPLACEMENT_italy=spiaggia) |
Файл .env обязателен; при отсутствии требуемых переменных скрипт завершится с ошибкой.
Авторизация и загрузка данных
gc = gspread.service_account(filename=config['credentials_path'])
worksheet = gc.open_by_key(config['sheet_id']).worksheet(config['worksheet_name'])
rows = worksheet.get_all_values()
df = (pd.DataFrame(rows[1:], columns=[h.strip() for h in rows[0]])
.fillna('')
.astype(str))
Используется клиент gspread с сервисным аккаунтом; данные загружаются полностью одним запросом.
По факту это самая простая часть — скрипт забирает нужные для авторизации данные и авторизуется (главное, чтобы данные были корректны и имелись в .env).
Вообще, у меня все эти данные были напрямую загружены в самом скрипте, но я собрал все немного более аккуратнее.
Нормализация и разметка спама
normalize_text: диакритика → ASCII → lower → strip.extract_first_sentence: первая законченная фраза из описания.is_music_or_lyrics: Heвристика для роликов с субтитрами-караоке (брекеты[Chorus], короткие строки).check_spam: поиск шаблонов спама + проверка музыкальных роликов.- Результат сохраняется в колонку
is_spam.
Тут чуть сложнее, но эта часть скрипта нужна для того, чтобы исключить ошибки при сопоставлении данных, к примеру скрипт возьмет ключевое слово с пробелом, а в тайтл оно будет без пробела и score будет расчитан некорректно. Собственно спам слова нужны, чтобы уже на первоначальном этапе убрать то, что заведомо не подойдет. В моем случае было куча рекламных роликов, которые имели общие паттерны, и без проверки на спам было много ложно-положительных срабатываний.
Вычисление Relevance
- Отбор строк
~is_spam & norm_keyword != ''. - Группировка по ключевому слову.
- TF-IDF-векторизация (
HashingVectorizer → TfidfTransformer, биграммы, 5000 фич). - Косинусное сходство запроса-ключа к каждому документу.
- При наличии ключа в первой фразе описания оценка повышается на
+0.1, максимум1.0.
Самая важная часть скрипта — тут и происходит та самая магия, но вероятно можно что-то и докрутить, я пока не придумал что конкретно. Итак — скрипт берет ключевое слово и оценивает насколько видео ему соответсвует. Предварительно мы уже поудаляли видео спамного и нерелевантного характера и теперь нужно оценить оставшиеся видео. Что делает скрипт — он вычисляет на основании семантической схожести (насколько это возможно сделать) соответсвие. Я посчитал так — если ключ есть в Тайтл, то это наличие должно давать + 0,1 к score, также, если ключ есть в первом предложении дескрипшн, то это также дает немного буста к общему score.
Да, немного SEOшный подход, но и вы ведь не знаете с чего я начинал, правда? В итоге получаем какой то score, который далее будем анализировать.
Контекстная модификация ключа и RelevanceContextual
Функция-модификатор создаётся, если в .env определены:
- слова-триггеры (
CONTEXT_TRIGGER_WORDS), - карта замен (
CONTEXT_REPLACEMENT_*) или слово по умолчанию (CONTEXT_DEFAULT_APPEND_WORD).
Алгоритм:
- Читается значение столбца
context_column(например,Country) и нормализуется. - Если ключ содержит триггерное слово, оно заменяется на слово-замену;
иначе к ключу добавляется замена/слово по умолчанию. - Полученный модифицированный ключ используется в расчёте второй метрики.
Это опциональная часть, я ее включил из-за того, что у меня была сильная локальная зависимость и необходимо было делать замену ключевого слова на важные для меня языки. Пример, был ключ воды на русском, нужно было проверить этот же ключ на испанском, немецком и английском. Скрипт удалял русское название и менял на испанское (немецкое и тд) — в зависимости от того, какая страна им распознавалась в столбце Country.
Важное уточнение, названия стран должны быть приведены к шаблонному виду — то есть к общепринятому обозначению.
Вы можете допилить свою логику, скрипт проверки поставляется как есть.
Собственно дальше скрипт создавет второй столбец и также проставляет score точно так же, как и в первом случае (но с модифицированным ключом).
Запись результатов
columns_to_write = ['Relevance', 'RelevanceContextual'] # либо только 'Relevance'
worksheet.append_cols([[col] for col in new_cols]) # при необходимости
worksheet.batch_update([
{'range': 'X2:X1001', 'values': df[['Relevance']].values.tolist()},
...
])
- При отсутствии нужных столбцов они добавляются в шапку.
- Данные передаются пакетно (
batch_update), что сокращает число API-запросов.
Логирование
logging.basicConfig — формат YYYY-MM-DD HH:MM:SS - LEVEL - message.
Все ключевые этапы (авторизация, загрузка, предобработка, расчёты, запись) отражаются в логе; по завершении выводится общее время работы.
Зависимости
pandas
gspread
python-dotenv
scikit-learn
Установите через pip install -r requirements.txt, где requirements.txt содержит перечисленные пакеты.
Скрипт предназначен для автономной, конфигурируемой оценки релевантности YouTube-роликов к заданным ключам, поддерживает гибкие правила спам-фильтрации и контекстные трансформации ключевых слов.
Теперь еще раз более простым языком — скрипт открывает таблицу, где собраны все спаршенные данные и работает внутри этой таблицы.
Сперва приводит все требуемые для работы данные в единый регистр, убирает все лишнее, и вытягивает из заголовка первую фразу, так как она имеет значение для сравнения и установки score видео в дальнейшем.
Чистит мусорные видео, чтобы не тратить на них время (список мусорных слов необходимо задавть самостоятельно). Таким видео скрипт присваивает нулевой score.
Как измеряет «похожесть» на ключевое слово
- каждое видео превращает в набор чисел (TF-IDF-вектор);
- то же делает с ключевым словом;
- считает косинусное сходство: чем ближе к 1, тем больше ролик «про то самое».
- если ключевое слово встречается в первой фразе описания, добавляет небольшой бонус.
Далее есть небольшой опциональный кусок — это я использовал в своем наборе, так как было много локальных языков и нужно было проверять ключевое слово на локальном языке, то есть скрипт может проверить, выполняется ли условие для проверки и проверить. Выводит соответсвенно второй столбец. В простом варианте будет достаточно первого столбца.
Ну и все, далее опытным путем я обнаружил, что видео со score выше 0,5 имеют процент брака 5% и этот результат меня полностью устроил. Можно дополнительно руками проверить видео от 0,5 до 0,15 — но для этого у меня тоже есть некоторое решение, но более замороченное. Опишу его в следующем кейсе. Там уже подключается GPT за денежку.

Таким образом из общего списка в 300к видеороликов после прогона по данному алгоритму осталось 5000 видео со score 0,5 и выше и процентом брака 5% (это я выяснил путем ручной проверки). Видео со score от 0,5 до 0,15 осталось около 48к -но тут уже процент брака выше, от 10 до 15%, что для меня не приемлимо. Эту выборку можно прогнать через второй этап проверки, о нем в следующей статье.








