API des séances de cinéma en Python : ce soir, une semaine en CSV, un film près de chez soi

Trois scripts Python avec requests et pandas : ce qui passe ce soir dans une ville, une semaine de séances exportée en CSV, et les prochaines séances d’un film autour d’un point.

4 min de lecture

Sur cette page
  1. Ce qu’il vous faut
  2. 1.Un mini-client
  3. 2.Qu’est-ce qui passe ce soir
  4. 3.Une semaine de séances dans un tableur
  5. 4.Un film près de chez moi
  6. Pour aller plus loin

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 films

Ce 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.
Terminal
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.

api_cinema.py
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 429 avec Retry-After, les secondes à attendre. Au-delà du quota hebdomadaire elle répond aussi 429, mais l’attente court jusqu’au lundi : le script s’arrête plutôt.
  • meta.nextCursor est 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

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)
Terminal
python tonight.py Lyon
python tonight.py Chicago

from 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.

week_csv.py
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.

near_me.py
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']}")
Terminal
python near_me.py Karma

Deux 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, puis 0 9 * * 3 cd ~/seances && .venv/bin/python week_csv.py Lyon exporte la nouvelle semaine chaque mercredi à 9 h.
  • Versions originales. Ajoutez version="VOST" (ou VO) à 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 ont removedAt renseigné).
  • Affiches et réservation. Chaque film a un posterUrl, chaque séance un bookingUrl.

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.