Ошибка IndexError: "list index out of range" в тг-боте

Есть код:

from telebot import TeleBot, types
from bs4 import BeautifulSoup
import random as rnd
import requests
import token

TOKEN = token.token
bot = TeleBot(TOKEN)

@bot.message_handler(commands=["start"])
def handle_start(message):
    global city
    bot.send_message(message.chat.id, "Привет, давай пройдем небольшую регистрацию!")
    bot.send_message(message.chat.id, "Введи город в котором ты живешь(это нужно для определения погоды в твоем городе)")
    city = message.text.lower()

@bot.message_handler(commands=["menu"])
def handle_menu(message):
    keyboard = types.InlineKeyboardMarkup()
    info_b = types.InlineKeyboardButton('Информация?', callback_data='qwerty')
    weather_b = types.InlineKeyboardButton('Погода❄️', callback_data='Weather')
    keyboard.add(info_b, weather_b)
    bot.send_message(message.chat.id,f"Привет, {message.from_user.first_name}, это менюшка", reply_markup=keyboard)

def check_weather(city):
    headers = {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36"
    }

    responce = requests.get(f"https://www.google.com/search?q=погода+в+{city}", headers=headers)
    print(responce)

    soup = BeautifulSoup(responce.text, "html.parser")

    temperature = soup.select("#wob_tm")[0].getText()
    title = soup.select("#wob_dc")[0].getText()
    humidity = soup.select("#wob_hm")[0].getText()
    time = soup.select("#wob_dts")[0].getText()
    wind = soup.select("#wob_ws")[0].getText()

    print(time)
    print(title)
    print(f"Температура: {temperature}C")
    print(f"Влажность: {humidity}")
    print(f"Ветер: {wind}")

    return temperature

@bot.callback_query_handler(func=lambda callback: True)
def callback_message(callback):
    if callback.data == "Weather":
        bot.send_message(callback.message.chat.id, text=f"{check_weather(city)}")

if __name__ == '__main__':
    bot.polling(none_stop=True)

Возникает ошибка после нажатия на кнопку Погода:

Ошибка temperature = soup.select("#wob_tm")[0].getText() IndexError: list index out of range

Ответы (1 шт):

Автор решения: Ben Puls

Во-первых, в глобальную переменную вы записываете команду, только что введённую пользователем. А значит, в объявленную глобальную переменную записывается не город, а команда /start.

Для того, чтобы это исправить существует метод register_next_step_handler().

@bot.message_handler(commands=["start"])
def handle_start(message):
    
    bot.send_message(message.chat.id, "Привет, давай пройдем небольшую регистрацию!")
    city_message = bot.send_message(
        message.chat.id,
        "Введи город в котором ты живешь(это нужно для определения погоды в твоем городе)")
    
    bot.register_message_handler(city_message, get_city)


def get_city(message):
    city = message.text.lower()
    ...

Уже в функции get_city() вы можете работать пользовательскими данными, записать в бд и прочее.

Из-за этого вместо поиска введённого пользователем города в поиск отправлялась команда /start. Отсюда и метод select() не нашёл никаких элементов с соответствующим id. Потому что на странице какая-то другая информация.

Во-вторых, проверяйте, что вам отвечает поиск Google, чтобы такие ошибки можно было как-то обработать.

В-третьих, найти элемент по id можно несколько проще:

soup = bs4.BeautifulSoup(response.text, "html.parser")

temperature = soup.find(id="wob_tm").text
condition = soup.find(id='wob_dc').text
time = soup.find(id='wob_dts').text

print(temperature, condition, time)

Результат:

'2' 'Переменная облачность' 'суббота 02:00'

Если всё-таки нужно получить данные через метод select(), то тогда нужно сделать через свойство text:

soup.select('#wob_tm')[0].text

В-четвёртых, не используйте глобальные переменные в таком коде. Лучше создайте словарь, где ключом будет id пользователя, а значением - его город. Так будет хоть какая-то возможность нормально работать с данными, ну а лучше всего подключить какую-нибудь базу данных, sqlite3, например.

→ Ссылка