Ну для начала твоя лесенка из if-elif-elif-... - плохое решение.
Сделай нормальную структуру данных вместо пачки переменных. Используй словарь, или ещё что. Например, такого вида:
# словарь, где ключ - строка с названием пунка отправления, а значение - ещё словарь,
# где ключ - строка с названием пункта назначения, а значение - список,
# где элементы - пары строк ("время отправления", "время прибытия")
# Тогда с таким словарём можно будет работать так:
bus_timetable: dict[str, dict[str, list[tuple[str, str]]]] = {
# ты словарь заполняешь по результатам парсинга, ну и то хорошо
# я для примера запишу прямо так
'Владимир' : {
'Муром': [
('8:00', '11:00'),
('9:00', '12:00'),
('10:00', '13:00'),
],
},
}
point_from = 'Владимир'
point_to = 'Муром'
# для примера вывожу в консоль, для бота перепишешь сам
print(f'Автобус из {point_from} в {point_to}')
for departure, arrival in bus_timetable[point_from][point_to]:
print(f'Отходит в {departure}, прибывает в {arrival}')
Тогда тебе не потребуется делать кучу веток для разных городов, достаточно лишь определить значения point_from и point_to. Более того, ты можешь просто перечислить ключи внешнего словаря при создании кнопок:
kbd_from = types.ReplyKeyboardMarkup(resize_keyboard=True)
buttons = [types.KeyboardButton(point_from) for point_from in bus_timetable] # список кнопок
kbd_from.add(*buttons) # если надо добавить все кнопки сразу
Похожий приём возможен и для определения кнопок для городов назначения.
А теперь по тому, как сделать выбор. Тут есть два варианта, но давай пока поговорим о ReplyKeyboardMarkup, которую ты используешь.
Если ты хочешь использовать ReplyKeyboardMarkup, то стоит помнить - её кнопки дают тот же эффект, как если бы пользователь просто ввёл текст кнопки сам. Поэтому тебе потребуется использовать register_next_step_handler(). Ты не привёл код своей попытки, но в целом идея несложная. В основном обработчике события ты проверяешь, что текст сообщения содержится в bus_timetable (оператор in в помощь) - это значит, что текст сообщения содержит название известного боту города.
Тогда ты делаешь вызов register_next_step_handler() и ставишь обработчик второго сообщения. Единственное "но": тебе нужно будет обработчику передать первый выбранный город. Это будет выглядеть как-то так:
@bot.message_handler(content_types=['text'])
def first_message_handler(message):
if message.text in bus_timetable: # назвали известный город? Это пункт отправления
kbd = ... # тут определяешь клавиатуру, опираясь на города в bus_timetable[message.text]
response = bot.reply_to(message, "А теперь назовите пункт назначения", reply_markup=kbd)
# обрати внимание: все параметры после указания функции second_message_handler будут
# переданы в эту функцию при её вызове. А вызвана она будет, когда пользователь ответит.
bot.register_next_step_handler(response, second_message_handler, message.text)
elif ... # нам назвали не город - тут можно проверить другие команды
def second_message_handler(message, point_from):
# а эта функция будет вызвана только когда пользователь уже назвал пункт отправления
# point_from будет содержать название города, отправленное пользователем.
if message.text in bus_timetable[point_from]: # нам назвали допустимый пункт назначения
bus_rides = bus_timetable[point_from][message.text] # список рейсов
... # дальше перебираем список bus_rides и выводим его пользователю
else: # пользователь назвал что-то другое
... # говорим пользователю, что он дурак