Проверка релевантности видео, полученных при помощи парсинга Ютуба — применение TF-IDF + косинусного сходства

Логотип статьи про чекер Кейсы

Итак, в своей предыдущей статье я подробно описал, как я парсил Ютуб и как спарсил более 300к видео за примерно 4 дня используя официальную документацию АПИ. Подробно можете ознакомиться с этой статьей по ссылке — парсинг Youtube.

Теперь пришло время разобраться, что же со всем этим спаршеным добром делать. Вот у меня порядка 17 заполненых столобцов в 300+к строках и с ними нужно что то делать, не проверять же их вручную, насколько каждое видео соответсвует ключевому запросу, по которому он был собран.

Как говориться:

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

Итак, я решил пойти по пути проверки тайтлов и дескрипшнов у каждого видео, для чего был создан скрипт, который выполняет проверку каждого видео. Теперь давайте подробно рассмотрим что из себя представляет данный скрипт. Кстати, скрипт уже доступен в моем Github — если вдруг интересно поюзать — добро пожаловать!

Разбор скрипта для проверки релевантности видео

Скрипт загружает данные с листа Google Sheets, нормализует текст роликов YouTube, отсеивает нерелевантные записи (спам-тематика, музыкальные клипы), рассчитывает две метрики релевантности — Relevance и RelevanceContextual (при наличии правил контекстной подстановки ключевого слова) — и сохраняет результаты обратно в тот же лист. Все параметры (ID таблицы, пути к учётным данным, наборы стоп-слов, контекстные правила) задаются через .env.

Вот результат работы данного скрипта — два последних столбца — это score который скрипт вычислил для каждого видео:

Назначение и общая схема работы

  1. Чтение конфигурации из .env.
  2. Авторизация в Google Sheets по сервисному аккаунту.
  3. Загрузка данных в pandas.DataFrame.
  4. Нормализация текстовых полей и маркировка спам-строк.
  5. Расчёт базовой метрики Relevance.
  6. (Опционально) модификация ключевого слова с учётом контекста и расчёт RelevanceContextual.
  7. Запись новых столбцов в лист одной пакетной операцией.
  8. Логирование всех этапов и времени выполнения.

Конфигурация через .env — что должно быть в файле, чтобы скрипт заработал

ПеременнаяНазначение
SHEET_IDID таблицы 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

  1. Отбор строк ~is_spam & norm_keyword != ''.
  2. Группировка по ключевому слову.
  3. TF-IDF-векторизация (HashingVectorizer → TfidfTransformer, биграммы, 5000 фич).
  4. Косинусное сходство запроса-ключа к каждому документу.
  5. При наличии ключа в первой фразе описания оценка повышается на +0.1, максимум 1.0.

Самая важная часть скрипта — тут и происходит та самая магия, но вероятно можно что-то и докрутить, я пока не придумал что конкретно. Итак — скрипт берет ключевое слово и оценивает насколько видео ему соответсвует. Предварительно мы уже поудаляли видео спамного и нерелевантного характера и теперь нужно оценить оставшиеся видео. Что делает скрипт — он вычисляет на основании семантической схожести (насколько это возможно сделать) соответсвие. Я посчитал так — если ключ есть в Тайтл, то это наличие должно давать + 0,1 к score, также, если ключ есть в первом предложении дескрипшн, то это также дает немного буста к общему score.

Да, немного SEOшный подход, но и вы ведь не знаете с чего я начинал, правда? В итоге получаем какой то score, который далее будем анализировать.

Контекстная модификация ключа и RelevanceContextual

Функция-модификатор создаётся, если в .env определены:

  • слова-триггеры (CONTEXT_TRIGGER_WORDS),
  • карта замен (CONTEXT_REPLACEMENT_*) или слово по умолчанию (CONTEXT_DEFAULT_APPEND_WORD).

Алгоритм:

  1. Читается значение столбца context_column (например, Country) и нормализуется.
  2. Если ключ содержит триггерное слово, оно заменяется на слово-замену;
    иначе к ключу добавляется замена/слово по умолчанию.
  3. Полученный модифицированный ключ используется в расчёте второй метрики.

Это опциональная часть, я ее включил из-за того, что у меня была сильная локальная зависимость и необходимо было делать замену ключевого слова на важные для меня языки. Пример, был ключ воды на русском, нужно было проверить этот же ключ на испанском, немецком и английском. Скрипт удалял русское название и менял на испанское (немецкое и тд) — в зависимости от того, какая страна им распознавалась в столбце 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 за денежку.

Думал, что 95 % точности хватит тебе? Должен ты будешь руками 5 % досмотреть!

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

Оцените статью
autoparse.tech
Добавить комментарий