Как бот может вынести значение, которое требует юзер, из Excel таблицы? PyTelegramBotAPI
Создаю телеграм бота (библиотека pytelegrambotapi). Допустим, бот связан с мебелью, а этой мебели 200 штук и писать if-elif-else, словари и т.д. очень долго и неудобно. Поэтому решил подключить к работе Excel таблицу (впервые с ним работаю, выбрал библиотеку xlrd, если библиотека выбрана не так, как надо, то прошу сообщить мне!).
Есть заголовки столбцов: название, материал, высота, ширина.
И должно выглядить вот так:
Юзер: "Пишет название мебели"
Бот: *берет всю инфу об ЭТОЙ мебели, кроме названия*
Бот: *Выводит* "Высота: х см., ширина у см., материал такой-то"
Возможно ли такое реализовать? Есть ли примеры? Примеров вообще не нашел в гугле. Заранее спасибо громадное))
Ответы (2 шт):
Используйте sqlite3 вместо exel таблиц, если данные должны храниться локально. Если же у вас SQL сервер в облаке, используйте PyMySQL.
Действительно, реализовать такое можно, но использовать для этих целей Excel - не лучшая идея. Почему? .xls это простой файл, считывание таких файлов относительно медленная операция, особенно с учетом того, что считывание экселя обычно значительно замедляется при увеличении количества данных (а что если у вас будет 10000 наименований мебели?) а так же с учетом того, что библиотека, которая его читает должна кроме прочего спарсить такой файл в удобный для работы в питоне объект (например в словарь или список). Такая задача, возможно, требует другого подхода.
Возможно вы скажете, что в вашей текущей задаче такой проблемы не появится, но ведь этот ответ в Т.Ч. для будущих поколений и для помощи вам в решении будущих задач :)
Теоретически (если вашей мебели действительно всего +-200 экземпляров) можно хранить всё в Json файле, примерно так:
[
{
"name": "Черный стол",
"sizes": "100x200x300",
"color": "black",
"description": "самый лучший стол"
},
{
"name": "Синий стул",
"sizes": "146x300x69",
"color": "blue",
"description": "самый лучший стул для лучшего стола"
},
{
"name": "Шкаф",
"sizes": "2x2",
"color": "purple",
"description": "Кто вообще заказал фиолетовый шкаф?"
}
]
Для работы с Json в Python есть готовый модуль json, а его считывание, запись и парсинг происходят весьма быстро, но такой подход все ещё будет не очень хорошо работать для большого количества данных, хотя к преимуществам можно отнести возможность создания произвольной структуры:
Для каждой мебели вы можете указывать те поля, которые хотите, например сделать объект без поля цвет, без описания, или добавить к шкафу параметр наличия отдельной антресоли.
Однако раз (судя по вашему вопросу) вы имеете четкую структуру описания каждого объекта, возможно данное "преимущество" вам не нужно, тогда вы можете прибегнуть к более традиционному способу: использовать Базу данных
База данных имеет много преимуществ, к основным можно отнести следующие:
- Высокая скорость работы (относительно прошлых способов)
- Возможность общего доступа (например если кроме вашего бота информацию из неё будет читать ещё ваш сайт, или если вы захотите подключиться к ней из вне и внести изменения) Согласитесь, удобнее зайти в браузер и поменять всё оттуда, а не подключаться к файловой системе сервера, открывать файл, копировать, вставлять и т.д.
- Определение правил безопасности (В базе данных можно легко ограничить права разных пользователей, например, чтобы вы могли вносить любые правки, а ваш менеджер мог лишь смотреть на них)
- Определение связей данных (например, если вы хотите всегда знать к какому шкафу в комплекте идет данная антресоль, или к какому кухонному комплекту можно заказать в комплекте данный стол.
Более подробно о преимуществах вы можете узнать в интернете :)
Я же попробую показать пример кода работы с sqlite3 базой данных. Она имеет много ограничений, в сравнении с более "правильным" базами данных, такими как MySQL, PostgreSQL, Oracle и т.п. Но имеет очень важное преимущество: она не требует дополнительных настроек и установок, а её использование достаточно просто, например Python имеет встроенный модуль для работы с sqlite3 базами данных, в то время как для работы с postgreSQL понадобится установка дополнительных библиотек, например psycopg2.
Попробую представить небольшой фрагмент (Очень упрощенный) Создания базы данных и добавления в неё информации:
import sqlite3 as sl
con = sl.connect('furniture.db')
try:
with con:
con.execute("""
CREATE TABLE furniture (
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
name VARCHAR(255),
size VARCHAR(255),
color VARCHAR(255),
description TEXT
);
""")
except sl.OperationalError:
print('База данных уже создана. Пропускаем этот этап')
# Записываем в базу какие-то записи
sql = 'INSERT INTO furniture (name, size, color, description) values( ?, ?, ?, ?)'
data = [
('Черный стол', '100x200x300', 'black', 'самый лучший стол'),
('Синий стул', '146x300x69', 'blue', 'самый лучший стул для лучшего стола'),
('Шкаф', '2x2', 'purple', 'Кто вообще заказал фиолетовый шкаф?')
] # data Может быть любыми вашими записями, как вы их запишите, это лишь ваше дело
with con:
con.executemany(sql, data)
Надеюсь пока не слишком сложно? После запуска данного кода в базе мы увидим следующую картину:

