Projet Prolog : un résumeur de site Web

L'objectif final du projet est de réaliser une application SWI-Prolog qui, à partir d'une URL, résume automatiquement en une unique page HTML tout le site Web accessible de cette URL. Par exemple, voici le résumé de cette URL. Les sections qui suivent vous guident pas à pas dans cette réalisation.

Pretty-print

Pour visualiser des termes SWI-Prolog, on peut s'aider de la relation pretty_print/1 définie dans ce fichier. Récupérez ce fichier en local, compilez-le et testez cette relation sur divers termes, par exemple f(X,[a,b,C],g(0,c,[6])).

Lancer un navigateur

  1. Créez et sauvegardez en local un fichier html bidon.html (vous pouvez éventuellement utiliser l'éditeur de SWI-Prolog pour cela) avec un titre et plusieurs niveaux de balises ol imbriqués, du texte et des nombres.
  2. Cherchez comment lancer le navigateur par défaut de votre système d'exploitation à partir de SWI-Prolog (essayez par exemple apropos(www)). A l'aide de cette relation, visualisez la page d'acceuil de Google ainsi que votre fichier bidon.html.

Ecrire du code statique HTML

Lisez cette section du manuel concernant les entrées/sorties. Le nom du flux correspondant à la sortie standard est user_output. Définissez la relation staticTable_browser/0, n'utilisant que la relation prédéfinie write/2 pour créer un fichier ts.html d'une page HTML contenant la table des carrés de 1 à 5. Browsez.
Indications : commencez par afficher sur user_output. Dans un second temps, écrivez dans un fichier nommé st.html.

Parser et générer dynamiquement du code HTML

SWI-Prolog dispose de nombreux packages, dont la librairie sgml, qui se charge sous SWI-Prolog à l'aide de la directive :- use_module(library(sgml)).
  1. Etudiez la page HTML qui documente ce package.
  2. Quelle relation de ce package pouvez-vous utiliser pour lire sous SWI-Prolog de l'HTML en local ? Testez-la pour lire le fichier bidon.html. Pretty-printez le terme lu. Analysez ce terme. Faites de même pour le fichier st.html.
  3. Quelle relation pouvez-vous utiliser pour écrire de l'HTML en local à partir d'un terme Prolog représentant de l'HTML ? Définissez la relation dynamic_table(+N,-Thtml) qui génère le terme HTML d'une page HTML intitulée Table contenant la table des carrés de 1 à N. Ecrivez le code HTML dans un fichier et browsez cette page.
    Indications : lisez cette section pour la manipulation d'atomes. Ecrivez un code Prolog temporaire avec affichage sur la sortie standard user_output. Ecrivez le code demandé.

Parcourir un arbre en profondeur d'abord

Considérez l'arbre représenté comme suit :
edges(a,[b,c,d]). edges(b,[e,f]). edges(c,[g]).
edges(d,[]).      edges(e,[]).    edges(f,[]).  edges(g,[]).
Définissez la relation tree_thtml(+N,-T) qui génère le terme HTML représentant un parcours préfixe main gauche en profondeur d'abord de l'arbre (ou du sous arbre) commençant au noeud N. Par exemple (la sortie a été éditée pour une meilleure lisibilité)  :
?- tree_thtml(b,T),pretty_print(T).
[ b,
  element(ul,[],
          [ element(li,[],[e]),
            element(li,[],[f])])].

T = [b, element(ul, [], [element(li, [], [e]), element(li, [], [f])])] ;

No
?-

Parcourir un graphe orienté en profondeur d'abord

Considérez le graphe :
edges2(a,[b,c,d]). edges2(b,[a,e,f]). edges2(c,[b,g]).
edges2(d,[]).      edges2(e,[b]).     edges2(f,[]).    edges2(g,[]).
Définissez la relation graph_thtml(+N,-T) qui génère le terme HTML représentant un parcours préfixe main gauche en profondeur d'abord du graphe commençant au noeud N. Par exemple :
?- graph_thtml(a,T),pretty_print(T).
[ a,
  element(ul,[],
          [ element(li,[],
                    [ b,
                      element(ul,[],
                              [ element(li,[],[a]),
                                element(li,[],
                                        [ e,
                                          element(ul,[],
                                                  [ element(li,[],[b])])]),
                                element(li,[],[f])])]),
            element(li,[],
                    [ c,
                      element(ul,[],
                              [ element(li,[],[b]),
                                element(li,[],[g])])]),
            element(li,[],[d])])].

T = [a, element(ul, [], [element(li, [], [b, element(ul, [], [element(li, [], [a]), element(li, [], [e, element(ul, [], [element(li, [], [b])])]), element(li, [], [f])])]), element(li, [], [c, element(ul, [], [element(li, [], [b]), element(li, [], [g])])]), element(li, [], [d])])] ;

No
Indications : attention aux cycles ! Définissez la relation not_member(+Xs,+X), vraie ssi X n'est pas élément de Xs, en vous aidant de la relation prédéfinie dif/2. Utilisez la relation memberchk/2 (help(memberchk) pour plus d'information). La relation graph_thtml/2 peut faire appel à une relation auxiliaire où vous maintenez, via une paire d'arguments, la liste des sommets déjà visités. Avisez suivant l'appartenance du sommet courant à cette liste.

