AMRANI Raihana
MSDI 2024-2025
Système De Recherche
D'animes En Intégrant Une
API
Objectif :
Ce projet consiste à créer un système de recherche d’animes en intégrant une API
spécialisée avec Python. L’application permet de trouver rapidement des animes en
saisissant une partie d’un titre, en exploitant la richesse des données de l’API. Ces
données sont récupérées en temps réel et traitées pour afficher des résultats
pertinents. L’objectif est de démontrer l’efficacité des API pour offrir une expérience
fluide et rapide. Ce projet illustre comment le traitement des données peut répondre
aux besoins des utilisateurs.
Fonctionnalités à inclure :
1. Initialisation de la fenêtre principale
*initialise la fenêtre principale de l'application en définissant son titre, sa taille, sa
couleur de fond et en appelant la méthode create_widgets() pour créer les éléments
de l'interface utilisateur. Elle configure également une variable pour stocker
éventuellement le contenu saisi par l'utilisateur.
2. Création des éléments de l'interface utilisateur
* crée un titre, un champ de recherche, et une zone de défilement où les résultats de
recherche seront affichés, permettant à l'utilisateur de saisir une recherche et de voir
les résultats de manière fluide.
3. Recherche d'animes via l'API
*cette fonction permet de récupérer les résultats de recherche d'animes depuis l'API
Jikan et d'afficher ou de vider les résultats en fonction de la saisie de l'utilisateur.
4. Affichage du titre de l'anime et gestion du clic :
*.cette fonction affiche le titre d'un anime dans un label cliquable et ouvre les détails
de l'anime lorsque l'utilisateur clique dessus.
voici le resultat
voici le code 📺
from tkinter import Tk, Label, Entry, Frame, Scrollbar, Canvas
from PIL import Image, ImageTk
import requests
import io
class AnimeApp:
def __init__(self, main_window):
# Initialize the main window and set up the app
self.main_window = main_window
self.main_window.title("Anime Recommendation") # Set window
title
self.main_window.geometry("600x700") # Set window size
self.main_window.configure(bg="#fefefe") # Set background color
self.input_content = None
self.create_widgets()
def create_widgets(self):
Label(self.main_window, text="Discover New Animes",
font=("Helvetica", 18, "bold"), fg="red", bg="#fefefe").pack(pady=10)
# Create the search input
self.search_entry = Entry(self.main_window, font=("Helvetica",
14), width=40)
#like the width to the input
self.search_entry.pack(pady=10)
self.search_entry.bind("<KeyRelease>", self.debounce) # Bind
key release for debounce
# Create a canvas and scrollbar for displaying results
#creat graphics like widget
canvas = Canvas(self.main_window, bg="#fefefe")
scrollbar = Scrollbar(self.main_window, orient="vertical",
command=canvas.yview)
scroll_frame = Frame(canvas, bg="white")
scroll_frame.bind("<Configure>", lambda e:
canvas.configure(scrollregion=canvas.bbox("all"))) # Update scroll
region
canvas.create_window((0, 0), window=scroll_frame, anchor="nw")
# Create window for scrolling
canvas.configure(yscrollcommand=scrollbar.set) # Link scrollbar
with canvas
# Pack canvas and scrollbar
canvas.pack(side="left", fill="both", expand=True, padx=10)
scrollbar.pack(side="right", fill="y")
self.results_frame = scroll_frame
def debounce(self, event):
# Cancel the previous scheduled search (if there is one)
if self.input_content is not None:
#method oo tk
self.main_window.after_cancel(self.input_content)
# Schedule the new search call after 500ms
self.input_content = self.main_window.after(500,
self.search_anime)
def search_anime(self):
# Get the search input and make an API call if not empty
search = self.search_entry.get().strip()
if len(search) == 0:
# Clear input is empty
# method info_children() retrieves a list of all widgets
(children) contained within the
for widget in self.results_frame.winfo_children():
widget.destroy()
return
url = f"https://api.jikan.moe/v4/anime?q={search}"
response = requests.get(url) # Fetch data from the API
api = response.json() # Parse the JSON response
# Clear previous search results
for widget in self.results_frame.winfo_children():
widget.destroy()
if 'data' in api:
# If there are results, loop through and display them
row = 0 # Start from the first row
col = 0 # Start from the first column
for anime in api['data']:
# frame group its image and title together.
anime_frame = Frame(self.results_frame, bg="white",
pady=10)
anime_frame.grid(row=row, column=col, padx=10, pady=5)
# Display anime image and title
self.display_anime_image(anime, anime_frame)
self.display_anime_title(anime, anime_frame)
# Update column and row for next anime
col += 1
if col == 4: # Move to the next row after 4 items
col = 0
row += 1
# Make sure all columns expand equally
for i in range(4):
self.results_frame.grid_columnconfigure(i, weight=1,
uniform="equal")
else:
# If no results found, display a message
Label(self.results_frame, text="No results found.",
font=("Helvetica", 14), bg="white").pack(pady=20)
def display_anime_image(self, anime, frame):
# Display the anime image, if available
try:
image_url = anime['images']['jpg']['image_url']
image_response = requests.get(image_url) # Fetch image data
image_data =
Image.open(io.BytesIO(image_response.content)).resize((100, 150)) #
Resize the image
anime_image = ImageTk.PhotoImage(image_data) # Convert to a
format suitable for Tkinter
image_label = Label(frame, image=anime_image) # Create a
label for the image
image_label.image = anime_image # Keep a reference to avoid
garbage collection
image_label.pack(side="left", padx=10) # Pack the image
label
except Exception:
pass # Skip if image is not available
def display_anime_title(self, anime, frame):
# Display the anime title and bind it to open details when
clicked
title_label = Label(frame, text=anime['title'],
font=("Helvetica", 14), bg="white", wraplength=400, justify="left",
cursor="hand2")
title_label.pack(side="left", padx=10)
title_label.bind("<Button-1>", lambda event, anime=anime:
self.open_details(event, anime)) # Bind click event
def open_details(self, event, anime):
# Open a new window with detailed information about the selected
anime
details_window = Tk()
details_window.title(anime['title']) # Set window title
details_window.geometry("600x600") # Set window size
# Display anime image in the details window
self.display_anime_image(anime, details_window)
# Display various details about the anime
Label(details_window, text=anime['title'], font=("Helvetica",
18, "bold")).pack(pady=10)
Label(details_window, text=f"Rating: {anime['rating']}",
font=("Helvetica", 14)).pack(pady=5)
Label(details_window, text=f"Episodes: {anime['episodes']}",
font=("Helvetica", 14)).pack(pady=5)
# Display genres
genres = ', '.join([genre['name'] for genre in anime['genres']])
Label(details_window, text=f"Genres: {genres}",
font=("Helvetica", 14)).pack(pady=5)
details_window.mainloop() # Run the details window
if __name__ == "__main__":
root = Tk() # Create the main window
app = AnimeApp(root) # Instantiate the app class
root.mainloop() # Start the Tkinter main loop