Поиск рецептов на Python с Tkinter и Edamam API

В эпоху множества разрозненных рецептов и рекламы удобно иметь собственное приложение, которое возвращает только релевантные результаты. Создание приложения-поисковика рецептов даёт единый, понятный интерфейс, помогает отточить навыки работы с HTTP, хранением API-ключей, обработкой изображений и динамическим GUI.
Что вы получите
- Рабочее настольное приложение на Python с вводом названия блюда и выводом топ‑5 рецептов.
- Отображение заголовка, изображения и ссылки на рецепт.
- Примеры улучшений: фильтры, закладки, сортировка, локализация.
Основные понятия (в одну строку)
- Tkinter — стандартная библиотека Python для создания GUI.
- Requests — библиотека для HTTP-запросов.
- Pillow (PIL) — библиотека для обработки изображений.
- Edamam Recipe Search API — сторонний API для поиска рецептов.
Установка зависимостей
Для работы потребуется Python (рекомендуем 3.8+). Установите модули через pip (на некоторых системах Tkinter уже встроен):
pip install tkinter
pip install requests
pip install PillowМодуль webbrowser включён в стандартную библиотеку Python, его подключать отдельно не нужно.
Важно: храните API‑ключи в безопасном месте (см. раздел «Хранение ключей»).
Получение ключа Edamam API
- Перейдите на сайт Edamam (https://www.edamam.com).
- Зарегистрируйтесь и выберите план «Recipe Search API - Developer».
- Войдите в аккаунт и откройте панель управления (Dashboard).
- Перейдите во вкладку «Applications» и выберите View рядом с Recipe Search API.
- Скопируйте Application ID и Application Key — они понадобятся в приложении.
Совет: никогда не добавляйте ключи в публичные репозитории. Используйте .env или переменные окружения.
Структура приложения и ключевые функции
Ниже — упрощённый план исполнения функции get_top_5_recipes(), которая получает топ‑5 рецептов по запросу пользователя, скачивает и ресайзит изображения, и отображает результат в Tkinter.
Ключевые шаги:
- Получить текст запроса из поля ввода.
- Сформировать параметры для Edamam API (q, app_id, app_key, from, to).
- Выполнить GET-запрос и распарсить JSON.
- Для каждого рецепта скачать изображение, открыть через Pillow, изменить размер и показать в GUI.
Пример кода (фрагмент):
import tkinter as tk
import requests
from PIL import Image, ImageTk
import webbrowser
def get_top_5_recipes():
recipe_name = entry_recipe_name.get()
if recipe_name:
api_url = "https://api.edamam.com/search"
app_id = # Put your app id for edamam api
app_key = # Put your app key for edamam api
params = {
"q": recipe_name,
"app_id": app_id,
"app_key": app_key,
"from": 0,
"to": 5,
}
response = requests.get(api_url, params=params)
data = response.json()
clear_recipe_list()
if "hits" in data and data["hits"]:
for i, hit in enumerate(data["hits"]):
recipe = hit["recipe"]
recipe_list.append(recipe)
recipe_name = recipe["label"]
recipe_link = recipe["url"]
image_url = recipe["image"]
image_response = requests.get(image_url, stream=True)
image = Image.open(image_response.raw)
image = image.resize((200, 200), Image.LANCZOS)
photo_image = ImageTk.PhotoImage(image)
recipe_title_label = tk.Label(
canvas_frame,
text=f"{i+1}. {recipe_name}",
font=("Helvetica", 12, "bold"),
)
recipe_title_label.pack(pady=(5, 0), anchor=tk.CENTER)
image_label = tk.Label(canvas_frame, image=photo_image)
image_label.image = photo_image
image_label.pack(pady=(0, 5), anchor=tk.CENTER)
link_label = tk.Label(canvas_frame, text=recipe_link, fg="blue", cursor="hand2")
link_label.pack(pady=(0, 10), anchor=tk.CENTER)
link_label.bind("", lambda event, link=recipe_link: open_link(link))
recipe_labels.append(recipe_title_label)
recipe_images.append(photo_image)
recipe_links.append(link_label)
def clear_recipe_list():
recipe_list.clear()
for label in recipe_labels:
label.pack_forget()
recipe_labels.clear()
for image_label in recipe_images:
try:
image_label.pack_forget()
except Exception:
pass
recipe_images.clear()
for link_label in recipe_links:
link_label.pack_forget()
recipe_links.clear()
def open_link(link):
webbrowser.open(link) Полная сборка интерфейса (основные фрагменты)
Инициализация окна, frame, поля ввода, кнопки поиска и область прокрутки:
root = tk.Tk()
root.title("Recipe Finder")
root.geometry("600x600")
root.configure(bg="#F1F1F1")
frame = tk.Frame(root, bg="#F1F1F1")
frame.pack(fill=tk.BOTH, expand=tk.YES, padx=20, pady=20)
label_recipe_name = tk.Label(
frame, text="Enter Recipe Name:", font=("Helvetica", 14, "bold"), bg="#F1F1F1"
)
label_recipe_name.pack()
entry_recipe_name = tk.Entry(frame, font=("Helvetica", 12))
entry_recipe_name.pack(pady=5)
search_button = tk.Button(
frame,
text="Search Recipes",
font=("Helvetica", 12, "bold"),
command=get_top_5_recipes,
)
search_button.pack(pady=10)
canvas = tk.Canvas(frame, bg="white")
canvas.pack(side=tk.LEFT, fill=tk.BOTH, expand=tk.YES)
scrollbar = tk.Scrollbar(frame, orient=tk.VERTICAL, command=canvas.yview)
scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
canvas.configure(yscrollcommand=scrollbar.set)
canvas_frame = tk.Frame(canvas, bg="white")
canvas.create_window((0, 0), window=canvas_frame, anchor=tk.NW)
canvas_frame.bind("", lambda event: canvas.configure(scrollregion=canvas.bbox("all")))
recipe_list = []
recipe_labels = []
recipe_images = []
recipe_links = []
root.mainloop() Демонстрация вывода
При вводе «Chicken Burger» приложение покажет пять результатов — заголовок, изображение и ссылку; клик по ссылке откроет браузер по умолчанию, а полоса прокрутки позволит увидеть все элементы.
Улучшения и расширения (планы и идеи)
- Фильтры: диета (веган, без глютена), время приготовления, калории.
- Сортировка: по популярности, времени, рейтингу (если есть поле).
- Закладки: локальная база (SQLite) для сохранения любимых рецептов.
- Поделиться: интеграция с социальными сетями или копирование ссылки.
- Кэширование изображений и результатов для снижения числа запросов.
Хранение ключей и безопасность
Лучше не хранить app_id/app_key прямо в коде. Используйте:
- Файл .env, который не добавляется в Git (.gitignore).
- Переменные окружения на прод-сервере.
- Менеджеры секретов (для более серьёзных развёртываний).
Пример чтения ключей из .env:
from dotenv import load_dotenv
import os
load_dotenv()
app_id = os.getenv('EDAMAM_APP_ID')
app_key = os.getenv('EDAMAM_APP_KEY')Обработка ошибок и устойчивость
- Проверяйте статус ответа: response.status_code.
- Обрабатывайте исключения requests.exceptions.RequestException.
- На случай ошибок сети показывайте пользователю уведомление и предлагайте «Попробовать снова».
Пример базовой обработки:
try:
response = requests.get(api_url, params=params, timeout=10)
response.raise_for_status()
data = response.json()
except requests.exceptions.RequestException as e:
# Показать диалог об ошибке в GUI
print("Ошибка запроса:", e)
returnЛокализация и единицы измерения для русскоязычных пользователей
- Переводите заголовки интерфейса и кнопки: «Enter Recipe Name» → «Введите название рецепта», «Search Recipes» → «Найти рецепты».
- Приводите единицы времени (мин, ч) и веса (г, кг) к локальному формату, если вы будете показывать шаги рецепта.
- Будьте осторожны с названиями ингредиентов: в разных регионах одно и то же блюдо может называться по-разному.
Альтернативные подходы к источникам рецептов
- Другие API: Spoonacular, TheMealDB, Tasty API (при наличии доступа).
- Скрапинг сайтов рецептов — быстро, но требует соблюдения правил сайта и может нарушать ToS.
- Локальная база рецептов — хороша для оффлайн-режима и полной кастомизации.
Когда альтернативы не подходят: если нужен лицензированный контент или официальные данные о пищевой ценности — используйте официальные API.
Мини‑методология разработки (быстрый SOP)
- Подготовка: получить API ключ, настроить виртуальное окружение, .gitignore.
- MVP: рабочий поиск, отображение топ‑5, открытие ссылок.
- Тесты: базовые тесты GUI и интеграционные тесты запросов (mock ответа).
- Улучшения: фильтры, кеш, локализация, закладки.
- Релиз: упаковка как exe (pyinstaller) или снапшот для платформы.
Критерии приёмки
- Приложение запускается без ошибок на чистой машине с Python 3.8+.
- При вводе названия блюда отображаются максимум 5 карточек с заголовком, изображением и рабочей ссылкой.
- Ссылки открываются в браузере по умолчанию.
- Если сеть отсутствует — показывается понятная ошибка.
Ручной тест: примеры тест-кейсов
- Ввод пустой строки → ничего не ищем, уведомление «Введите название».
- Корректный запрос «pasta» → получено 1–5 рецептов, изображения загружены.
- Неверный app_key → обработка ошибки и сообщение пользователю.
- Большой ответ API → GUI остаётся отзывчивым (при необходимости вынесите работу в фоновый поток).
Role-based чек-листы
Разработчик:
- Настроить .env и .gitignore.
- Обработать исключения сети.
- Написать модульные тесты для парсинга ответа.
QA-инженер:
- Проверить UI на масштабирование и прокрутку.
- Проверить открытие ссылок на разных ОС.
- Смоделировать ошибки API и проверить поведение.
Дизайнер:
- Подобрать читаемые шрифты и отступы.
- Предложить варианты карточек рецептов (размеры изображений).
Производительность и масштабирование (советы)
- Кешируйте последние поисковые запросы и скачанные изображения в локальную папку.
- Для многопоточности скачивания изображений используйте ThreadPoolExecutor.
- Для веб-версии — вынесите логику обращений к API на серверную часть и кеширование.
Технический чек-лист безопасности и приватности
- Не храните ключи в публичных репозиториях.
- Не логируйте чувствительные данные.
- Для сбора персональных данных (например, закладки пользователя) предупредите о хранении данных и предоставьте способ удаления.
Модель принятия решений: когда использовать Edamam
- Если нужен быстрый старт с готовыми данными рецептов и изображениями — Edamam подходит.
- Если нужен полный контроль над контентом или оффлайн-доступ — лучше локальная база.
flowchart TD
A[Начало] --> B{Есть API ключ Edamam?}
B -- Да --> C[Использовать Edamam]
B -- Нет --> D{Можно оплатить API?}
D -- Да --> E[Зарегистрироваться и получить ключ]
D -- Нет --> F[Рассмотреть локальную БД или другой API]
C --> G[Реализовать поиск и UI]
F --> GПримеры кода и сниппеты (cheat sheet)
- Запрос с проверкой статуса:
resp = requests.get(api_url, params=params, timeout=10)
if resp.status_code != 200:
print('Ошибка API', resp.status_code)
else:
data = resp.json()- Скачивание и сохранение изображения в кэш:
from pathlib import Path
cache_dir = Path('cache')
cache_dir.mkdir(exist_ok=True)
img_path = cache_dir / 'recipe_123.jpg'
with requests.get(image_url, stream=True) as r:
r.raise_for_status()
with open(img_path, 'wb') as f:
for chunk in r.iter_content(1024):
f.write(chunk)Что делать, если что‑то идёт не так (runbook)
- Приложение не стартует — проверить версию Python и установленные зависимости.
- Нет ответов от API — проверить статус API и корректность app_id/app_key.
- Изображения не загружаются — проверить URL, обработать исключения Pillow.
- Программа подтормаживает — профиль производительности, перенос загрузки в отдельный поток.
Заключение
Это руководство даёт полный набор шагов от установки зависимостей до идей по расширению приложения «поиск рецептов». Начните с MVP, затем добавляйте фильтры, кеш, локализацию и хранение избранного. Приложение легко портируется в исполняемый файл или в веб‑версию при необходимости.
Важное: не публикуйте свои ключи в открытом доступе и тестируйте обработку ошибок сети.
Краткое резюме и шаги для старта: 1) получить ключ Edamam; 2) собрать минимальный интерфейс; 3) реализовать get_top_5_recipes(); 4) добавить обработку ошибок и кеширование.
Похожие материалы
RDP: полный гид по настройке и безопасности
Android как клавиатура и трекпад для Windows
Советы и приёмы для работы с PDF
Calibration в Lightroom Classic: как и когда использовать
Отключить Siri Suggestions на iPhone