#!/usr/bin/env python # coding: utf-8 # Pendant les vacances d'été, j'ai pris l'habitude de réécouter des épisodes du podcast [Rendez-vous avec X](https://fr.wikipedia.org/wiki/Rendez-vous_avec_X), tous archivés sur le site d'un passionné, . Le site propose une liste alphabétique des différents épisodes sur une page web. Il se trouve que je préfère utiliser une application de podcast, et que pour pouvoir relire tous ces épisodes, il me faut un flux RSS. Je propose donc dans ce billet de créer un flux RSS à partir du site que je viens de citer. # # **Le lien pour le gestionnaire de podcast est le suivant :** # # Un flux RSS ? # Un flux RSS est un fichier qui permet de déclarer les épisodes d'un podcast ainsi que de diffuser les liens vers les médias (mp3). La [page wikipédia](https://fr.wikipedia.org/wiki/RSS) propose l'exemple suivant : # # ``` # # # # Mon site # Ceci est un exemple de flux RSS 2.0 # Sat, 07 Sep 2002 00:00:01 GMT # http://www.example.org # # Actualité N°1 # Ceci est ma première actualité # Sat, 07 Sep 2002 00:00:01 GMT # http://www.example.org/actu1 # # # Actualité N°2 # Ceci est ma seconde actualité # Sat, 07 Sep 2002 00:00:01 GMT # http://www.example.org/actu2 # # # # ``` # Pour écrire un fichier RSS, nous allons donc tout d'abord récupérer les épisodes disponibles sur le site . # # Téléchargement des liens vers les épisodes # Nous allons partir de la page qui recense tous les épisodes par liste alphabétique : . Nous allons utiliser BeautifulSoup pour ceci. # In[1]: from bs4 import BeautifulSoup # In[2]: import requests # Dans un premier temps, nous téléchargeons la page : # In[3]: r = requests.get('http://rendezvousavecmrx.free.fr/page/liste.php') r.encoding = 'utf-8' # In[4]: soup = BeautifulSoup(r.text, 'html.parser') # Puis nous en extrayons les lignes qui contiennent chacun une émission : # In[5]: rows = soup.find('table').find_all('tr') # Enfin, nous extrayons de chaque ligne l'adresse vers la page dédiée : # In[6]: links = ['http://rendezvousavecmrx.free.fr/page/' + row.find_all('td')[1].find('a').attrs['href'] for row in rows] # Combien d'émissions trouvons nous ? # In[7]: len(links) # # Extraction des propriétés de chaque épisode # A partir de ces liens individuels, nous pouvons télécharger chacune des pages et en extraire les informations que nous cherchons. Prenons pour exemple le premier lien de la liste. # In[8]: link = links[6] link # On télécharge la page : # In[9]: r = requests.get(link) r.encoding = 'utf-8' # In[10]: soup = BeautifulSoup(r.text, 'html.parser') # In[11]: centre = soup.find(id='centre') # On en extrait la date de l'émission : # In[12]: [tag.next_sibling.strip() for tag in centre.find('strong').select('br')[:-1]] # Le lien de téléchargement : # In[13]: centre.find(id='telechargement').find('a').attrs['href'] # In[14]: centre.find(id='telechargement').find('a').attrs['href'].replace('..', 'http://rendezvousavecmrx.free.fr') # Ainsi que le titre : # In[15]: centre.find(id='titre').text.strip() # Et la description : # In[16]: centre.find(id='emission').text.strip() # Nous sommes prêts à écrire une fonction qui va nous permettre de générer les données dont nous avons besoin. # In[17]: from collections import OrderedDict # In[18]: def extract_props(r): """Extracts properties from request r.""" soup = BeautifulSoup(r.text, 'html.parser') centre = soup.find(id='centre') props = OrderedDict() props['date'] = [tag.next_sibling.strip() for tag in centre.find('strong').select('br')[:-1]] props['titre'] = centre.find(id='titre').text.strip() props['media'] = centre.find(id='telechargement').find('a').attrs['href'].replace('..', 'http://rendezvousavecmrx.free.fr') props['contenu'] = centre.find(id='emission').text.strip() return props # On vérifie que la fonction donne le résultat attendu : # In[19]: extract_props(r) # On peut maintenant faire une boucle sur chacune des émissions : # In[20]: import tqdm # In[21]: allprops = [] for link in tqdm.tqdm(links): r = requests.get(link) r.encoding = 'utf-8' allprops.append(extract_props(r)) # # Construction d'une table des épisodes classée par date # Avec les données précédentes, nous pouvons maintenant créer un grand tableau de toutes les émissions : # In[24]: import pandas as pd import dateparser # In[25]: df = pd.DataFrame(allprops) df['date'] = [items[0] for items in df['date']] df[df.titre == ''] = pd.np.nan df[df.media == 'http://rendezvousavecmrx.free.fr/audio/'] = pd.np.nan df = df.dropna() df['date'] = pd.to_datetime([dateparser.parse(date).date() for date in df.date]) df = df.sort_values(by='date') # In[26]: df # Pour finir, il nous faut rajouter à chaque item de la table la longueur du fichier mp3 en bytes (voir [ici](https://stackoverflow.com/questions/14270698/get-file-size-using-python-requests-while-only-getting-the-header)). # In[27]: byte_lengths = {} for media in tqdm.tqdm(df.media): r = requests.head(media) if r.status_code == 200: byte_lengths[media] = r.headers['content-length'] df['bytes'] = [byte_lengths[media] for media in df.media] df.head() # # Ecriture d'un fichier RSS # Pour écrire un fichier RSS avec Python, nous allons utiliser la libraire ElementTree. Nous suivons le schéma montré en haut du billet et ajoutons ligne par ligne les épisodes. # In[29]: import xml.etree.cElementTree as ET rss = ET.Element("rss", version="2.0") channel = ET.SubElement(rss, "channel") title = ET.SubElement(channel, "title") title.text = 'Podcast Rendez-vous avec X' image = ET.SubElement(channel, "image") image_url = ET.SubElement(image, "url") image_url.text = 'https://cdn.radiofrance.fr/s3/cruiser-production/2019/10/b3ceaae4-c8dc-4b1a-870a-7f24f80bdee4/1400x1400_rf_omm_0000021551_ite.jpg' description = ET.SubElement(channel, "description") description.text = "Podcast inofficiel de l'émission Rendez-vous avec X, tiré du site http://rendezvousavecmrx.free.fr/" for index, row in df.iterrows(): item = ET.SubElement(channel, "item") item_title = ET.SubElement(item, "title") item_title.text = row['titre'] item_description = ET.SubElement(item, "description") item_description.text = row['contenu'] item_pubdate = ET.SubElement(item, "pubDate") item_pubdate.text = row.date.strftime('%a, %d %b %Y 13:15:00') item_enclosure = ET.SubElement(item, "enclosure", url='{}'.format(row.media), length=row.bytes, type="audio/mpeg") tree = ET.ElementTree(rss) tree.write("files/podcast_mr_x.xml", encoding='utf-8') # Et voilà le travail ! Le lien à ajouter au gestionnaire de podcast est le suivant : . # *Ce billet a été écrit à l'aide d'un notebook Jupyter. Son contenu est sous licence BSD. Une vue statique de ce notebook peut être consultée et téléchargée ici : [20170811_RSSFeedMonsieurX.ipynb](http://nbviewer.ipython.org/urls/raw.github.com/flothesof/posts/master/20170811_RSSFeedMonsieurX.ipynb).*