Дорогой дневник... или как я вновь начал учиться, заметки начинающего питониста
Короткий блок о себе и почему это здесь
Идея что-то изменить в своей жизни родилась у меня в конце 2021. Идет третий десяток нового тысячелетия, четвертый моей собственной жизни. А за плечами, ВУЗ и специальность по которой не работал ни дня, сложное заболевание и инвалидность, отсутствие перспектив…
Как-то справившись с прострацией, от того что моя жизнь изменилась и больше никогда не станет прежней, на что мне потребовалось шесть лет(О_О), я очутился в точке 26 декабря 2021. Именно тогда родилась идея «стать программистом». Из смежных знаний по теме были лишь хорошие навыки работы в unix среде и благополучно забытый курс алгоритмизации в ВУЗе.
Начальные этапы я освещать не буду. Это все и так очевидно. Алгоритмы, структуры данных, десятки часов в день за литературой и первые попытки что-то написать на python, а также тренировки на codewars… И к концу февраля я уже почти выгорел от взятого темпа.
Возможно, вся история на этом бы и закончилась, я бы постепенно терял мотивацию, и в конечном счете забросил бы все. Никогда не пытайтесь "победить проблему" постоянным вливанием огромного количества времени. Особенно если проблема — обучение чему-то новому. Но случилось 24 февраля. Сон прервался нетипичной активностью родственников и звуками далеких разрывов. Затем новая прострация, смешанная со страхом, на два месяца. В итоге страх до сих пор никуда не ушел, но притупился. За это время я сделал ряд важных для себя выводов об ошибках в организации обучения и в мае подошел иначе к процессу.
Идея начать вести «мой блог» на DTF возникла из постов dtf.ru/u/590177-ali Ведь написать о том, что ты делал — хороший способ повторить и закрепить полученные навыки и знания. Не переживайте, "ронять сосиску" каждый час я не буду, да и в целом в "Свежее" только избранные посты по тематике портала отправлять буду("Игровая физика на python", мини спойлер), остальное "только для подписчиков", т.е. меня самого).
P.S. Качество кода, которое тут будет появляться - за гранью, надеюсь оно будет расти(регулярно перечитываю pep’ы), но этот процесс может происходить не так быстро как хотелось бы. Любая критика приветствуется, в том числе навыков владения русским. Несмотря на то, что это мой родной язык, учить его приходилось не в школе(он был лишь один год как предмет), а самостоятельно. И этот процесс, так же как и обучение программированию далек от завершения.
Собственно код
Вступление вышло не таким коротким, как хотелось бы. Начнем кодить. Как писал выше, посты Ali, подтолкнули меня потренироваться и создать простую страничку-трекер посмотренных фильмов, сериалов. Безусловно, кинопоиск, imdb и другие сайты агрегаторы, имеют такой функционал. Но для этого и существуют учебные проекты, чтобы изобретать свой велосипед, да и что если мы захотим смешать данные из двух источников или сделать функционал еще не реализованный на агрегаторах?
Еще одно маленькое уточнение, мы будем работать не напрямую с api агрегатора(в данном случае imdb) , а с готовым модулем оборачивающим наши запросы в понятную серверу amazon форму. В непосредственно api imdb мы погрузимся в следующий раз.
Далее код с разъяснениями
Необходимые импорты, подробнее о том, что это мы остановимся когда встретим это в коде.
Инициируем Фласк и и модуль через который мы будем обращаться к imdb. Веб документация по модулям Cinemagoer и Flask.
Основная функция для поиска по ключевому слову. @app.route — декоратор что это и зачем нужно, подробно описано в документации. В данном же случае декоратор изменяет поведение функции index, так чтобы возвращаемое ею значение было в формате http запроса и позволило нам просто работать с веб сервером созданным Flask. if request.method == 'POST' and request.form['search'] — проверка того, что мы отправили post запрос, и в этом запросе есть не пустая форма search с ключевым словом по которому будет происходить поиск. В противном случае мы просто вернем шаблон этой же страницы без изменений. initial_search = ia.search_movie(request.form['search']) — непосредственно поиск по переданному ключевому слову с помощью метода search_movie из модуля Cinemagoer
movie_list — создание переменной в которой мы будем хранить и передавать на страничку выбранные данные.
Затем в цикле for i in initial_search проходим по ответу на наш запрос, каждая итерация цикла — информация по одному фильму. Собирая в movie_list необходимую для дальнейшей передачи данные, для отрисовки страницы в браузере с поисковой выдачей. Чтобы сформировать список фильмов отвечающих нашему поисковому запросу, нам нужны: постер, название фильма, а также id этого фильма в базе imdb, для получения дополнительной информации о каждом конкретном кинофильме. В блоке if i[«cover url»] мы проверяем в ответе imdb наличие ссылки на постер. Изначально, в этом поле ссылка на уменьшенный постер, для полно размерного нам придется немного поработать над url
Начнем с конца, если в ответе сервера нет изображение, задаем переменную poster_url как None, а вместо ссылки на скачанную на наш сервер обложку(это немного ниже) — задаем ссылку на лежащий на сервере файл "по умолчанию". poster_suffix переменная в которую мы положем расширение нашего файла. Все просто, если мы получили какую-то строку в поле 'cover url', то там всегда будет такой формат "ссылка.расширение". Так что блок try except тут не нужен, но пусть будет. В итоге мы ищем точку начиная просмотр url справа и как только находим берем срез по найденному индексу от точки до конца ссылки. Вся полученная строка — наше расширение. С префиксом, т.е. самой ссылкой сложнее. В ней может быть символ '@' до которого, включая его ссылка ведет на полноразмерный постер, так и полное отсутствие символа собаки если полноразмерного постера у фильма нет. Поэтому, тут блок try except необходим, если в ссылке отсутствует символ '@' мы берем ее всю, как ссылку на постер, если символ есть — берем срез отбрасывая правую часть. И сразу же создаем переменную с путем до постера на нашем сервере, мы еще его не скачали, но если мы в этой ветке выполнения программы то url для скачивания у нас уже есть. Путь до файла на нашем сервере нам пригодится, в том числе, для того, чтобы указать программе куда положить скачанный файл. Имя файла при этом, будет состоять из id фильма в базе imdb и ранее полученного префикса.
Еще один интересный момент. В ответе от imdb id у фильмов в одних местах имеют формат вида «111111" в других к этому id впереди добавляется '0', для того, чтобы точно знать что мы отсылаем в качестве запроса и используем в нашей программе, если видим в ответе 'id' первый символ '0» отбрасываем его, если первый символ не ноль то ничего не меняем.
В ранее созданный пустой список movie_list добавляем словарь с названием фильма, его id и ссылками на обложку. Две последние строки, проверяем наличие локального файла с постером на сервере с помощью функции exists, если не находим, то с помощью метода request из модуля urllib скачиваем, передавая ему заранее сохраненный url постера и путь по которому сохраняем файл.
В случае, если мы отправляем поисковый запрос то перенаправляем пользователя на страницу с результатами возвращая функцию redirect('/result') и передавая ей путь на который отправляем пользователя.
Простая функция, которая возвращает render_template и набор параметров movie_list нашему серверу, затем с помощью html и css формируем страницу с результатами поиска. Выглядит это все так:
Функция позволяющая получить больше информации по конкретному фильму.
'/detail/<int:movie_id>' Интересный момент мы получаем нужный нам для поиска id фильма из http запроса. Для этого на странице с результатами формируем ссылку вида <a class="" href="/detail/{{ element['movie_id'] }}"> —{} шаблонизатор jinja позволяющий нам исполнять код python и использовать его для формирования страницы с помощью html. element['movie_id'] — это id конкретного фильма, который мы молучаем пройдясь по всему списку movie_list переданому серверу, опять же с помощью jinja {% for element in movie_list% } {% end for% }. Средствами функции ia. get_movie(movie_id) , которой мы передаем id нашего фильма, мы получаем более подробную информацию о фильме: рейтинги, актерский состав, реценции, бюджет и сборы и т. д. и т. п. куча информации с которой можно работать.
Вот и все, фронтенд части я тут не касался(будто она у меня есть, лол) , да и в беке всего пара функций. Но когда разбираешься с нуля, читаешь доки и в целом имеешь мало опыта, то даже такое требует около четырех часов работы. В дальнейшем цель сделать полноценный кастомный трекер посмотренных фильмов. Но это уже другая история. Весь код доступен на gitlab.
Спасибо всем осилившим сумбурное и криво написанное эссе. Следующий материал будет интереснее и нагляднее, и тематика будет менее офтоповая для DTF. Буду разбираться в методах реализации игровой физики на python.