Здарова, чуваки. Сегодня я расскажу историю одного проекта, который я закончил буквально на днях. Суть его заключалась в следующем: было четыре сайта, с которых нужно было парсить информацию, формировать их в пост, и отправлять через бота в telegram канал. Пообщавшись с заказчиком, я изложил свое видение проекта: для управления постами решили использовать админку Django, парсер и бот, естественно, на Python. Для развертывания будем использовать хостинг fullspace.ru (сто лет с ним работаю, очень привык).
Договорившись с заказчиком, мы пожали руки и я приступил к работе.
Часть первая. Модели Django
Я решил начать с разработки базы данных. Согласовав с заказчиком формат постов (одно сообщение с текстом — куча изображений) я набросал следующие модели:
В общем, тут ничего сложного:
MAGAZIN_CHOICES — это список источников, с которых парсится информация. Их тут пять, но парсить мы будем только четыре из них. (потому что пятый в контексте проекта нормально спарсить не получится, с заказчиком сошлись на том, что он будет его вручную постить)
date_string — это идентификационное поле. В нем будет содержаться эксклюзивная для поста информация, по которой можно будет определить — старый это пост, или новый
message — это текстовое сообщение, которое будет вкидываться на канал до изображений
base_url — ссылка на источник, с которого были собраны данные. Заказчик попросил для удобства
message_id, chat_id — поля, в которых хранится техническая информация о посте. Чуть позже расскажу, для чего.
datetime_post — время, когда нужно вкинуть пост на канал
magazine_type — ну тут понятно, поле показывающее к какому источнику относится пост
is_posted — поле, которое показывает, находится ли пост уже на канале, или еще нет
date_created — поле, показывающее время создания поста в базе данных, используется для сортировки
Модель Image хранит ссылку на пост и ссылку на изображение.
Часть вторая. Функционал бота
В общем, с форматом постов мы определились: это будет короткое сообщение с кучей изображений. Поэксперементировав в самой телеге с постами и погуглив API было решено использовать три функции:
- sendMessage для отправки текстового сообщения
- editMessageText для редактирования текстового сообщения
- sendMediaGroup для отправки кучи изображений
Заранее создав бота и получив секретный ключ для его использования я начал тестировать отправку постов через Python. Написав простые функции для отправки тестового сообщения и изображений я залил данные на уже заказанный клиентом хостинг и начал тестирование. Но… Ничего не работало. Заглянув в логи я увидел ошибку «истекло время ожидания» и тут меня пробил холодный пот: телеграм то заблокирован!
Обратившись в поддержку хостера в поисках каких нибудь штатных средств обхода блокировки мне ответили, что им принципиально пофиг на блокировку, но вот их провайдеру очень даже не пофиг, потому сказали, что ничем помочь не могут.
В голове сразу начали крутиться варианты решения проблемы: сказать клиенту, что нужно заказать другой хостинг? Нет, деньги уже потрачены. Заюзать бесплатные прокси и постоянно их менять? Бред. Купить прокси? Не вариант. Тогда мне в голову пришла следующая идея: можно написать небольшое django приложение, которое будет в роли ретранслятора. Т.е. принимать запросы от моего приложения, перенаправлять их к telegram api, принимать на него ответ и отправлять его моему приложению. Разместить его конечно нужно там, откуда есть доступ к telegram api.
Внимание! Это костыль, и за такое решение у нас в провинции бьют ногами в лицо, поэтому очень не рекомендую повторять это в своих проектах. У меня, благодаря моей врожденной глупости, не осталось выбора. Это был единственный вариант, который не раздувал бюджет. К тому же, посты через бота отправлялись четыре раза в неделю, поэтому этот костыль никак не сыграет на производительности.
В общем, получилось нечто такое:
Немного поясню. Я решил не заморачиваться и для общения с telegram api заюзал библиотеку telepot.
SendPostViews принимает запрос от моего приложения, в котором содержится текст, идентификационная строка и список изображений. Через функциюsendMessage мы отправляем текстовое сообщение на канал. После чего мы смотрим: если изображений больше 10, то делим этот список на части по 10 изображений, и отправляем по очереди. Если нет, то просто отправляем. Сделано это потому, что sendMediaGroup принимает от 2 до 10 изображений, и пост через эту функцию выглядит следующим образом:
Далее мы отвечаем ответом, который мы получили на запрос sendMessage, благодаря чему мы получили message_id и chat_id — идентификационные данные поста, с помощью которых мы можешь его редактировать.
EditPostView выглядит очень просто. Мы получаем из запроса message_id и chat_id, и используем их для редактирования текста в посте. Ответ пересылаем обратно.
Все это дело я по быстрому залил на heroku и протестировал. Работает идеально:
Допиливаем основное приложение
Пришло время реализовать основной функционал в нашем приложении
В наш Topic добавим три функции: is_post, posted и save
is_post скажет нам, готов ли пост по времени к отправке на канал
posted запостит его на канал
save — это переопределение метода сохранения модели. Переопределяем мы его для того, чтобы в случае, если пост уже на канале — отредактировать его не только в модели но и в телеграмме, отправив соответствующий запрос:
Отлично! Осталось спарсить данные в базу данных. Весь код всех источников я приводить не буду, потому как его там на на 150 строк, покажу лишь один пример:
Здесь я юзаю requests для получения страницы для парса и BeautifulSoup для парсинга html. Когда данные загружены в базу данных, всем пользователям (у кого есть доступ в админку) высылается письмо с требованием выставить дату и время постинга на канал.
Далее я создал файл posted.py с следующим содержанием:
Он делает следующее: получаем все посты, которые еще не на канале, проверяем, нужно ли их постить, и если нужно, вызываем posted().
После этого настраиваем на хостинге по крону вызов парсеров раз в сутки и вызов posted_topics() раз в минуту.
На скорую руку делаем html заглушку с просьбой подписаться на канал в телеграме и показываем результат заказчику:
На этом все. Канал посвящен скидкам и акциям киевских супермаркетов Billa, АТБ, Novus, Сiлпо, Велика Кишеня. Возможно будут и другие, так что если кому интересно, обязательно подписывайтесь: https://t.me/foodsalesua
Если понравилась статья, порадуй старину лайком и подпиской на сообщество. Ну а если уж вообще, то можешь даже и поделиться статьей со своими друзьями. Так же пиши в комментариях о чем хочешь следующую статью.
Понравилась статья? Подписывайся на наш паблик вконтакте: https://vk.com/forge_startups
Нажмите "Понравилось" - мы будем знать, что написать для вас в следующий раз
Подпишитесь на канал - наши статьи для вас будут попадаться чаще
Подпишитесь на наш паблик ВК - потому как там все самое интересное
Поделитесь с друзьями - это может быть интересно другим!