Как сэкономить деньги, время (и окружающую среду) с помощью Python
Не редко мы сталкиваемся с тем, что закачиваем приложения на свои устройства, например, которые нам предоставляют команды тренировок. И даже оформляем подписки на данные программы/приложения. План состоит в том, чтобы вы могли смотреть программу тренировок, находясь в зале. Но также можете столкнуться с тем, что программа представляет из себя просто набор видео с YouTube.
И тут в голове может возникнуть вопрос: «Почему бы не скачать эти видео и не отменить подписку?»
Но так как, приложение может оказаться платным, а наша задача не потратить финансы, мы можем попробовать бесплатную версию. Тем самым мы натыкаемся на проблему, связанная с кучей объявлений и реклам.
Избежать эту проблему, возможно, можно попробовав загрузить видео с помощью кода Python.
Моральные принципы
Чтобы не чувствовать вину за загрузку видео, в оправдание можно озвучить, что предоставленный продукт не работает как модель подписки.
Просто кажется неправильным платить денежные средства каждый месяц за доступ к существующей библиотеке видео на YouTube с несколькими новыми дополнениями каждый месяц. Видео YouTube, к которым вы, вероятно, все еще можете получить доступ без подписки, если вы где-то храните идентификаторы.
В отчаянной попытке отвести вину, они сами виноваты в том, что сделали продукт, который можно просто скачать. Это как оставить свои ценности лежать во дворе.
Вернемся к теме
Рассмотрим пункты в названии по отдельности. Сэкономить. После загрузки всех видео, нам не пришлось бы продолжать оплачивать подписку, тем самым сохраняя бюджет. Но тем самым пропускаем новый контент. Есть возможность вернуться в приложение снова, загрузить новые видео и снова выйти.
Сэкономить время. Если же оставаться в приложении или же смотреть видео напрямую в YouTube, продолжались бы просмотры объявлений и рекламы. Что тоже не маловажно для пользователя. Кроме того, время, потерянное из-за проблем с буферизацией, также будет сэкономлено.
Окружающая среда. Есть видео, которые нам нравятся, и с тех пор мы можем смотреть их несколько раз. Если бы мы транслировали это видео несколько раз, серверы должны были бы предоставить это нам, а инфраструктура передачи должна была бы передать это нам. Это требует электричества и оставляет углеродный след. Если этого избежать, окружающая среда сохраняется (чуть-чуть).
С большой вероятностью наш мыслительный процесс слишком упрощен.
Код
Необходимо решить три основные проблемы:
- Как получить доступ в веб-сайту продукта?
- Как можно извлечь идентификаторы видео с указанного веб-сайта?
- Как скачать данные видео?
Чтобы быстро подвести итог:
- Первая проблема была решена с помощью пакета запросов и предоставления учетных данных активного сеанса в виде файлов cookies и headers.
- Вторая проблема была решена с помощью пакета BeautifulSoup4 для выполнения некоторого - crude - синтаксического анализа html.
- Последняя проблема решалась с помощью pytube, которая упрощает загрузку видео YouTube.
Приведем подробности в следующих разделах.
Как попасть внутрь системы
Нам может помочь:
import requests
awesome = requests.get('https://topjer.net')
Запуск фрагмента кода обычно приводил к коду возврата 200 - huge success - и полному доступу к коду веб-сайта.
Тем не менее, веб-сайт потребовал аутентификации. Вместо блестящих 200 мы можем получить мрачные 403. В этом случае можно перейти на stackoverflow.
Решение, которым мы воспользовались, заключалось в том, чтобы перейти на вкладку network в инструментах разработчика браузера после входа в систему и извлечение запроса в виде cURL. Это может быть скопировано в https://curlconverter.com/ и это создаст код Python, необходимый для доступа к сайту.
Теперь код примерно выглядит так, с файлами COOKIES и HEADERS, взятыми прямо с ранее упомянутого веб-сайта.
response = requests.get(CURRENT_URL + '/index', cookies=COOKIES, headers=HEADERS)
Это решение самое благоприятное. Они работают с первой попытки и не требуют он нас понимания того, что происходит внутри системы.
Должно ли нас беспокоить то, что введена потенциально конфиденциальная информация на какой-то случайный веб-сайт? Ответ отрицательный. Потому что примечание о конфиденциальности на веб-сайте обещает, что все происходит в нашем браузере и никакая информация никуда не отправляется.
Извлечение идентификатора видео
То что мы имеет сейчас - это чистый html-код, настолько полных заостренных «>» и «<», что можно навредить себе, если смотреть на них долго.
Для перехода на библиотеку Python мы используем: BeautifulSoup.
Beautiful Soup — это библиотека Python для извлечения данных из файлов HTML и XML. Он работает с вашим любимым синтаксическим анализатором, предоставляя идиоматические способы навигации, поиска и изменения дерева синтаксического анализа. Это обычно экономит часы или дни работы программистов.
Наш сложный рабочий процесс будет выглядеть следующим образом:
- Загружаем веб-сайт на нашем веб-браузере:
- Щелкаем правой кнопкой мыши интересующий нас объект и выбираем «Проверить»:
- С помощью элемента, выделенного в html-коде веб-сайта, попытаемся идентифицировать родителей с помощью уникальных тегов, чтобы перейти к элементу:
- При необходимости повторяем процедуру.
Структура, на которую мы ориентируемся в нашем случае:
На стартовой странице было несколько выпадающих меню. Третий содержал записи, которые привели бы нас на сайт с видео, которые нам и нужны.
Что нам предстоит сделать:
- Найти все выпадающие меню и нполучить содержимое третьего
- Извлечь все ссылки из указанного выпадающего меню
- Просмотреть список ссылок и в каждом случае найти встроенное видео YouTube и извлечь ID.
Давайте взглянем на некоторые фрагменты кода. Обратите внимание, что это не тот фактический код, который мы используем. Это просто предназначено для того, чтобы показать функциональные возможности с которыми мы работали.
from bs4 import BeautifulSoup
soup = BeautifulSoup(html_mess, "html.parser")
dropdown_menus = soup.find('div', class_='col-xs-12').findAll('li', class_='dropdown')
movement_menu = dropdown_menus[2]
entries = movement_menu.findAll(lambda tag: tag.name == 'li' and tag.has_key('data-post_id'))
for entry in entries:
video_source_id_raw = entry.contents[0]['data-video_source_id']
Поскольку это не подробное руководство по BeautifulSoup, кратко объясним, какова цель нашего кода.
Первым шагом является синтаксический анализ html-строки, которая в нашем случае исходит из «response.content».
Чтобы найти нужные нам теги, в основном используются функции «find» и «findAll». Если требуется только первый тег, соответствующий описанию, используйте «find». Если все экземпляры представляют интерес, используйте «findAll» (или «find_All»).
Перовый аргумент который вы должны указать - это тип тега, т. е. первое что идет после «<», а затем любая подходящая комбинация атрибутов.
В нашем случае достаточно найти атрибут класса тега. Но также можно предоставить функцию, которая возвращает True или False. Здесь мы используем lambda-функции, которые проверяют, является ли тег «li» и имеет ли тег атрибут «data-post_id».
Обратите внимание, что результатом функции find снова является объект Soup, поэтому можно выполнять несколько последовательных поисков.
Если вы хотите просмотреть список прямых дочерних элементов тега, то есть всех тегов верхнего уровня внутри указанного тега, используйте атрибут «contents».
Если вы хотите получить доступ к значению данного атрибута, то вы можете сделать это так, как если бы объект soup был словарем, как мы делаем это в последней строке.
Обеспечение качества
После того, как самая сложная работа выполнена, мы можем перейти к самой интересной части. Загрузка самих видео. Задача, которая довольно проста благодаря напряженной работе других людей.
Существует такой пакет «Pytube», который заботится обо всем. Вот весь код, который нам нужен:
from pytube import YouTube
video = YouTube('https://www.youtube.com/watch?v=' + video_id)
stream = video.streams.filter(file_extension='mp4', resolution='720p', progressive=True).first()
title = video.title.replace(' ', '_') + '.mp4'
file_path = stream.download(filename=title, output_path='./downloads/')
Сначала вы «connect» к видео: указав его URL. Затем вы можете получить список всех доступных потоков через «video.stream». Этот список может быть отфильтрован по различным атрибутам, таким как расширение файла или разрешение.
Один комментарий к атрибуту «Progressive=True». Если вы посмотрите видео, вы заметите, что у большинства из них есть «Progressive=True». Это означает, что для большинства потоков аудио и видео разделены. В этом случае вам придется загружать видео и аудио отдельно и в последствии объединять их.
Мы же будем надеяться на поток «Progressive=True». Затем выбираем первый полученный результат, удаляем пробелы из заголовка и приступаем к загрузке видео.
К сожалению, по умолчанию вы не получите подробной информации о текущем ходе загрузки. Код просто останавливает выполнение до завершения загрузки. Похоже, вы могли бы предоставить функцию обратного вызова по ходу загрузки и, Таким образом, получить некоторое представление о том, сколько осталось загрузить.
Дополнительный бонус: Загрузка музыки
Небольшие модификации приведенного выше кода позволят вам загружать только звуковую дорожку видео. Идеально, если вы хотите скачать музыку.
video = YouTube('https://www.youtube.com/watch?v=' + video_id)
title = video.title.replace(' ', '_') + '.webm'
file_path = video.streams.filter(mime_type="audio/webm").last().download(filename=title)
Все, что вам нужно сделать, это сменить фильтр. В наших примерах надежнее всего было проверить «mime_type», а поскольку mp3 не всегда был доступен, используем «webm».
Теперь у вас должны быть все части, чтобы склеить свой собственный инструмент для извлечения идентификаторов видео youtube с веб-сайта, а затем загрузить их.