Sur cette page
Python est le chemin le plus court entre une question et sa réponse : qu’est-ce qui passe ce soir dans ma ville, quels films ont le plus de séances cette semaine, où voir ce film en VO près de chez moi. Ce tutoriel répond aux trois avec requests et pandas, en quatre petits fichiers qui tournent tels quels.
$ python tonight.py Lyon
Ce soir à Lyon : 163 séances, 48 filmsCe qu’il vous faut
- Python 3.9 ou plus récent.
- Une clé API Cinéma : créez un compte gratuit, confirmez votre adresse e-mail, puis créez une clé depuis le tableau de bord. L’offre gratuite donne 150 requêtes par semaine pour les tests et les projets non commerciaux ; chaque script ci-dessous en coûte une à trois.
python -m venv .venv && source .venv/bin/activate
pip install requests pandas
export API_CINEMA_KEY="ac_live_…"Un mini-client : api_cinema.py
Deux fonctions : get fait un appel, all_pages parcourt une longue liste de séances page après page.
import os
import time
import requests
API = "https://api.api-cinema.com/v1"
session = requests.Session()
session.headers["Authorization"] = f"Bearer {os.environ['API_CINEMA_KEY']}"
def get(path, **params):
"""Un GET sur l’API. Attend puis réessaie une fois si la limite par minute est atteinte (HTTP 429)."""
for attempt in range(2):
res = session.get(f"{API}{path}", params=params, timeout=30)
wait = int(res.headers.get("Retry-After", "0"))
# limite par minute ; au-delà du quota hebdo l’attente court jusqu’à lundi : abandon
if res.status_code == 429 and attempt == 0 and wait <= 60:
time.sleep(wait)
continue
res.raise_for_status()
return res.json()
def all_pages(path, **params):
"""Toutes les lignes d’une liste de séances, page après page, en suivant meta.nextCursor."""
params.setdefault("limit", 1000)
while True:
page = get(path, **params)
yield from page["data"]
cursor = page["meta"].get("nextCursor")
if not cursor:
return
params["cursor"] = cursor- La clé va dans l’en-tête
Authorization, lue dans l’environnement : ne la versionnez jamais. - Au-delà de la limite par minute (60 requêtes par clé sur les offres standard), l’API répond
429avecRetry-After, les secondes à attendre. Au-delà du quota hebdomadaire elle répond aussi429, mais l’attente court jusqu’au lundi : le script s’arrête plutôt. meta.nextCursorest la façon stable de parcourir un long résultat : 1 000 lignes par page, aucune ligne sautée ni répétée même si le programme change entre-temps.
Qu’est-ce qui passe ce soir : tonight.py
import sys
from collections import defaultdict
from datetime import date
from api_cinema import get
city = sys.argv[1] if len(sys.argv) > 1 else "Lyon"
today = date.today().isoformat()
# from / to s’entendent à l’heure locale de chaque cinéma : 18:00, c’est 18 h à Lyon comme à Chicago
res = get("/showtimes", city=city, **{"from": f"{today}T18:00", "to": f"{today}T23:59"}, limit=1000)
films = defaultdict(list)
for s in res["data"]:
films[s["movie"]["title"]].append(f"{s['startsAt'][11:16]} {s['cinema']['name']} ({s['version']})")
print(f"Ce soir à {city} : {len(res['data'])} séances, {len(films)} films\n")
for title, times in sorted(films.items(), key=lambda f: -len(f[1]))[:10]:
print(title)
for t in sorted(times)[:5]:
print(" ", t)python tonight.py Lyon
python tonight.py Chicagofrom et to acceptent une date ou une date et une heure, toujours dans le fuseau de chaque cinéma : le même script marche pour une ville française et une ville américaine. city compare exactement le nom de la commune : Paris couvre ses arrondissements mais pas sa banlieue.
Une semaine de séances dans un tableur : week_csv.py
all_pages récupère toutes les séances de la ville sur 7 jours (une grande ville tient en deux ou trois requêtes), pandas les aplatit dans un CSV et répond à deux questions.
import sys
from datetime import date, timedelta
import pandas as pd
from api_cinema import all_pages
city = sys.argv[1] if len(sys.argv) > 1 else "Lyon"
start = date.today()
end = start + timedelta(days=6)
rows = [
{
"date": s["startsAt"][:10],
"time": s["startsAt"][11:16],
"cinema": s["cinema"]["name"],
"film": s["movie"]["title"],
"tmdb_id": s["movie"]["tmdbId"],
"version": s["version"],
"format": s["format"],
"booking_url": s["bookingUrl"],
}
for s in all_pages("/showtimes", city=city, **{"from": start.isoformat(), "to": end.isoformat()})
]
df = pd.DataFrame(rows).astype({"tmdb_id": "Int64"}) # les ids restent des entiers malgré les valeurs manquantes
df.to_csv(f"showtimes-{city.lower()}-{start}.csv", index=False)
print(f"{len(df)} séances enregistrées, {start} → {end}\n")
print("Films les plus programmés cette semaine :")
print(df.groupby("film").size().sort_values(ascending=False).head(10).to_string())
print("\nPart des séances en version originale (VO + VOST) :")
print(f"{df['version'].isin(['VO', 'VOST']).mean():.0%}")$ python week_csv.py Lyon
1755 séances enregistrées, 2026-10-31 → 2026-11-06
Films les plus programmés cette semaine :
film
Moulin 129
Quelques mots d'amour 108
…Le CSV s’ouvre dans Excel, Google Sheets ou un notebook. En France, la plupart des cinémas publient la semaine suivante le lundi ou le mardi, pour les sorties du mercredi : lancez le script le mercredi pour avoir une semaine complète.
Un film près de chez moi : near_me.py
On cherche le film par son titre, puis ses séances autour d’un point.
import sys
from api_cinema import get
title = sys.argv[1] if len(sys.argv) > 1 else "Karma"
lat, lng = 45.7640, 4.8357 # centre de Lyon : mettez vos coordonnées
movies = get("/movies", q=title, playing="true", limit=5)["data"]
if not movies:
sys.exit(f"Aucun film à l’affiche ne correspond à {title!r}")
movie = movies[0]
# tmdb_id réunit toutes les séances du film, quel que soit le titre publié par chaque cinéma
film = {"tmdb_id": movie["tmdbId"]} if movie["tmdbId"] else {"movie_id": movie["id"]}
res = get("/showtimes", **film, near=f"{lat},{lng}", radius_km=5, limit=50)
print(f"{movie['title']} : prochaines séances à moins de 5 km\n")
for s in res["data"][:15]:
print(f"{s['startsAt'][:10]} {s['startsAt'][11:16]} {s['version']:<5} {s['cinema']['name']}")python near_me.py KarmaDeux cinémas peuvent publier le même film sous des titres légèrement différents ; tmdb_id (identifiant The Movie Database) les réunit tous. near=lat,lng avec radius_km donne les séances triées par heure autour de n’importe quel point, dans une agglomération que city couperait.
Pour aller plus loin
- Chaque semaine, automatiquement.
crontab -e, puis0 9 * * 3 cd ~/seances && .venv/bin/python week_csv.py Lyonexporte la nouvelle semaine chaque mercredi à 9 h. - Versions originales. Ajoutez
version="VOST"(ouVO) à n’importe quel appel de séances pour une liste de ciné-club. - Seulement ce qui a changé. Pour une base tenue à jour,
updated_since=<date ISO>renvoie les séances ajoutées, modifiées ou retirées depuis le dernier passage (les retirées ontremovedAtrenseigné). - Affiches et réservation. Chaque film a un
posterUrl, chaque séance unbookingUrl.
Chaque paramètre et chaque champ sont dans la documentation ; le guide pour la France et le guide pour les États-Unis montrent les autres recherches.