Не работает цикл + обработка команд от пользователя в Telegram-боте

Рейтинг: 0Ответов: 1Опубликовано: 04.03.2023

О проблеме: Есть задача написать Telegram-бота, который ежедневно парсит информацию с сайта и отправляет ее всем подписчикам бота. Парсер написан, бот тоже. Но я не могу реализовать совместную работу рассылки из парсера с обработкой команд в боте: /start и т.д. Либо работает только рассылка, либо работают только команды бота.

Многое пробовал методом "тыка", но в итоге везде возникала какая-нибудь другая проблема. Например, на хостинге я запускал два файла .py - один файл с рассылкой, а другой файл с самим ботом. Но тогда возникала проблема с sql - он, видимо, не может работать с 2 потоками одновременно. Если рассылка работает с sql, то файл с ботом не может обратиться к sql (например, при записи нового пользователя в базу после команды /start).

Сейчас сам предполагаю 2 решения проблемы:

  1. Написать всё в рамках одного файла .py: и цикл с рассылкой, и команды от пользователей. Так, наверное, sql сможет обрабатывать все запросы, если они буду идти из одного файла .py. Можно ли это сделать? Асинхронность?
  2. Найти базу данных, которая может работать одновременно с множеством поток. Но я не знаю, поможет ли это. Может, проблема вообще не в sql?

Ниже прикладываю код. Файлы поотдельности работают. Рассылка отправляет подписчикам, бот принимает новых подписчиков в базу. Проблема именно в совместной их работе.

Файл с ботом main.py:

from aiogram import Bot, Dispatcher, executor, types
from db import Database

bot = Bot(token='********************')
dp = Dispatcher(bot)
db = Database('database.db')

users = db.get_users()

@dp.message_handler(commands=['start'])
async def start(message: types.Message):
    if message.chat.type == 'private':
        if not db.user_exists(message.from_user.id):
            db.add_user(message.from_user.id)
        await bot.send_message(message.from_user.id, 'Подписка на ежедневные новости оформлена!')
    await bot.send_message(5827479744, 'Новый подписчик!')


if __name__ == '__main__':
    executor.start_polling(dp, skip_updates=True)

Файл с рассылкой send_news.py(парсер был написан прямо в функции sendall - убрал его код, остались только переменные в сообщениях бота):

from db import Database
from aiogram import Bot, Dispatcher, executor, types
import asyncio
import requests
from bs4 import BeautifulSoup
from datetime import datetime


bot = Bot(token='*********************')
dp = Dispatcher(bot)
db = Database('database.db')


loop = asyncio.get_event_loop()

async def sendall():
users = db.get_users()
        for row in users:
            try:
                begining_of_news = open('begining_of_news.png', 'rb')
                with open('begining_of_news.png', 'rb') as photo:
                    await bot.send_photo(row[0], photo=begining_of_news)
                i = 0
                for el in range(len(news_for_bot)):
                    await bot.send_message(row[0], '◽️' + '<b>' + news_for_bot[i].strip() + '</b>' + '\n' + '\n' + gsearch_news_for_bot[i], parse_mode="HTML")
                    i += 1
                await bot.send_message(row[0], '<i>Какой-то текст', parse_mode="HTML")
                if int(row[1]) != 1:
                    db.set_active(row[0], 1)
            except:
                db.set_active(row[0], 0)
        await asyncio.sleep(10)

loop.run_until_complete(sendall())

Ответы

▲ 0

Первый вопрос и первый ответ ru.stackoverflow.com в одном месте :) Я нашел решение для себя - возможно, кому-то будет полезно.

Работает с базой sql теперь только один файл .py, а не два файла, как было ранее. Ежедневный запуск рассылки задается командой от администратора - а внутри команды обычный цикл while. Остальные команды в боте работают параллельно с рассылкой, никаких проблем пока не было.

from aiogram import Bot, Dispatcher, executor, types
import parser
from db import Database
import asyncio

bot = Bot(token='6142748527:AAExSYcE_kmXROoJAD0nVCUVwn65HOGSj60')
dp = Dispatcher(bot)
db = Database('database.db')


@dp.message_handler(commands=['start'])
async def start(message: types.Message):
    if message.chat.type == 'private':
        if not db.user_exists(message.from_user.id):
            db.add_user(message.from_user.id)
        await bot.send_message(message.from_user.id, 'Подписка оформлена!')


@dp.message_handler(commands=['start_news'])
    async def start_news(message: types.Message):
        if message.from_user.id == 5827479744:
            while True:
                await parser.start_parser()
                users = db.get_users()
                for row in users:
                    try:
                        begining_of_news = open('begining_of_news.png', 'rb')
                        with open('begining_of_news.png', 'rb') as photo:
                            await bot.send_photo(row[0], photo=begining_of_news)
                        i = 0
                        for el in range(len(parser.news_for_bot)):
                            await bot.send_message(row[0], '◽️' + '<b>' + parser.news_for_bot[i].strip() + '</b>' + '\n' + '\n' + parser.gsearch_news_for_bot[i], parse_mode="HTML")
                            i += 1
                        if int(row[1]) != 1:
                            db.set_active(row[0], 1)
                    except:
                        db.set_active(row[0], 0)
                await asyncio.sleep(86400)