Невозможно выйти из цикла во время работы Telegram Bot

Я создаю бота Telegram с помощью pyTelegramBotAPI, который отправляет в режиме реального времени обновления текущих матчей по крикету. Я хочу разорвать цикл всякий раз, когда пользователь вводит команду /stop. Я искал различные источники, а также пробовал несколько методов для достижения того же, но все напрасно. Цикл продолжает повторяться. Самое близкое, что я достиг, - это выйти из программы, вызвав ошибку. Кроме того, внутри цикла метод getUpdates всегда возвращает пустой список. Я также написал проблему на GitHub.

def loop(match_url):
    prev_info = ""
    flag = 1
    #continuously fetch data 
    while flag:
        response = requests.get(match_url)
        info = response.json()['score']
        #display only when the score updates 
        if str(info) != prev_info:
            prev_info = str(info)
            send_msg(info)
        else:
            pass
        send_msg(info)
        #this handler needs to be fixed 
        @bot.message_handler(commands=['stop', 'end'])
        def stop(message):
            #code to break the loop
            flag = 0
            return
            

Поскольку это не сработало, я охотно использовал этот неправильный метод:

while flag:
        response = requests.get(match_url)
        info = response.json()['score']
        if str(info) != prev_info:
            prev_info = str(info)
            send_msg(info)
        else:
            pass
        send_msg(info)
        @bot.message_handler(commands=['stop', 'end'])
        def stop(message):
            bot.polling.abort = True #an arbitrary function that raises error and exits the program

Вот весь код. Я также добавил на GitHub ссылку этого кода:

import requests, json, telebot

token = <TOKEN>
bot = telebot.TeleBot(token)

#parsing data from cricapi.com
def live_matches():
    #here I'm using the KEY obtained from cricapi.com
    curr_matches_url = "https://cricapi.com/api/cricket?apikey=<KEY>"  
    curr_matches = requests.get(curr_matches_url)
    match_data = curr_matches.json()['data']
    global unique_id_arr, score_arr
    unique_id_arr, score_arr = [], []
    match_details = ""
    for i in match_data:
        unique_id_arr.append(i["unique_id"])
    for i in range(len(match_data)):
        score_arr.append(match_data[i]["title"])
        score_arr[i] += "\n"
        match_details += str(i+1) + ". "
        match_details += score_arr[i]
    send_msg(match_details)

def send_msg(msg):
    url2 = 'https://api.telegram.org/bot'+token+'/sendMessage'
    data = {'chat_id': chat_id, 'text': msg}
    requests.post(url2, data).json()


@bot.message_handler(commands=['start', 'help'])
def send_welcome(message):
    bot.reply_to(message, "Howdy, how are you doing?")
    global chat_id
    chat_id = message.chat.id
    msg = bot.reply_to(message, "Welcome to test project\nEnter the match number whose updates you want to receive")
    live_matches()
    bot.register_next_step_handler(msg, fetch_score)

def fetch_score(message):
    chat_id = message.chat.id
    match_no = message.text
    #checking if the number entered is present in the displayed list
    if not match_no.isdigit():
        msg = bot.reply_to(message, 'Error1!\nSelect a no. from the above list only')
        return bot.register_next_step_handler(msg, fetch_score)
    elif 1 <= int(match_no) <= len(score_arr):
        unique_id = unique_id_arr[int(match_no)-1]
        global match_url
        #get the data of the desired match
        match_url = "https://cricapi.com/api/cricketScore?unique_id="+unique_id+"&apikey=<KEY>"
        loop(match_url)
    else:
        msg = bot.reply_to(message, "Error2!\nSelect a no. from the above list only")
        return bot.register_next_step_handler(msg, fetch_score)

def loop(match_url):
    prev_info = ""
    flag = 1
    #continuously fetch data
    while flag:
        response = requests.get(match_url)
        info = response.json()['score']
        #display only when the score updates
        if str(info) != prev_info:
            prev_info = str(info)
            send_msg(info)
        else:
            pass
        send_msg(info)
        #this handler needs to be fixed
        @bot.message_handler(commands=['stop', 'end'])
        def stop(message):
            #an arbitrary function that raises error and then exits
            bot.polling.abort = True 
bot.polling()
"""
#currently not using
def receive_msg():
    url1 = 'https://api.telegram.org/bot'+token+'/getUpdates'
    response = requests.get(url1)
    text = response.json()['result']
    if len(text) > 0:
        user_msg = text[-1]['message']['text']
        return user_msg
    return text
"""

person Wolferic_Locker    schedule 25.03.2021    source источник
comment
Пожалуйста, покажите полный код. Особенно часть «#code to break the loop»   -  person 0stone0    schedule 27.03.2021
comment
@0stone0 Я добавил обе вещи. Пожалуйста, попробуйте еще раз.   -  person Wolferic_Locker    schedule 27.03.2021


Ответы (1)


Вы неправильно используете пакет telebot(pyTelegramBotAPI):

  1. Зачем вы создали свою функцию send_msg там, где уже есть метод send_message в telebot?
  2. Вы повторно объявляете свой обработчик остановки в цикле, что неправильно!

Я предлагаю вам научиться правильно использовать pyTelegramBotAPI!

Вот демонстрационный код, который решает вашу проблему:

import telebot
from time import sleep

bot = telebot.TeleBot(BOT_TOKEN)
flag = 1

@bot.message_handler(commands=['loop'])
def loop(msg):
    while flag:
        bot.send_message(msg.chat.id, "ping")
        sleep(1)

@bot.message_handler(commands=['stop', 'end'])
def stop(msg):
    global flag
    flag = 0
    bot.send_message(msg.chat.id, "stopped")


bot.polling(none_stop=True)

Объяснение:

  • Объявлено flag как глобальная переменная и установлено значение 1
  • обработчик цикла для запуска цикла, который отправляет вам сообщение ping каждую секунду
  • обработчик остановки, который изменяет flag на 0, что завершает рабочий цикл
person GooDeeJAY    schedule 04.04.2021
comment
Большое спасибо @GooDeeJAY за ваши ответы. Это действительно мне очень помогло. Что касается вашего первого пункта, я хорошо знаю об этом, но я просто пробовал кое-что. Кроме этого, я определенно буду больше изучать pyTelegramBotAPI. - person Wolferic_Locker; 04.04.2021