Начинающие программисты на питоне постоянно натыкаются на уроки о том, как создать бота. И да, боты – это довольно полезная штука, но лишь в том случае, если они еще и выполняют какие-либо полезные функции. С помощью телеграмм-бота можно даже управлять компьютером удаленно. И это не так уж и сложно реализовать. Но, в данной статье мы этого делать не будем. А займемся более прозаическими вещами и все-таки создадим бота, который получает новости. Но в отличии от других мы не будем без ума парсить новостные ленты, чтобы получить заголовки новостей и ссылку. Мы пойдем другим путем. А вот каким, давайте и узнаем в статье.
А начнем мы все же с создания бота, прежде чем будем двигаться дальше. Ведь бот будет каркасом нашего скрипта.
Что потребуется?
Для того, чтобы создать бота, нужно установить библиотеку aiogram. Делается это довольно просто, с помощью команды в терминале:
И после того, как она установлена, давайте импортируем сразу же все, что нам пригодиться в дальнейшем. А понадобятся нам из библиотеки Bot, Dispatcher, executor и types. Так же, для оформления отправляемых сообщений в более-менее красивом виде импортируем методы hbold, hlink из модуля markdown.
Так же нам понадобиться токен и id канала. Но это лишь в том случае, если мы будем отправлять сообщения не в бота, а пересылать их непосредственно в канал. Как получить токен, думаю вы знаете. Инструкций на эту тему в интернете очень и очень много. Поэтому повторятся в данном вопросе не буду. Скажу лишь, что, если вы создадите канал и будете отправлять с помощью бота в него сообщения, вам нужно будет после того, как вы создадите бота и канал, добавить бота в администраторы канала, чтобы он мог с ним взаимодействовать. Иначе у вас просто ничего не получиться.
А теперь давайте создадим бота и диспетчер. В бота мы передадим наш токен, а в диспетчера передадим бота для управления.
Токен и id канала я сохранил в отдельном файле, который и импортировал в создаваемый скрипт с помощью:
Теперь давайте создадим функцию, в которой и будет происходить получение новостей и отправка их в канал или чат. Назовем ее просто start. Или можете назвать как-то иначе. Это не особо принципиально. И укажем в диспетчере, что вызов данной функции будет происходить посредством отправки боту команды /start.
Само тело функции пока что опущу, тут нужно будет более детально пройтись по всему, что будет в ней твориться. Об этом ниже. А пока запустим бота на исполнение. А вернее создадим для этого функцию, где и поместим команду на запуск.
Теперь давайте перейдем к основному телу функции. Как вы уже поняли, нам нужно будет получить новости с какого-либо новостного сайта. И тут есть два путя. Можно парсить, можно не парсить. Я пошел по первому пути. Не сейчас, конечно, а когда только пробовал создать себе новостного бота. Не скажу, что это быстрая задача. Ведь я поставил себе задачу обработать штук пять новостных сайтов. Или даже больше. Уже точно не помню. Но помню, что у меня получились простыни кода, которые пришлось вынести в отдельный модуль и вызывать его в основной функции.
Впрочем, наверное, так и надо делать. Но, просто я помню, сколько было потрачено усилий для того, чтобы просто получить новости. А оказывается, если бы мы не забывали о старых технологиях, о тех технологиях, которые постепенно сходят на нет, но, кое-где еще остаются, то все получилось бы гораздо быстрее и проще. А речь идет об RSS. И тут уже не надо парсить сотни строк кода. Не надо искать тэги, в которых находится текст новости или ссылка на нее. Тут достаточно спарсить RSS, а затем пройтись по полученному xml.
Чем же это сделать? Можно в принципе и руками. Но, оказывается, есть для этого специальная библиотека, которая упрощает это дело до пары тройки строк кода. Суть тут в том, что в RSS содержится вся информация, которая нам нужна для отправки новости в бота. Дата новости, ссылка на новость и краткое содержание при необходимости. Но, когда в чат телеграмма отправляется ссылка, отображается краткое превью. И необходимости в описании нет. Поэтому, все, что нужно забрать, это дата, заголовок и ссылка. Давайте приступим.
Для начала установим библиотеку rss-parser с помощью команды:
И импортируем нужные нам модули в скрипт:
А теперь, когда все необходимые приготовления проделаны, давайте перейдем к написанию тела бота. Для начала создадим список, в который будем складывать заголовки. Это нужно для того, чтобы через полчаса не получить ту же самую новость.
А теперь запускаем бесконечный цикл, в котором и будет происходить получение новостей:
В первую очередь, чтобы не хранить в памяти слишком много значений списка, проверяем его длину. И если она больше 20, то сбрасываем все его значение.
Теперь введем переменную, в которой будем хранить ссылку на ленту новостей. У Хабра ссылка, к примеру такая:
Дальше получаем содержимое xml по данной ссылке.
Полученное содержимое передаем в парсер, где и происходит основное действо. Тут же можно установить параметр limit, который будет выводить из RSS столько новостей, сколько вы укажете. Это очень похоже на точно такой же параметр lxml, когда парсишь сайт. Ну да ладно, вот код парсера:
Теперь передаем все в переменную:
И запускаем цикл, в котором проходимся по каждому полученному значению, по каждой новости:
Дальше делаем проверку есть ли заголовок новости в списке или нет. Если есть, новость пропускаем. Если нет, добавляем заголовок в список и отправляем новость в чат или канал.
Как вы понимаете, тут можно пойти двумя путями, про которые я уже упоминал. Выше указан код и для отправки в чат бота, и для отправки в канал, который будет создан вами. В чат бота это закомментированный код отправки, в канал, тот, что раскомментирован.
Давайте пройдемся чуть подробнее по коду. Здесь параметр publish_date, как можно понять из контекста, означает дату публикации. title – заголовок новости, а link – ссылка на нее. Ну и обернут этот код в разметку markdown. Дату публикации я сделал жирной, а вот заголовок и ссылку поместил в специальный тэг, первым параметром у которого служит текст, в данном случае заголовок, а вторым параметром ссылка. Таким образом заголовок в сообщении будет уже содержать в себе ссылку на новость. Что намного эстетичнее, чем то и другое по раздельности.
Ну и запускаем таймер, в котором указываем, сколько секунд будем спать до следующей проверки. В данном случае указано полчаса.
Вот, собственно, и все. Такой просто и небольшой код, взамен простыней парсинга. Если бы я раньше вспомнил об этой технологии и поискал бы решение, то может быть мои боты работали до сих пор. А того бота я забросил. Уж не помню почему, но, по-моему, код изменился на странице какого-то из порталов. А переписывать парсер мне было просто лень. Тем не менее, это было очень полезно, потому как я, все же получил бесценный опыт.
Как видите, тут больше строк занимают комментарии, чем сам код. Если нужны новости с еще одного сайта, ищем у них RSS, копируем ссылку, пишем код, запускаем цикл и так же создаем словарь уже для заголовков нового сайта, чтобы не пересекались и не очищался словарь раньше, чем новости на сайте устареют. И все. Новости получены. И так можно продолжать довольно долго. И даже вынести получение новостей в отдельный модуль. Но, тогда нужно будет создаваемый список возвращать боту. В общем, тут все зависит от вашей фантазии.
Забыл упомянуть, что новости тут грузятся очень быстро. Просто потому, что не нужно тратить время на парсинг кучи страниц, а нужно всего лишь загрузить один xml-файлик.
Спасибо за внимание. Надеюсь, что данная информация будет вам полезна
А начнем мы все же с создания бота, прежде чем будем двигаться дальше. Ведь бот будет каркасом нашего скрипта.
Что потребуется?
Для того, чтобы создать бота, нужно установить библиотеку aiogram. Делается это довольно просто, с помощью команды в терминале:
pip install aiogram
И после того, как она установлена, давайте импортируем сразу же все, что нам пригодиться в дальнейшем. А понадобятся нам из библиотеки Bot, Dispatcher, executor и types. Так же, для оформления отправляемых сообщений в более-менее красивом виде импортируем методы hbold, hlink из модуля markdown.
Python:
from aiogram import Bot, Dispatcher, executor, types
from aiogram.utils.markdown import hbold, hlink
Так же нам понадобиться токен и id канала. Но это лишь в том случае, если мы будем отправлять сообщения не в бота, а пересылать их непосредственно в канал. Как получить токен, думаю вы знаете. Инструкций на эту тему в интернете очень и очень много. Поэтому повторятся в данном вопросе не буду. Скажу лишь, что, если вы создадите канал и будете отправлять с помощью бота в него сообщения, вам нужно будет после того, как вы создадите бота и канал, добавить бота в администраторы канала, чтобы он мог с ним взаимодействовать. Иначе у вас просто ничего не получиться.
А теперь давайте создадим бота и диспетчер. В бота мы передадим наш токен, а в диспетчера передадим бота для управления.
Python:
bot = Bot(token=token, parse_mode=types.ParseMode.HTML)
dp = Dispatcher(bot)
Токен и id канала я сохранил в отдельном файле, который и импортировал в создаваемый скрипт с помощью:
from config import token, id_channel
Теперь давайте создадим функцию, в которой и будет происходить получение новостей и отправка их в канал или чат. Назовем ее просто start. Или можете назвать как-то иначе. Это не особо принципиально. И укажем в диспетчере, что вызов данной функции будет происходить посредством отправки боту команды /start.
Python:
@dp.message_handler(commands="start")
async def start(message: types.Message):
Само тело функции пока что опущу, тут нужно будет более детально пройтись по всему, что будет в ней твориться. Об этом ниже. А пока запустим бота на исполнение. А вернее создадим для этого функцию, где и поместим команду на запуск.
Python:
if __name__ == "__main__":
# запускаем бота
executor.start_polling(dp)
Теперь давайте перейдем к основному телу функции. Как вы уже поняли, нам нужно будет получить новости с какого-либо новостного сайта. И тут есть два путя. Можно парсить, можно не парсить. Я пошел по первому пути. Не сейчас, конечно, а когда только пробовал создать себе новостного бота. Не скажу, что это быстрая задача. Ведь я поставил себе задачу обработать штук пять новостных сайтов. Или даже больше. Уже точно не помню. Но помню, что у меня получились простыни кода, которые пришлось вынести в отдельный модуль и вызывать его в основной функции.
Впрочем, наверное, так и надо делать. Но, просто я помню, сколько было потрачено усилий для того, чтобы просто получить новости. А оказывается, если бы мы не забывали о старых технологиях, о тех технологиях, которые постепенно сходят на нет, но, кое-где еще остаются, то все получилось бы гораздо быстрее и проще. А речь идет об RSS. И тут уже не надо парсить сотни строк кода. Не надо искать тэги, в которых находится текст новости или ссылка на нее. Тут достаточно спарсить RSS, а затем пройтись по полученному xml.
Чем же это сделать? Можно в принципе и руками. Но, оказывается, есть для этого специальная библиотека, которая упрощает это дело до пары тройки строк кода. Суть тут в том, что в RSS содержится вся информация, которая нам нужна для отправки новости в бота. Дата новости, ссылка на новость и краткое содержание при необходимости. Но, когда в чат телеграмма отправляется ссылка, отображается краткое превью. И необходимости в описании нет. Поэтому, все, что нужно забрать, это дата, заголовок и ссылка. Давайте приступим.
Для начала установим библиотеку rss-parser с помощью команды:
pip install rss-parser
И импортируем нужные нам модули в скрипт:
from rss_parser import Parser
А теперь, когда все необходимые приготовления проделаны, давайте перейдем к написанию тела бота. Для начала создадим список, в который будем складывать заголовки. Это нужно для того, чтобы через полчаса не получить ту же самую новость.
habr_title = []
А теперь запускаем бесконечный цикл, в котором и будет происходить получение новостей:
while True:
В первую очередь, чтобы не хранить в памяти слишком много значений списка, проверяем его длину. И если она больше 20, то сбрасываем все его значение.
Python:
if len(habr_title) > 20:
habr_title = []
Теперь введем переменную, в которой будем хранить ссылку на ленту новостей. У Хабра ссылка, к примеру такая:
rss_url = 'https://habr.com/ru/rss/news/?fl=ru'
Дальше получаем содержимое xml по данной ссылке.
xml = get(rss_url)
Полученное содержимое передаем в парсер, где и происходит основное действо. Тут же можно установить параметр limit, который будет выводить из RSS столько новостей, сколько вы укажете. Это очень похоже на точно такой же параметр lxml, когда парсишь сайт. Ну да ладно, вот код парсера:
parser = Parser(xml=xml.content, limit=3)
Теперь передаем все в переменную:
feed = parser.parse()
И запускаем цикл, в котором проходимся по каждому полученному значению, по каждой новости:
for item in reversed(feed.feed):
Дальше делаем проверку есть ли заголовок новости в списке или нет. Если есть, новость пропускаем. Если нет, добавляем заголовок в список и отправляем новость в чат или канал.
Python:
if not item.title in habr_title:
habr_title.append(item.title)
# await message.answer(f'{hbold(item.publish_date)}\n\n{hlink(item.title, item.link)}\n\n')
await bot.send_message(id_channel, f'{hbold(item.publish_date)}\n\n{hlink(item.title, item.link)}\n\n')
Как вы понимаете, тут можно пойти двумя путями, про которые я уже упоминал. Выше указан код и для отправки в чат бота, и для отправки в канал, который будет создан вами. В чат бота это закомментированный код отправки, в канал, тот, что раскомментирован.
Давайте пройдемся чуть подробнее по коду. Здесь параметр publish_date, как можно понять из контекста, означает дату публикации. title – заголовок новости, а link – ссылка на нее. Ну и обернут этот код в разметку markdown. Дату публикации я сделал жирной, а вот заголовок и ссылку поместил в специальный тэг, первым параметром у которого служит текст, в данном случае заголовок, а вторым параметром ссылка. Таким образом заголовок в сообщении будет уже содержать в себе ссылку на новость. Что намного эстетичнее, чем то и другое по раздельности.
Ну и запускаем таймер, в котором указываем, сколько секунд будем спать до следующей проверки. В данном случае указано полчаса.
time.sleep(1800)
Вот, собственно, и все. Такой просто и небольшой код, взамен простыней парсинга. Если бы я раньше вспомнил об этой технологии и поискал бы решение, то может быть мои боты работали до сих пор. А того бота я забросил. Уж не помню почему, но, по-моему, код изменился на странице какого-то из порталов. А переписывать парсер мне было просто лень. Тем не менее, это было очень полезно, потому как я, все же получил бесценный опыт.
Python:
# pip install aiogram
# pip install rss-parser
# pip requests
# импортируем библиотеки
import time
from rss_parser import Parser
from requests import get
from aiogram import Bot, Dispatcher, executor, types
from aiogram.utils.markdown import hbold, hlink
from config import token, id_channel
# создаем объект бота, которому передаем токен, а также указываем какого типа будут
# отправляемые сообщения, создаем диспетчера, в которого передаем бота
bot = Bot(token=token, parse_mode=types.ParseMode.HTML)
dp = Dispatcher(bot)
# указываем обработку диспетчером комманды start
# создаем функцию в которой будем отправлять сообщения
# для этого явно указываем на тип сообщений
@dp.message_handler(commands="start")
async def start(message: types.Message):
habr_title = []
# запускаем бесконечный цикл, в котором будем проверять наличие новостей
while True:
if len(habr_title) >= 20:
habr_title = []
rss_url = "https://habr.com/ru/rss/news/?fl=ru"
xml = get(rss_url)
parser = Parser(xml=xml.content, limit=3)
feed = parser.parse()
# пробегаемся по каждой новости в цикле
for item in reversed(feed.feed):
# проверяем есть ли заголовок новости в списке
if not item.title in habr_title:
habr_title.append(item.title)
# отправляем сообщение
# await message.answer(f'{hbold(item.publish_date)}\n\n{hlink(item.title, item.link)}\n\n')
await bot.send_message(id_channel, f'{hbold(item.publish_date)}\n\n{hlink(item.title, item.link)}\n\n')
time.sleep(1800)
# запускаем бота
if __name__ == "__main__":
executor.start_polling(dp)
Как видите, тут больше строк занимают комментарии, чем сам код. Если нужны новости с еще одного сайта, ищем у них RSS, копируем ссылку, пишем код, запускаем цикл и так же создаем словарь уже для заголовков нового сайта, чтобы не пересекались и не очищался словарь раньше, чем новости на сайте устареют. И все. Новости получены. И так можно продолжать довольно долго. И даже вынести получение новостей в отдельный модуль. Но, тогда нужно будет создаваемый список возвращать боту. В общем, тут все зависит от вашей фантазии.
Забыл упомянуть, что новости тут грузятся очень быстро. Просто потому, что не нужно тратить время на парсинг кучи страниц, а нужно всего лишь загрузить один xml-файлик.
Спасибо за внимание. Надеюсь, что данная информация будет вам полезна