Сразу отвечу на возможно возникший вопрос тех, кто впервые столкнулся с базами данных, и не понимает, что это за странные буквы аля CREATE TABLE - это специальный язык SQL. Почти все реляционные базы данных (например все упомянутые выше) управляются при помощи этого языка, не стоит пугаться раньше времени, основы его очень просты например здесь можно изучить весь основной синтаксис за 20 минут.
Скорее всего, запуск данного кода, с заполнением базы данных вы хотите выполнять редко: при поступлении новых товаров, например раз в неделю. В остальное время вам, скорее всего нужно будет читать содержимое. Давайте рассмотрим пример:
Вот так можно сделать чтение всех записей из таблицы:
import sqlite3 as sl
con = sl.connect('furniture.db')
with con:
data = con.execute("SELECT * FROM furniture")
for row in data:
print(f'{row[4]} размером {row[2]} и с цветом "{row[3]}"')
Согласитесь, не очень сложно?
А как известно простое правило гласит:
Всё что можно вывести в консоль, можно вывести и в telegram бота.
Но ведь нам нужно получать только конкретную мебель по названию? Да без проблем:
import sqlite3 as sl
con = sl.connect('furniture.db')
furniture_name = 'Черный стол'
with con:
data = con.execute("SELECT * FROM furniture WHERE name=?", [furniture_name])
res = data.fetchone()
if not res:
print('Мебель не найдена')
else:
print(res)
При этом в выводе мы увидим всю информацию об искомом столе:

И при этом логику вы можете легко подстроить под себя: находить только те модели, которые есть на складе, возможно пользователь захочет увидеть всю черную мебель и т.д. всю логику фильтрации (если вы сделаете её при помощи SQL) будет брать на себя БД, а она делает это куда быстрее питона (хорошо видно на большом количестве записей)
Но вы же всё-таки спрашивали про Excel, и я говорил, что можно сделать через excel? Ну, за слова надо отвечать. Вот так выглядит мой excel файл:

А вот как выглядит его считывание:
import pandas as pd
xl = pd.ExcelFile('db.xlsx')
df1 = xl.parse(xl.sheet_names[0])
hist_data = df1.to_numpy().tolist()
for el in hist_data:
print(el)
Сразу оговорись, я использую pandas и openpyxl, потому что новые .xlsx файлы библиотека xlrd обрабатывать не умеет.
Вам может показаться, что данный скрипт куда проще, Но за это приходится дорого платить: В то время как скрипт читающий записи из базы у меня выполняется ~0.3 секунды, этот уже целых 2! И будьте уверены, чем больше будет записей, тем больше будет разрыв.
Более того, скрипт записи отрабатывает ещё дольше, около 3х секунд:
import pandas as pd
#xl = pd.ExcelFile('db1.xlsx', )
data = [
[1, 'Черный стол', '100x200x300', 'black', 'самый лучший стол'],
[2, 'Синий стул', '146x300x69', 'blue', 'самый лучший стул для лучшего стола'],
[3, 'Шкаф', '2x2', 'purple', 'Кто вообще заказал фиолетовый шкаф?']
]
df = pd.DataFrame(data)
df = df.transpose()
df.to_excel('db.xlsx')
Но при его работе получается другая структура документа:

А значит, нужно либо учитывать это при считывании, либо изменять структуру получаемого файла под себя. Причем я, например, не смог в приемлемые сроки найти в интернете понятный гайд, как это сделать. Хотя нужные мне подсказки по работой с базе данных я нашел по первым же ссылкам.
Да, возможно есть и более быстрые способы работы с Excel, но они, очевидно, будут более сложными и менее понятными.
Исходя из всего выше перечисленного, как я уже сказал, для таких целей нужно использовать базу данных, ведь именно для этого они и придуманы.

