Вопрос или проблема
Я пишу телеграм-бота, который должен отправлять некоторые сообщения с помощью клиента telethon, а некоторые — с помощью aiogram. Он выдает ошибку, которую я не понимаю
Я пробовал следующий код:
bot = Bot(token=bot_token)
dp = Dispatcher()
client = TelegramClient("session", api_id, api_hash).start(bot_token=bot_token)
@dp.message(CommandStart())
async def start(message: types.Message):
await message.answer("текст aiogram")
await client_send(message)
async def client_send(message: types.Message):
async with client:
await client.send_message(message.chat.id, "текст telethon")
async def main():
await dp.start_polling(bot)
if __name__ == '__main__':
asyncio.run(main())
Когда бот получает сообщение, я получаю этот длинный трассировку ошибок:
Cause exception while process update id=xxx by bot id=xxx
RuntimeError: The asyncio event loop must not change after connection (see the FAQ for details)
Traceback (most recent call last):
File "C:\Users\Artyxx\AppData\Local\Programs\Python\Python311\Lib\site-packages\aiogram\dispatcher\dispatcher.py", line 309, in _process_update
response = await self.feed_update(bot, update, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\Artyxx\AppData\Local\Programs\Python\Python311\Lib\site-packages\aiogram\dispatcher\dispatcher.py", line 158, in feed_update
response = await self.update.wrap_outer_middleware(
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
...
File "C:\Users\Artyxx\AppData\Local\Programs\Python\Python311\Lib\site-packages\aiogram\dispatcher\event\handler.py", line 43, in call
return await wrapped()
^^^^^^^^^^^^^^^
File "C:\Users\Artyxx\Documents\Python\bot\bot-check-in\testcode.py", line 19, in start
await client_send(message)
File "C:\Users\Artyxx\Documents\Python\bot\bot-check-in\testcode.py", line 23, in client_send
async with client:
File "C:\Users\Artyxx\AppData\Local\Programs\Python\Python311\Lib\site-packages\telethon\client\auth.py", line 657, in __aenter__
return await self.start()
^^^^^^^^^^^^^^^^^^
File "C:\Users\Artyxx\AppData\Local\Programs\Python\Python311\Lib\site-packages\telethon\client\auth.py", line 141, in _start
me = await self.get_me()
^^^^^^^^^^^^^^^^^^^
File "C:\Users\Artyxx\AppData\Local\Programs\Python\Python311\Lib\site-packages\telethon\client\users.py", line 165, in get_me
me = (await self(
^^^^^^^^^^^
File "C:\Users\Artyxx\AppData\Local\Programs\Python\Python311\Lib\site-packages\telethon\client\users.py", line 30, in __call__
return await self._call(self._sender, request, ordered=ordered)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\Artyxx\AppData\Local\Programs\Python\Python311\Lib\site-packages\telethon\client\users.py", line 34, in _call
raise RuntimeError('The asyncio event loop must not change after connection (see the FAQ for details)')
RuntimeError: The asyncio event loop must not change after connection (see the FAQ for details)
Как я могу подключить и использовать эти две библиотеки
asyncio.run
создает новый цикл событий. После того как вы установили соединение (что вы делаете с помощью .start()
Telethon), вы не можете изменить цикл (строка .start()
использует стандартный цикл, но asyncio.run
создает новый).
Уберите .start()
. Когда вы используете async with client
, это также вызывает .start()
, поэтому первый раз вызова избыточен и вызывает проблемы.
Также обратите внимание, что Telethon может управлять аккаунтами ботов тоже. Если вам нужны и пользователь, и бот, использование одной библиотеки может быть проще.
Ответ или решение
Для успешного соединения и работы с библиотеками Aiogram и Telethon в одном проекте, важно правильно управлять контекстом событий (event loop) и избегать ошибок изменения цикла после его использования. Рассмотрим код, который у вас есть, и исправим его.
Проблема
Основная проблема возникает из-за того, что вы используете .start()
у клиента Telethon и одновременно запускаете новое событие с помощью asyncio.run(main())
, что создаёт два разных цикла событий. Это приводит к ошибке: RuntimeError: The asyncio event loop must not change after connection
.
Решение
Мы можем избежать этой ошибки, устранив дублирование вызова .start()
и используя только один контекст событий. Telethon самостоятельно управляет подключением, если мы используем async with
. Так что, давайте уберём вызов .start()
при создании клиента Telethon и создадим обязательный контекст для работы с клиентом Telethon.
Вот исправленный код:
import asyncio
from aiogram import Bot, Dispatcher, types
from aiogram.filters import CommandStart
from telethon import TelegramClient
bot_token = 'YOUR_BOT_TOKEN'
api_id = 'YOUR_API_ID'
api_hash = 'YOUR_API_HASH'
# Инициализация бота
bot = Bot(token=bot_token)
dp = Dispatcher()
# Инициализация клиента Telethon
client = TelegramClient("session_name", api_id, api_hash)
async def client_send(chat_id, message_text):
async with client:
await client.send_message(chat_id, message_text)
@dp.message(CommandStart())
async def start(message: types.Message):
await message.answer("text aiogram")
await client_send(message.chat.id, "text telethon")
async def main():
async with client:
await dp.start_polling(bot)
if __name__ == '__main__':
asyncio.run(main())
Объяснение изменений
-
Удаление вызова
.start()
у клиента: Мы убрали вызовclient = TelegramClient(...).start(bot_token=bot_token)
, так как это вызывает подключение до того, как мы используем его вasync with
. -
Использование
async with client
в функцииmain
: Теперь мы управляем подключением клиента Telethon в контекстеmain()
, гарантируя, что клиент правильно подключится и отключится. -
Передача
chat_id
в функциюclient_send
: Передаем идентификатор чата вclient_send
, чтобы сделать функцию более гибкой.
Заключение
С помощью этих изменений вы сможете успешно использовать Aiogram и Telethon в одном Telegram боте. Также не забывайте, что Telethon может управлять как пользовательскими аккаунтами, так и аккаунтами ботов, и использование одной библиотеки может быть проще в ряде случаев.
Если у вас остались вопросы или возникли новые проблемы, не стесняйтесь задавать их.