Outils pour utilisateurs

Outils du site


nsi:tds:flux_rss

Ceci est une ancienne révision du document !



Warning: Undefined array key 1 in /home/goupillf/wiki.goupill.fr/lib/plugins/codeprettify/syntax/code.php on line 172

Warning: Undefined array key 1 in /home/goupillf/wiki.goupill.fr/lib/plugins/codeprettify/syntax/code.php on line 149

Warning: Trying to access array offset on value of type null in /home/goupillf/wiki.goupill.fr/lib/plugins/codeprettify/syntax/code.php on line 149

Warning: Undefined array key 1 in /home/goupillf/wiki.goupill.fr/lib/plugins/codeprettify/syntax/code.php on line 172

Warning: Undefined array key 1 in /home/goupillf/wiki.goupill.fr/lib/plugins/codeprettify/syntax/code.php on line 172

Warning: Undefined array key 1 in /home/goupillf/wiki.goupill.fr/lib/plugins/codeprettify/syntax/code.php on line 172

Warning: Undefined array key 1 in /home/goupillf/wiki.goupill.fr/lib/plugins/codeprettify/syntax/code.php on line 172

Warning: Undefined array key 1 in /home/goupillf/wiki.goupill.fr/lib/plugins/codeprettify/syntax/code.php on line 149

Warning: Trying to access array offset on value of type null in /home/goupillf/wiki.goupill.fr/lib/plugins/codeprettify/syntax/code.php on line 149

Warning: Undefined array key 1 in /home/goupillf/wiki.goupill.fr/lib/plugins/codeprettify/syntax/code.php on line 172

Warning: Undefined array key 1 in /home/goupillf/wiki.goupill.fr/lib/plugins/codeprettify/syntax/code.php on line 149

Warning: Trying to access array offset on value of type null in /home/goupillf/wiki.goupill.fr/lib/plugins/codeprettify/syntax/code.php on line 149

Warning: Undefined array key 2 in /home/goupillf/wiki.goupill.fr/lib/plugins/codeprettify/syntax/code.php on line 214

Warning: Undefined array key 2 in /home/goupillf/wiki.goupill.fr/lib/plugins/codeprettify/syntax/code.php on line 214

Warning: Undefined array key 2 in /home/goupillf/wiki.goupill.fr/lib/plugins/codeprettify/syntax/code.php on line 214

Warning: Undefined array key 2 in /home/goupillf/wiki.goupill.fr/lib/plugins/codeprettify/syntax/code.php on line 214

Warning: Undefined array key 2 in /home/goupillf/wiki.goupill.fr/lib/plugins/codeprettify/syntax/code.php on line 214

Warning: Undefined array key 2 in /home/goupillf/wiki.goupill.fr/lib/plugins/codeprettify/syntax/code.php on line 214

Warning: Undefined array key 2 in /home/goupillf/wiki.goupill.fr/lib/plugins/codeprettify/syntax/code.php on line 214

Warning: Undefined array key 2 in /home/goupillf/wiki.goupill.fr/lib/plugins/codeprettify/syntax/code.php on line 214

Warning: Undefined array key 2 in /home/goupillf/wiki.goupill.fr/lib/plugins/codeprettify/syntax/code.php on line 214

Warning: Undefined array key 2 in /home/goupillf/wiki.goupill.fr/lib/plugins/codeprettify/syntax/code.php on line 214

Warning: Undefined array key 2 in /home/goupillf/wiki.goupill.fr/lib/plugins/codeprettify/syntax/code.php on line 214

Warning: Undefined array key 2 in /home/goupillf/wiki.goupill.fr/lib/plugins/codeprettify/syntax/code.php on line 214

Chargement d'un flux RSS

Cet exercice reprend des méthodes vues dans ce TD.

Objectif : Afficher les titres d'un flux RSS.

RSS, qu'est ce que c'est ?

Le RSS (Really Simple Syndication) est un format de fichier dont le contenu est produit automatiquement pour tenir compte des mises à jours sur un site web (par exemple)

Syndication ou souscription : système qui consiste à vendre / fournir à plusieurs diffuseurs le droit de reproduire un contenu ou de diffuser un programme. Le diffuseur de contenu est appelé syndicate.

Imaginons une situation :

  • A est un site produisant podcasts (par exemple www.franceculture.fr). De nouveaux podcasts sont produits régulièrement.
  • B est une application sur téléphone qui permet de s'abonner à divers podcasts.

A souhaite que ces podcasts soient écoutés et B souhaite que ses utilisateurs puissent voir facilement tous les podcasts disponibles. Il est donc essentiel que A publie une liste à jour de ses podcasts pour que B puisse y accéder.

Cette liste est un fichier RSS. Le fichier RSS est presque toujours produit automatiquement par l'environnement qui permet à A d'entretenir son site : à chaque nouveau podcast déposé sur le site, une nouvelle entrée dans le fichier RSS est automatiquement créée.

Comme ce fichier RSS se remplit et se vide tout seul à mesure que les nouveaux podcasts sont créés puis deviennent périmés, on parle de flux. C'est donc un flux RSS.

