#!/usr/bin/env python3 """ Médiathèques Plaine Commune - Recherche de livres Script de recherche dans le catalogue des médiathèques de Plaine Commune Utilise Selenium pour interagir avec l'interface web (JavaScript requis). Usage: python mediatheque_search.py "Carl Jung" python mediatheque_search.py --author "Jung" python mediatheque_search.py --title "rêves" python mediatheque_search.py --subject "psychologie" """ import argparse import sys import time from selenium import webdriver from selenium.webdriver.firefox.options import Options from selenium.webdriver.firefox.service import Service from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.common.keys import Keys from webdriver_manager.firefox import GeckoDriverManager class MediathequeSearch: """Recherche dans le catalogue des médiathèques de Plaine Commune""" BASE_URL = "https://mediatheques-plainecommune.fr/iguana/www.main.cls" SEARCH_URL = "https://mediatheques-plainecommune.fr/iguana/www.main.cls?surl=search&searchProfile=Recherche" def __init__(self, headless=True): """Initialise le driver Selenium""" options = Options() if headless: options.add_argument("--headless") options.add_argument("--width=1920") options.add_argument("--height=1080") service = Service(GeckoDriverManager().install()) self.driver = webdriver.Firefox(service=service, options=options) self.driver.implicitly_wait(5) def _reject_cookies(self): """Refuse la bannière cookies RGPD""" try: refuse_btn = WebDriverWait(self.driver, 3).until( EC.element_to_be_clickable((By.ID, "gdpr-cookie-refuse")) ) refuse_btn.click() time.sleep(0.5) return True except: return False def _load_search_page(self): """Charge la page de recherche""" self.driver.get(self.BASE_URL + "?surl=axiell") time.sleep(2) self._reject_cookies() self.driver.get(self.SEARCH_URL) time.sleep(3) self._reject_cookies() def search(self, query, max_results=20): """ Effectue une recherche dans le catalogue Args: query: Terme de recherche max_results: Nombre maximum de résultats à retourner Returns: Liste de dictionnaires contenant les résultats """ try: self._load_search_page() # Entrer la requête search_input = self.driver.find_element(By.CSS_SELECTOR, "input[id*='inputWords']") search_input.clear() search_input.send_keys(query) search_input.send_keys(Keys.RETURN) # Attendre les résultats time.sleep(5) self._reject_cookies() # Extraire les résultats results = [] items = self.driver.find_elements(By.CSS_SELECTOR, "li.listItem") for item in items[:max_results]: try: result = self._extract_result(item) if result: results.append(result) except Exception: continue # Infos de pagination try: page_info = self.driver.find_element(By.CSS_SELECTOR, ".pageInfo").text except: page_info = None return { "query": query, "results": results, "page_info": page_info, "total_found": len(results) } finally: self.driver.quit() def _extract_result(self, item): """Extrait les informations d'un résultat""" result = {} # Titre try: result["title"] = item.find_element(By.CSS_SELECTOR, ".briefMainTitle").text.strip() except: result["title"] = "N/A" # Auteur try: result["author"] = item.find_element(By.CSS_SELECTOR, ".BriefAuthorpco").text.strip() except: result["author"] = "N/A" # Type de document try: result["type"] = item.find_element(By.CSS_SELECTOR, ".briefTypeDoc").text.strip() except: result["type"] = "N/A" # Disponibilité try: result["availability"] = item.find_element(By.CSS_SELECTOR, ".briefAvailability span").text.strip() except: result["availability"] = "N/A" # Résumé try: summary = item.find_element(By.CSS_SELECTOR, ".briefResume").text.strip() result["summary"] = summary[:200] + "..." if len(summary) > 200 else summary except: result["summary"] = "" return result def search_author(self, author, max_results=20): """Recherche par auteur""" return self.search(f"auteur: {author}", max_results) def search_title(self, title, max_results=20): """Recherche par titre""" return self.search(f"titre: {title}", max_results) def search_subject(self, subject, max_results=20): """Recherche par sujet""" return self.search(f"sujet: {subject}", max_results) def print_results(data): """Affiche les résultats formatés""" print(f"\n{'='*60}") print(f"RECHERCHE: {data['query']}") print(f"{'='*60}\n") for i, result in enumerate(data["results"], 1): print(f"📚 {i}. {result['title']}") print(f" Auteur: {result['author']}") print(f" Type: {result['type']}") print(f" Disponibilité: {result['availability']}") if result['summary']: print(f" Résumé: {result['summary']}") print() if data['page_info']: print(f"📄 {data['page_info']}") def main(): parser = argparse.ArgumentParser( description="Recherche dans le catalogue des médiathèques de Plaine Commune", formatter_class=argparse.RawDescriptionHelpFormatter, epilog=""" Exemples: %(prog)s "Carl Jung" %(prog)s --author "Jung" %(prog)s --title "rêves" %(prog)s --subject "psychologie" --max 50 """ ) parser.add_argument("query", nargs="?", help="Terme de recherche") parser.add_argument("--author", "-a", help="Rechercher par auteur") parser.add_argument("--title", "-t", help="Rechercher par titre") parser.add_argument("--subject", "-s", help="Rechercher par sujet") parser.add_argument("--max", "-m", type=int, default=20, help="Nombre max de résultats (défaut: 20)") parser.add_argument("--no-headless", action="store_true", help="Afficher le navigateur") args = parser.parse_args() # Déterminer le type de recherche if args.author: searcher = MediathequeSearch(headless=not args.no_headless) results = searcher.search_author(args.author, args.max) elif args.title: searcher = MediathequeSearch(headless=not args.no_headless) results = searcher.search_title(args.title, args.max) elif args.subject: searcher = MediathequeSearch(headless=not args.no_headless) results = searcher.search_subject(args.subject, args.max) elif args.query: searcher = MediathequeSearch(headless=not args.no_headless) results = searcher.search(args.query, args.max) else: parser.print_help() sys.exit(1) print_results(results) return 0 if __name__ == "__main__": sys.exit(main())