Télécharger une page externe

  1. Parmi les packages de SWI-Prolog, parcourez la documentation de celui qui pourrait vous permettre de ramener en local un fichier via le protocole HTTP.
  2. Pretty-printez le terme HTML associé à la page http://www.w3.org/TR/html4/about.html.

Récupérer le titre et les hrefs

  1. Définissez la relation html_title(+Thtml,-Titre)Titre est le titre de la structure Thtml d'une page HTML valide. Utilisez la relation memberchk/2. Testez.
  2. Définissez la relation html_hrefTxts(+Thtml,-HrefTxts)HrefTxts est une liste des paires lien/texte de la structure Thtml d'une page HTML valide. Testez.

Gérer les URLs

Pour résoudre les questions suivantes, vous pourrez vous aider de la library(url).
  1. Définissez la relation url_base(+URL,?Base)Base est le préfixe maximum d'URL à partir duquel on parcourt un site Web d'URL URL. Par exemple :
    ?- url_base('http://www.example.org/index.html',B).
    
    B = 'http://www.example.org/' ;
    
    No
    ?- url_base('http://www.example.org/~john',B).
    
    No
    ?- url_base('http://www.example.org/~john/',B).
    
    B = 'http://www.example.org/~john/' ;
    
    No
    Indications : auparavant lire la section concernant la manipulation des atomes sous SWI-Prolog.
  2. Définissez la relation is_internal_url(+URL,+Base) vraie ssi URL est une URL interne relativement à Base. Par exemple :
    ?- is_internal_url('test/index.html','http://www.ex.org/').
    
    Yes
    ?- is_internal_url('test','http://www.ex.org/').
    
    No
    ?- is_internal_url('test.html','http://www.ex.org/').
    
    Yes
    ?- is_internal_url('test/','http://www.ex.org/').
    
    Yes
    ?- is_internal_url('mailto://john.doe@ex.org','http://www.ex.org/').
    
    No
    ?- 
  3. Définissez la relation url_base_absolute(+URL,+Base,-FullURL)FullURL est l'URL absolue par rapport à Base de l'URL possiblement relative URL.
    ?- url_base_absolute('index.html','http://www.example.org/',F).
    
    F = 'http://www.example.org/index.html' ;
    
    No
    ?- url_base_absolute('test/index.html','http://www.example.org/',F).
    
    F = 'http://www.example.org/test/index.html' ;
    
    No
    ?- url_base_absolute('http://www.example.org/index.html','http://www.example.org/',F).
    
    F = 'http://www.example.org/index.html' ;
    
    No
    ?- url_base_absolute('~john/index.html','http://www.example.org/',F).
    
    F = 'http://www.example.org/~john/index.html' ;
    
    No
    ?- url_base_absolute('test/index.html','http://www.example.org/',F).
    
    F = 'http://www.example.org/test/index.html' ;
    
    No
    ?- url_base_absolute('test/../index.html','http://www.example.org/',F).
    
    F = 'http://www.example.org/test/../index.html' ;
    
    No
    ?- 

Résumer un site Web en une unique page HTML

Définissez la relation url_summary(+URL,-Thtml) qui résume le site d'adresse URL en une page HTML représentée par le terme Thtml. Ce résumé reflète la structure du site Web, avec les liens externes et internes du site.
  1. Dans un premier temps, vous supposerez que le site Web à résumer se limite à une unique page.
  2. Il se peut que l'URL soit erronée. Quels sont cas possibles ? Gérez avec catch/3.
  3. Ensuite, définissez un parcours récursif des pages accessibles à partir de cette URL.

Documenter

Documentez et ajoutez des tests unitaires à votre programme.

Transformer en script

Transformez votre programme en un script comme indiqué ici.

Créer une application

  1. Ajoutez une fenêtre de dialogue modal pour l'entrée de l'URL. Vous trouverez un exemple ici.
  2. Compilez.

Finaliser

Sous Mac OS X :
  1. Vous pouvez finaliser en utilisant Platypus pour créer une application OS X. Ces indications peuvent être utiles.
  2. Vous souhaitez éviter X11 ? Platypus peut se combiner avec CocoaDialog.
  3. Notez que Platypus peut également servir d'installeur, en particulier d'une application bundlée par Platypus !
Le packaging de votre application pour d'autres plateformes m'intéresse. Voici quelques infos.
Fred Mesnard

Valid XHTML 1.0 Transitional