Bien sûr, j'ai parlé de podcasts, mais tout ce qui a été dit est valable pour n'importe quel type de contenu : des vidéos, des images, des articles, des news, des tweets…

Format du flux RSS

Prenons l'exemple du flux RSS des articles de France Info : https://www.francetvinfo.fr/titres.rss

Le fichier obtenu est au format *.xml. C'est un simple fichier texte qui ressemble à :

<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Franceinfo - Les Titres</title>
    <description>Franceinfo - Les Titres</description>
    <pubDate>Tue, 08 Jun 2021 19:03:00 +0200</pubDate>
    <generator>francetvinfo 2021 (https://www.francetvinfo.fr)</generator>
    <link>https://www.francetvinfo.fr/titres/</link>
    <atom:link rel="self" type="application/rss+xml" href="https://www.francetvinfo.fr/titres.rss"/>
    <item>
      <title>Emmanuel Macron giflé : cinq questions sur l'agression subie par le président de la République</title>
      <description><![CDATA[Le chef de l'Etat a reçu une gifle lors d'un déplacement à Tain-l'Hermitage (Drôme), mardi. "Rien ne change sur les prochains déplacements", assure l'Elysée.]]></description>
      <pubDate>Tue, 08 Jun 2021 18:44:39 +0200</pubDate>
      <link>https://www.francetvinfo.fr/politique/emmanuel-macron/emmanuel-macron-gifle-lors-d-un-deplacement-dans-la-drome/emmanuel-macron-gifle-cinq-questions-sur-l-agression-subie-par-le-president-de-la-republique_4655901.html#xtor=RSS-3-[lestitres]</link>
      <guid>https://www.francetvinfo.fr/politique/emmanuel-macron/emmanuel-macron-gifle-lors-d-un-deplacement-dans-la-drome/emmanuel-macron-gifle-cinq-questions-sur-l-agression-subie-par-le-president-de-la-republique_4655901.html#xtor=RSS-3-[lestitres]</guid>
      <enclosure type="image/jpeg" length="21675" url="https://www.francetvinfo.fr/image/75wmi7lt0-0257/500/281/24758405.jpg"/>
    </item>
    <item>
      <title>"Intolérable", "inadmissible"... A gauche comme à droite, les responsables politiques condamnent unanimement l'agression d'Emmanuel Macron</title>
      <description><![CDATA[Le chef de l'Etat a été giflé mardi par un individu lors de son déplacement dans la Drôme, à la rencontre des restaurateurs.]]></description>
      <pubDate>Tue, 08 Jun 2021 17:51:30 +0200</pubDate>
      <link>https://www.francetvinfo.fr/politique/emmanuel-macron/emmanuel-macron-gifle-lors-d-un-deplacement-dans-la-drome/intolerable-inadmissible-a-gauche-comme-a-droite-les-responsables-politiques-condamnent-unanimement-l-agression-d-emmanuel-macron_4655879.html#xtor=RSS-3-[lestitres]</link>
      <guid>https://www.francetvinfo.fr/politique/emmanuel-macron/emmanuel-macron-gifle-lors-d-un-deplacement-dans-la-drome/intolerable-inadmissible-a-gauche-comme-a-droite-les-responsables-politiques-condamnent-unanimement-l-agression-d-emmanuel-macron_4655879.html#xtor=RSS-3-[lestitres]</guid>
      <enclosure type="image/jpeg" length="29261" url="https://www.francetvinfo.fr/image/75wmi7nvl-0fff/500/281/24758373.jpg"/>
    </item>
  </channel>
</rss>
Il n'y a que deux articles dans ce flux. Je l'ai abrégé. Le flux original est beaucoup plus long.

Le format XML est lourd et un peu pénible. C'est un format à balises comme HTML. Néanmoins il est très utilisé, c'est bien d'en avoir entendu parlé.

Quelques exemples ici dans ce fichier :

  • La balise <rss> s'ouvre ligne 2 et se referme ligne 27. Elle contient l'ensemble du flux.
  • Dans ce flux il n'y a qu'une seule chaîne (channel), la balise s'ouvre ligne 3 et se ferme ligne 26.
  • Cette chaîne est décrite par les balises des lignes 4 à 9 (title, description…)
  • Une série (juste 2 dans cet exemple abrégé) de balises <item>...</item> suivent. Ce sont les articles. Le premier commence ligne 10 et termine ligne 17.
  • À l'intérieur de chaque article, d'autres balises donnent des informations. Pour le premier article par exemple, lignes 11 à 16, title, description, …
Notez une différence avec HTML : en HTML, les balises <a>, <div>, etc. sont toutes des balises appartenant à la norme HTML. Il n'est pas prévu que l'on rajoute nos propres balises. En XML c'est différent. XML décrit seulement l'organisation des balises mais nous sommes libres de créer des balises avec les noms que l'on veut, du moment que l'on respecte la forme <balise>...</balise> ou éventuellement <balise options />.

XML avec Python

Dans la plupart des langages, on pourra trouver des bibliothèques de fonctions permettant de gérer facilement les fichiers XML.

En python on pourra utiliser xml.dom.minidom :

import xml.dom.minidom as xml
# si le xml est dans un fichier, par ex flux_rss.xml :
xml_doc = xml.parse('flux_rss.xml')

# si le xml est dans une chaîne de caractère, par ex reponseXML
xml_doc = xml.parseString(reponseXML)

Le document est construit sous forme d'un arbre (pensez à un arbre généalogique) : une balise enferme d'autres balises qui sont ses enfants. Une des balise (dans l'exemple la balise <rss> contient l'ensemble. C'est la racine.

root = xml_doc.documentElement # racine

On peut ensuite parcourir les enfants, les enfants des enfants :

for article in root.getElementsByTagName('item'):
    # article correspond à un noeud <item> trouvez sous la racine
    child0 = article.childNodes[0] # premier noeud enfant de article
    print(child0.data ) # contenu du noeud

Implémentation Python

La solution proposée est en 3 parties :

  1. connexion au flux RSS de France Info (fait)
  2. analyse du contenu du fichier reçu avec XML (à faire)
  3. affichage des titres (à faire)
Remarque : La plupart des sites sont aujourd'hui en https, c'est à dire chiffrés. Cela occasionne quelques complications. J'ai commenté autant que possible pour que vous compreniez le principe général. Dans tous les cas, gardez à l'esprit que, en fonction des évolutions des technologies, on est obligé de s'adapter. Par exemple, ici, j'ai découvert la bibliothèque python ssl à l'occasion de cet exercice. On a donc besoin de savoir lire des documentations sur internet pour prendre en main ces outils.
# lecture flux RSS

import socket       # pour création socket TCP-IP
import ssl          # gestion chiffrement pages https

# le flux qui nous sert d'exemple est un flux d'actualité sur wwww.francetvinfo.fr
# on donne l'adresse du serveur (domaine)
hostname = 'www.francetvinfo.fr'

# adresse du flux lui-même
address = 'https://www.francetvinfo.fr/titres.rss'

# création d'un contexte sécurisé avec ssl
context = ssl.SSLContext()

HTTP_VERSION = 1.0
CRLF = "\r\n\r\n"

# Dans certains cas on utilise une ressource. Il faut demander au système d'exploitation
# de nous donner accès à cette ressource puis il faut lui dire quand on libère cette ressource.
# ex : ouverture / fermeture de fichier ; ouverture / fermeture de connexion
# avec le mot clé with, on crée un bloc qui réserve la ressource
# puis la libère dès qu'on sort du bloc.

# 443 est le port habituel pour https
with socket.create_connection((hostname, 443)) as sock:
    # sock est "emballé" dans le contexte sécurisé (donnée cryptée) avec ssl
    with context.wrap_socket(sock, server_hostname=hostname) as ssock:
        # lancement la requête GET en précisant l'adresse
        ssock.send("GET {} HTTP/{} {}".format(address, HTTP_VERSION, CRLF).encode())
        # la taille de la réponse est inconnue.
        # on réceptionne par morceaux de 1024 octets.
        reponseXML = "" # au début la réponse est vide.

        while True:
            block = ssock.recv(1024)
            if not block:
                # block est vide, il n'y a plus rien à récupérer
                # sortie de la boucle
                break

            # À l'usage je n'ai pas pu clairement définir l'encodage utilisé...
            # le bloc qui suit consiste à tenter (try) un décodage en utf-8
            # et si cette tentative provoque une erreur,
            # recommencer mais avec un décodage en iso
            try:
                reponseXML += block.decode("utf-8")
            except:
                reponseXML += block.decode("ISO-8859-2")

# arrivé à ce point, reponseXML contient le texte de réponse.
# chargement de la bibliothèque xml
import xml.dom.minidom as xml

# votre travail :
def getTitles(texteXml):
    '''
    texteXml : le texte XML dans lequel chercher
    retourne l'ensemble des titres (contenus dans <title>...</title>)
    sous forme d'une liste.
    '''
    # à vous !
    pass

# Et pour finir, utilisez la fonction getTitles pour obtenir les titres
# et affichez-les.

En ligne 14 j'ai changé l'ancien context = ssl.create_default_context() qui ne fonctionnait plus pour ssl.SSLContext(). Ce n'est pas idéal car ce choix fait qu'on ne vérifie pas le certificat ssl du site. Cela nous évite les erreurs mais est potentiellement dangereux (les certificats sont là pour la sécurité). Toutefois, dans le cadre de ce TP on échange aucune donnée sensible et on ne risque rien.

Tout le bloc des lignes 1 à 49 permet de comprendre le principe de l'échange. On peut passer par des modules qui font le tout de façon plus courtes.

import ssl
import urllib.request as req
url = "https://www.francetvinfo.fr/titres.rss"
context = ssl.SSLContext()  # supprime la vérification du ssl
reponseXML = req.urlopen(url, context=context).read()
nsi/tds/flux_rss.1685075783.txt.gz · Dernière modification : de 40.77.167.146