Главная » Хабрахабр » [Из песочницы] А сколько вы потратили времени на фильмы?

[Из песочницы] А сколько вы потратили времени на фильмы?

Возникновение идеи

Недавно был в гостях у друзей и мы выбирали фильм, а я как прожжённый киноман (на самом деле, не то чтобы прям прожжённый) отбраковывал всё как просмотренные. И мне задали логичный вопрос, а что ты вообще не смотрел? На что я рассказал, что веду кинопоиск и каждый фильм, которые посмотрел отмечаю либо оценкой, либо просто галочкой, что просмотр состоялся. И тут в голове у меня возник вопрос, а сколько я вообще времени то потратил на фильмы? В Steam есть удобная статистика по игре, а по фильмам ничего такого нет. Вот и решил я заняться данной идеей.

Что там с реализацией?

Я уже несколько лет разрабатываю на ASP.NET и привык к C#, сначала на нём и хотел написать данную утилиту, но тут возникла проблема с тяжеловесным окружением и, так как я немного знаком с Python, именно к его помощи я прибегнул.

А где взять данные?

И вот тут я столкнулся с первой проблемой. Я наивно предполагал, что у кинопоиска есть официальное публичное API и какая-нибудь бесплатная версия. Но ничего такого я не нашёл. Есть возможность запросить через техподдержку, но и там выдают только за n-ую сумму, а я писал это для себя и никак не хотел платить за это.

Естественно, пришлось рассматривать вариант парсинга страниц и именно на нём я и остановился.

image

Таким образом я могу получить всего несколько страниц (У меня 762 фильма и необходимо было получить всего 17 страниц) и рассчитать потраченное время. У каждого в профиле есть список просмотренных фильм с небольшим описанием, которое включает продолжительность картины.

Сказано — сделано.

class KinopoiskParser: def __init__(self, user_id, current_page=1): self._user_id = user_id self._current_page = current_page self._wasted_time_in_minutes = 0 def calculate_wasted_time(self): while True: film_list_url = f'https://www.kinopoisk.ru/user/' \ f'/votes/list/ord/date/genre/films/page/{self._current_page}/#list' try: film_response = requests.get(film_list_url).text except BaseException: proxy_manager.update_proxy() continue user_page = BeautifulSoup(film_response, "html.parser") is_end = kinopoisk_parser._check_that_is_end_of_film_list(user_page) if is_end: break wasted_time = self._get_film_duration_on_page(user_page) self._wasted_time_in_minutes += wasted_time print(f'Page {self._current_page}, wasted time {self._wasted_time_in_minutes}') self._move_next_page() def get_wasted_time(self): return self._wasted_time_in_minutes def _move_next_page(self): self._current_page += 1 @staticmethod def _get_film_duration_on_page(user_page): try: wasted_time = 0 film_list = user_page.findAll("div", {"class": "profileFilmsList"})[0].findAll("div", {"class": "item"}) for film in film_list: film_description = film.findAll("span") if len(film_description) <= 1: continue film_duration_in_minutes = int(film_description[1].string.split(" ")[0]) wasted_time = wasted_time + film_duration_in_minutes return wasted_time except BaseException: print("Something went wrong.") return 0 @staticmethod def _check_that_is_captcha(html): captcha_element = html.find_all("a", {"href": "//yandex.ru/support/captcha/"}) return len(captcha_element) > 0 @staticmethod def _check_that_is_end_of_film_list(html): error_element = html.find_all("div", {"class": "error-page__container-left"}) return len(error_element) > 0

Но уже на этапе отладки я столкнулся с проблемой, что кинопоиск блокирует запросы (примерно, на 4 итерации) и считает их подозрительными. И он ведь прав! Но такой вариант я тоже предполагал и перешёл к плану Б.

План Б — меняем прокси как перчатки

Взяв первый попавшийся сервер, который предоставляет API для получения ip proxy (не рекламирую никакие сервисы, взял первые две ссылки из гугла), криво прикрутил его и продолжил писать основной код. И уже через час, когда я был близок к завершению меня заблокировал и сервер, которые предоставляет API! Пришлось сменить его на другой, который выдаёт фиксированный список, каждые полчаса, для моей задачи этого достаточно. Но если вдруг кончится список, можно вернутся к предыдущему варианту (они выдают каждые 24 часа где-то 10-20 proxy).

class ProxyManager: def __init__(self): self._current_proxy = "" self._current_proxy_index = -1 self._proxy_list = [] self._get_proxy_list() def get_proxies(self): proxies = { "http": self._current_proxy, "https": self._current_proxy } return proxies def update_proxy(self): self._current_proxy_index += 1 if self._current_proxy_index == len(self._proxy_list): print("Proxies are ended") print("Try get alternative proxy") proxy_ip_with_port = self._get_another_proxy() print("Proxy updated to " + proxy_ip_with_port) self._current_proxy = f'http://{proxy_ip_with_port}' return self._current_proxy proxy_ip_with_port = self._proxy_list[self._current_proxy_index] print("Proxy updated to " + proxy_ip_with_port) self._current_proxy = f'http://{proxy_ip_with_port}' return self._current_proxy @staticmethod def _get_another_proxy(): proxy_response = requests.get("https://api.getproxylist.com/proxy?protocol[]=http", headers={ 'Content-Type': 'application/json' }).json() ip = proxy_response['ip'] port = proxy_response['port'] proxy = f'{ip}:{port}' return proxy def _get_proxy_list(self): proxy_response = requests.get("http://www.freeproxy-list.ru/api/proxy?anonymity=false&token=demo") self._proxy_list = proxy_response.text.split("\n")

Соединив всё это вместе (в конце приведу ссылку на гитхаб с конечной версией), я получил отличную штуку для подсчёта времени потраченного на фильмы. И получил заветное число, тадам: «You wasted 84542 minutes or 1409.03 hours or 58.71 day».

Зря потратил время для подсчёта зря потраченного времени

На самом деле, не зря. Задача была интересная, хоть и вряд ли нужная хоть кому-то.
Да и теперь я могу всем говорить, что, почти, два месяца своей жизни я занимался просмотром кино!

Если кому-то будет тоже интересно получить такую «важную» статистику для себя, просто скопируйте id своего профиля и запустите проект с этим параметром и если несложно скиньте в комментарии результат, мне интересно «киноман» я или любитель начинающий.

Ссылка на исходный код

S. P. Также буду рад услышать советы по улучшению кода, так как на питоне писал очень мало и даже синтаксисом владею не в полной мере.


Оставить комментарий

Ваш email нигде не будет показан
Обязательные для заполнения поля помечены *

*

x

Ещё Hi-Tech Интересное!

[Перевод] Учебный курс по React, часть 1: обзор курса, причины популярности React, ReactDOM и JSX

Представляем вашему вниманию первые 5 занятий учебного курса по React для начинающих. Оригинал курса на английском, состоящий из 48 уроков, опубликован на платформе Scrimba.com. Возможности этой платформы позволяют, слушая ведущего, иногда ставить воспроизведение на паузу и самостоятельно, в том же ...

[Перевод] Разбираем лямбда-выражения в Java

Мы открыли его для себя совсем недавно, но уже по достоинству оценили его возможности. От переводчика: LambdaMetafactory, пожалуй, один из самых недооценённых механизмов Java 8. 0 фреймворка CUBA улучшена производительность за счет отказа от рефлективных вызовов в пользу генерации лямбда ...