Il y a quelques temps maintenant, quand j'ai commencé à lire quotidiennement sur mon ebook, j'ai rapidement souhaité être en mesure de lire des articles provenant de web sur ma liseuse. Après un rapide tour d'horizon, je n'avais rien trouvé à l'époque (cela remonte quand même à un petit bout de temps maintenant), et je m'étais donc lancé dans le développement d'une solution personnelle.

Après quelques réflexions, j'ai développé les outils suivants :

  • HTML::Excerpt::FromXPath ; cet outil permet d'extraire une partie d'une page web sur base d'une expression XPath, à cette époque, je n'avais pas encore entendu parlé du merveilleux outil développé par Arc90, j'ai nommé Readability 1
  • Mobigen::Command ; cet outil était juste un wrapper du programme mobigen_linux qui permettait de convertir un fichier HTML en fichier Mobibook ; il est bon de noter que mobigen_linux a été remplacé par kindlegen (disponible gratuitement même si ce n'est pas libre) ;
  • HTML::Image::Save ; cet outil permet de sauvegarder les images d'un fichier HTML, et de modifier ce dernier de manière à faire correspondre les liens des images vers les versions locales ;
  • App::uri2mobi ; est l'outil exploitant ces trois outils précédents dans une interface en ligne de commande.

Par (mauvaise) paresse, je n'ai jamais pris le temps de mettre ces modules sur CPAN 2, mais cela ne m'empêche pas d'en parler quand même.

Donc, dans le cas qui nous occupe aujourd'hui, nous allons voir HTML::Image::Save. L'utilisation de ce dernier est aussi simple que possible :

my $img_saver = HTML::Image::Save->new(
   output_dir => './',
   img_dir => 'images',
);
$img_saver->html( $html );
$img_saver->output_html( 'web_scraping.html' );
$img_saver->save();

Comme le HTML pouvait venir de différents sources (fichiers en local ou récupéré directement sur le web), j'ai préféré la solution la plus simple, à savoir prévoir une méthode pour obtenir le code HTML.

En ce qui concerne le code lui-même, il n'y a pour ainsi que la méthode save() qui est intéressante :

sub save {
    my $self = shift;

    croak "No base URL" unless $self->base_url;
    croak "No HTML" unless $self->html;
    
    my $resolver = HTML::ResolveLink->new(
        base => $self->base_url
    );
    
    my $html = $resolver->resolve($self->html);

    my $tree = HTML::TreeBuilder->new_from_content( $html );
    my @img = $tree->find('img');

    $self->_build_directories();
    
    foreach my $image (@img) {
        my $remote_link = $image->attr('src');
        my $local_link = $self->_get_local_link($remote_link);
        getstore($remote_link, $local_link);
        $image->attr('src', $local_link);
        if ($self->callback) {
            $self->callback->($self, $image, $local_link);
        }
    }

    $self->html($tree->as_HTML());

    if ($self->output_html()) {
        open my $fh, '>', $self->output_html;
        print $fh $self->html();
        close $fh;
    }

    return $self->html();   
}

Cette dernière s'appuie sur HTML::ResolveLink pour modifier le HTML de manière à transformer tout les liens en liens absolus, sur HTML::TreeBuilder pour parcourir les images du code HTML, et enfin sur LWP::Simple pour récupérer les images.

Bref, rien de bien compliqué, et une chouette exploitation du CPAN me permettant d'avoir l'outil qu'il faut, rapidement, et sans trop de prises de tête.

Notes de bas de page:

1 il existe maintenant deux modules permettant de reproduire le comportement de Readability : HTML::ExtractMain et HTML::ExtractContent, donc, dans mes futurs outils, il est plus que probable que j'utiliserai ces derniers.

2 mais je vais le faire, promis !

Perl est une planète

| Aucun Commentaire | Aucun Trackback

Avec un temps de retard, je viens de lire le billet de Jean Véronis intitulé « Ontologies: Perl est une planète du système solaire », (une version anglaise de l'article est disponible).

Et donc, mis-à-part l'intérêt intrinsèque du billet, vive Perl ;-)

En lisant le dernier « PragPub: The First Iteration » (le n°9, disponible sur le site de PragProg), dans l'article « JavaScript: It's Not Just for Browsers Any More » de Jason Huggins, je suis tombé sur une réflexion intéressante :

When we choose a technology to write an application, we don't just choose the language, we also choose the list of available libraries. If a language has many useful libraries with a vibrant community around them, it's going to be easier to write your application in less time.

Bon, dans mon cas, cela m'a fait pensé au Perl et au CPAN, mais je suis sûr que d'autres liront autres choses :)

Pearltrees, RDF & Perl

| 2 Commentaires | Aucun Trackback

Suite à quelques discussions récentes, je me suis replonger dans les arcanes du RDF. En effet, Pearltrees offrant une possibilité d'exportation des favoris en RDF, ma curiosité naturelle m'a poussée à investiguer de manière à savoir ce que je pouvais faire concrètement avec ce fichier. En plus, @SebDeclercq a été assez gentil que pour me transmettre sa propre sauvegarde, m'épargnant ainsi la tâche fastidieuse d'enrichir mes propres Pearltrees.

Donc, j'ai un fichier contenant plein de liens, et maintenant, je veux exploiter ces informations. Comment faire ? Comme indiqué dans le billet du blog de Nicolas Cynober, nous pouvons utiliser un outil comme SPARQLer pour manipuler les informations. Dans SPARQLer, vous pourrez soumettre votre requête écrite en SPARQL, et obtenir une réponse sous différent format :

  • en XML, avec la possibilité de renseigner un script XSLT permettant de transformer le document (par exemple en XHTML) ;
  • en JSON ;
  • ou encore simplement en texte.

Donc, c'est un outil très intéressant, mais il faut être en ligne, et personnellement, j'aime bien avoir mes outils directement disponibles, quelque soit mes accès au web. Et donc, se pose la question de savoir ce que je peux avoir directement sur ma machine. Un petit tour par le CPAN, et hop, voici quelques modules prometteurs :

  • RDF::Redland ;
  • RDF::Trine ;
  • et celui qu'il me faut pour interroger le fichier via la SPARQL : RDF::Query.

Un petit cpan RDF::Query plus tard, je me retrouve donc avec un module permettant d'interroger en SPARQL un store RDF.

Mais comment faire passer mon fichier pearltrees_export.rdf dans un store RDF ? Relativement simplement, RDF::Trine propose dans son répertoire bin quelques exemples de scripts qui vont nous aider :

  • rdf_init_store.pl qui, comme son nom l'indique, permet d'initialiser un magasin RDF ; j'ai donc lancé la commande suivante pour initialiser ma base de données : ./rdf_init_store.pl sqlite ./pearltrees.db '' '' pearltrees ce qui signifie donc :
    1. initialise une base de données en utilisant SQLite ;
    2. le nom de cette base de données est ./pearltrees.db 1;
    3. le premier '' permet de spécifier le nom d'utilisateur pour la base de données, et il n'y en a pas dans le cas présent ;
    4. le second '' permet de spécifier le mot de passe, idem que précédemment2
    5. et finalement, pearltrees est le nom du modèle de données RDF, ici j'ai arbitrairement donné le nom de pearltrees ;
    6. la commande une fois lancée me donne un message d'avertissement : Log4perl: Seems like no initialization happened. Forgot to call init()?, mais quand je vérifie via un sqlite3 pearltrees.db, je constate que les tables (Bnodes, Literals, Models, Resources et Statement2742456113224982524) ont bien été créées, donc, pas de soucis !
  • rdf_store_add_file.pl qui permet d'ajouter un fichier dans la base de données de triplets ; ce script s'utilise de la manière suivante ./rdf_store_add_file.pl sqlite ./pearltrees.db '' '' pearltrees sebdeclercq.rdf, ce qui suit la logique du script précédent (utilisation de SQLite, le nom de la base de données, le nom d'utilisateur, le mot de passe et le nom du modèle de données RDF.

Sur mon EeePC 1005HA, voici quelques statistiques :

  • pour un fichier RDF de 421515 octets, j'obtiens une base de données de 1872896 octets ;
  • le traitement du fichier prend un peu de temps, voici le résultat de time :
real    16m52.234s
user    3m33.573s
sys     0m17.757s

Après l'exécution de rdf_store_add_file.pl, nous nous retrouvons donc avec une base de données qui pourra servir de base à RDF::Query.

Voici un petit script illustrant l'utilisation de RDF::Query :

#!/usr/bin/env perl

use strict;
use warnings;

use RDF::Trine;
use RDF::Trine::Store::DBI;
use RDF::Query;
use Data::Dump;

my $sparql = <<'SPARQL';
PREFIX pt: <http://www.pearltrees.com/rdf/0.1/>
PREFIX owl: <http://www.w3.org/2002/07/owl#>
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX dc: <http://purl.org/dc/elements/1.1/>

SELECT ?title ?url
WHERE {
   ?pearl rdf:type pt:pearl;
          dc:title ?title;
          owl:sameAs ?url;
          pt:parentTree ?tree
}
ORDER BY DESC (?tree)
SPARQL

my $store =
  RDF::Trine::Store::DBI->new( 'pearltrees', 'DBI:SQLite:dbname=./pearltrees.db', '', '' );
my $model = RDF::Trine::Model->new($store);

my $querier = RDF::Query->new($sparql);

my $iterator = $querier->execute($model);
while ( my $row = $iterator->next ) {
    print $row->{title} . ' ' . $row->{url} . "\n";
}

Voilà pour aujourd'hui. Je suis en train de travailler sur un script s'appuyant sur HTTP::Server::Simple et Template::Declare afin d'avoir une interface plus agréable pour tester mes requêtes SPARQL.

Keep in touch…

Notes de bas de page:

1 puisque nous utilisons SQLite, la base de données est en fait un fichier

2 dans le cas d'une base de données MySQL, cela aurait été nécessaire évidemment

« On se tient au courant ! »

| Aucun Commentaire | Aucun Trackback

Récemment, au détour de GitHub, j'ai vu un projet intéressant : growlme. Pour ceux qui ne connaissent pas Growl, il s'agit d'un système de notification non intrusif. Imaginez que vous lancez la gravure d'un DVD, et pendant ce temps-là vous en profitez pour travailler sur un article ou un billet de blog. Traditionnellement, les logiciels de gravure vous afficheront une petite fenêtre à la fin de la grave, interrompant ainsi ce que vous étiez en train de faire. Avec les systèmes de notification comme Growl, une fenêtre volante apparaîtra en haut à droite de l'écran signalant la fin de la gravure. Growl est uniquement disponible sur Mac1, mais il existe des systèmes équivalent sur Linux (libnotify entre autres).

growlme permet de lancer un programme en ligne de commande et d'être tenu au courant du résultat de son exécution via Growl. Comme il m'arrive souvent de lancer un processus assez long via la ligne de commande, et de m'atteler à d'autres tâches entre-temps, j'aimerais bien avoir l'équivalent sur mon Linux.

Le résultat n'est pas bien long et exploite Desktop::Notify, c'est-à-dire l'interface Perl à libnotify, IPC::Run pour lancer la commande, Getopt::Long pour traiter les paramètres en ligne de commande (notez l'usage de Getopt::Long::Configure('pass_through') pour conserver un @ARGV, ainsi que Sys::Hostname pour avoir le titre de la notification. Pour le reste, j'ai singé le programme originel.

#!/usr/bin/env perl

use strict;
use warnings;

use Desktop::Notify;
use IPC::Run qw( run );
use Getopt::Long;
use Sys::Hostname;

my $config = {
    message => 'Succeed!',
    fail    => 'FAILED',
    title   => hostname(),
};

Getopt::Long::Configure('pass_through');
GetOptions( $config, 'message=s', 'fail=s', 'title=s' );

if ( scalar(@ARGV) == 0 ) {
    die "$0: must provide a command to execute\n";
}
else {
    my $notify = Desktop::Notify->new();
    my $notification;

    eval { run \@ARGV };
    my $exitcode = $? >> 8;
    if ( $exitcode == 0 ) {
        $notification = $notify->create(
            summary => $config->{title},
            body    => $config->{message},
            timeout => 5000,
        );
    }
    else {
        $notification = $notify->create(
            summary => $config->{title},
            body    => $config->{fail},
            timeout => 5000,
        );
    }

    $notification->show();
    $notification->close();
}

J'ai créé un gist sur GitHub de cet outil.

Pearltrees

| 2 Commentaires | Aucun Trackback

Pearltrees

Suite à un commentaire sur son blog, @SebDeclercq a expliqué les raisons de son choix concernant Pearltrees. En résumé (et il me corrigera si j'ai mal compris) :

  1. besoin d'un outil permettant d'effectuer des sauvegardes de ces favoris ;
  2. cet outil devait être en ligne pour pouvoir être utilisé depuis plusieurs machines ;
  3. le système de classement proposé doit être efficace, et le classement visuel sous forme d'arbre rencontrait ses attentes.

De mon côté, je partage le besoin d'un système permettant de gérer mes favoris. J'ai utilisé pendant un temps Delicious, mais à un moment, j'ai abandonné l'habitude d'y déposer les ressources jugées intéressantes au profit d'un petit outil développé par mes soins. Dans sa réponse @SebDeclercq signale que son utilisation de Pearltrees passe essentiellement par l'extension Firefox. Je n'avais pas pris le temps de tester ce dernier. D'abord parce que mon navigateur principal est maintenant Chromium, et aussi par manque de temps. J'avais donc testé l'outil offert par Pearltrees, à savoir le bookmarklet, mais je n'en étais pas nécessairement content. Ce dernier déposait les perles (comprendre les URL que vous souhaitez conserver) dans un panier, et il vous restait encore à « ranger » ces perles. Et donc, devoir utiliser cette interface en Flash que je trouve particulièrement rebuttante1. Bref, dans ces conditions, il m'était difficile d'adopter Pearltrees dans ma boîte à outils.

Mais l'article de @SebDeclercq m'a obligé à revisiter l'outil, et donc, cette fois-ci j'ai pris le temps de lancer un Mozilla Firefox, et d'installer l'extension. Et j'ai donc pu comprendre pourquoi c'était un outil intéressant pour gérer ses favoris :

  • l'évidente intégration dans le navigateur ;
  • la mise à disposition d'un bouton vous permettant de choisir où placer votre perle, et donc, cela vous dispense de passer par le site, et donc d'éviter l'interface Flash ;
  • un bouton permettant de lancer votre Pearltrees.

Néanmoins, malgré tout, je ne pense pas inclure Pearltrees dans ma boîte à outil pour les raisons suivantes :

  • absence d'API à ce jour : de mon point de vue, c'est vraiment le plus gros point noir de cet outil. En effet, dans le web 2.0 qui est le nôtre, et dans le web 3.0 ou le web des données qui pointe le bout de son nez, la présence d'un API est essentielle2 ! Ainsi, si j'ai du mal avec l'interface Flash, la présence d'une API m'aurait permis de développer un interface en ligne de commande comme je les aime. Mais là, ce n'est pas avec l'export RDF que je vais aller bien loin3 puisque je dois me connecter pour réaliser cet exportation ;
  • les fonctionnalités de l'outil ne dépasse pas de beaucoup celle d'un Delicious. Bon, la structure arborescente est vraiment chouette, l'aspect visualisation est intéressante4, le fait de pouvoir « capturer » un pearltree est vraiment très sympathique, mais pour le reste, je crains de reproduire le même schéma qu'avec Delicious ;
  • à côté de cela, j'ai découvert dernièrement via un tweet de @MarioAsselin un outil plus en accord avec mes besoins : Diigo, je l'utilise depuis maintenant une semaine, et même si je dois encore améliorer mon workflow personnel de PKM afin de faire un peu de place à Diigo, j'ai peut-être trouvé une réponse adéquate à mes besoins.

Diigo

Alors, voici en bref les fonctionnalités qui m'ont séduit :

  1. présence d'une API ; bon, OK, elle n'est pas complète, mais elle permet déjà
    de récupérer les informations sur les favoris, et donc, à moi de jouer pour
    l'intégrer dans mes workflows personnels ; j'ai déjà jeté les premières pierres pour réaliser cette opération, mais je dois encore continuer
    (vivement le week-end !) ;
  2. existence d'une extension pour Chromium (et évidemment, une extension est
    également disponible pour Firefox, mais je n'ai pas encore pris le temps de
    la tester) ;
  3. possibilité d'annoter les pages lues ; ces annotations peuvent être
    récupérées via l'API et dans les fonctions d'export de l'outil ;
  4. plusieurs formats d'exportation (IE Bookmark, Netscape Bookmark, RSS, CSV et
    Delicious) ;
  5. Diigo crée un snapshot du lien sauvegardé, cela signifie donc que même si
    le lien n'est plus disponible, vous avez une version disponible dans votre
    bibliothèque Diigo
  6. possibilité de créer des liens privés ;
  7. possibilité de créer des listes, et ces dernières peuvent également être
    privées ;
  8. possibilité de créer des groupes, c'est un aspect communautaire
    supplémentaire par rapport à Delicious, utilisé entre autres par le groupe UQ de partage sur la techno pédagogie et sur les technologies ou les environnements numériques d'apprentissage.

Bref, intéressant, non ?

Conclusion

Bon, j'ai été long, mais je pense que le sujet en vaux la peine : comment garder une trace de ses lectures sur le web. Une réflexion de base pour des spécialistes de l'information, mais aussi, et de plus en plus pour M. Tout-le-monde qui doit faire preuve d'une littératie de plus en plus importante. Quant au choix de l'outil, il importe finalement peu pour autant que ce dernier réponde aux besoins de l'utilisateur. 

Et comme je suis pour une diversité maximale de l'écologie des outils et des
logiciels : longue vie à Pearltrees et à Diigo !!! 

Notes de bas de page:

1 les raisons en sont relativement simples :

  • je travaille sur des machines différentes, et une de ces machine est un Asus EeePC 1005HA, donc, un écran 10", ce qui rend l'interface Flash particulièrement irritante ;
  • même sur des écrans plus grands, je trouve cette interface terriblement lente ; je suis particulièrement peu patient avec les interfaces de logiciels, et j'aime que la limite soit ma capacité à exploiter le logiciel, dans le cas présent, je dois attendre l'interface, et cela m'irrite au plus au point, cette philosophie explique probablement mon addiction à la ligne de commande.

2 Il me reste évidemment la possibilité d'analyser le fonctionnement du bookmarklet et de l'extension pour savoir comment construire les requêtes, etc. Bref, du reverse engineering qui me prendra du temps, et me distraira d'autres projets ;

3 cet export RDF peut difficilement être qualifié de bonne nouvelle, je vous met au défi de faire quoi que ce soit avec ce fichier RDF. Cela signifie donc que vous pouvez exporter vos données ... mais aucun logiciel actuel n'est capable de manipuler le format en question. Cool. Un export CSV ou, mieux encore, tout autre format habituellement géré par les navigateurs aurait été le bienvenu !

4 cela me rappelle l'histoire de KartOO, qui a commencé par l'interface « carte » (une innovation pour un métamoteur) puis qui a fini par proposer le choix entre une interface « carte » et une interface plus classique. En espérant que l'histoire se termine mieux pour Pearltrees puisque qu'apparemment, KartOO, c'est fini !!

Dans le cadre d'un cours d'un cours de Gestion numérique des connaissances, je parle un peu d'information retrieval. Juste les bases, mais bon, cela me paraît important de savoir comment fonctionne un moteur de recherche, surtout pour de futurs spécialistes de l'information et de la documentation. Parmi ces bases, nous avons la manière dont un moteur de recherche perçoit le texte qu'il doit indexer. Si la théorie est facile à appréhender, cela ne m'empêche pas de rajouter une couche visuelle, et c'est pour cette raison que j'ai écrit un petit permettant d'illustrer cette phase de l'indexation.

Le script a été développé sur un temps de midi, un peu avant de donner le cours, et donc, je n'ai pas travaillé l'ergonomie et la mise en page de l'outil. Pour réaliser rapidement l'outil, j'ai utilisé les outils suivants :

Pour le reste, le code est assez simple :

#!/usr/bin/env perl

use strict;
use warnings;

package MyView::Templates;
use Template::Declare::Tags;
use base 'Template::Declare';

private template form => sub {
    my $self  = shift;
    my $title = shift;

    div {
        attr { style => 'margin: auto; size: 15%;', };
        form {
            attr {
                action => '/submit',
                method => 'POST',
            };
            textarea {
                attr {
                    cols  => '100',
                    rows  => '25',
                    name  => 'title',
                    style => 'float: left;',
                };
                $title;
            };
            input {
                attr {
                    name  => 'submit',
                    type  => 'submit',
                    value => 'Soumettre',
                    style => 'float: left;',
                };
            };
            input {
                attr {
                    name  => 'reset',
                    type  => 'reset',
                    value => 'Réinitialiser',
                    style => 'float: left;',
                };
            };
            div { attr { style => 'clear: both;' } };
        };
    };

};

template main => sub {
    my $self  = shift;
    my $title = shift;

    html {
        head {};
        body {
            show( 'form', $title );
        };
    };
};

private template data => sub {
    my $self   = shift;
    my $result = shift;

    div {
        attr { style => 'margin: auto; width: 40%' };
        h1 {
            "Résultat de l'analyse";
        };
    }
    div {
        ol {
            foreach my $word ( sort keys %$result ) {
                li { $word . " : " . $result->{$word} };
            }
        };
    };
};

template result => sub {
    my $self   = shift;
    my $title  = shift;
    my $result = shift;

    html {
        head {};
        body {
            show( 'form', $title );
            hr {};
            show( 'data', $result );
        };
    }
};

package MyWebServer;

use HTTP::Server::Simple::CGI;
use base qw(HTTP::Server::Simple::CGI);
use Text::ExtractWords qw(words_count);

use Template::Declare;
Template::Declare->init( dispatch_to => ['MyView::Templates'] );

my %dispatch = (
    '/'       => \&resp_homepage,
    '/submit' => \&resp_submit,
);

sub handle_request {
    my $self = shift;
    my $cgi  = shift;

    my $path    = $cgi->path_info();
    my $handler = $dispatch{$path};

    if ( ref($handler) eq "CODE" ) {
        print "HTTP/1.0 200 OK\r\n";
        $handler->($cgi);

    }
    else {
        print "HTTP/1.0 404 Not found\r\n";
        print $cgi->header( -charset => 'UTF-8' ),
          $cgi->start_html('Not found'),
          $cgi->h1('Not found'),
          $cgi->end_html;
    }
}

sub resp_homepage {
    my $cgi = shift;
    return if !ref $cgi;

    print $cgi->header( -charset => 'UTF-8' ), Template::Declare->show('main');
}

sub resp_submit {
    my $cgi = shift;
    return if !ref $cgi;

    my $title  = $cgi->param('title');
    my $result = {};
    words_count( $result, $title, {} );

    print $cgi->header( -charset => 'UTF-8' ),
      Template::Declare->show( 'result', $title, $result );
}

package main;

my $server = MyWebServer->new(9999);
$server->run();

J'ai créé un gist de cet outil sur Github, et je compte l'améliorer quand j'aurai un peu de temps.

Dernièrement sur la liste de diffusion perl4lib, une question a été posée concernant l'existence d'une solution permettant de diviser un fichier MARC trop gros en plusieurs fichiers plus petits.

Comme beaucoup d'utilisateurs de fichiers MARC, et de programmeurs manipulant des fichiers MARC, j'ai été confronté à ce problème et j'avais développé une petite solution rapide :

#!/usr/bin/env perl

use strict;
use warnings;

use MARC::File::USMARC;
use MARC::Record;

use Getopt::Long;

my $config = { output => 'input' };

GetOptions($config, 'input=s', 'chunk=s', 'output=s', 'max=s');

if (not exists $config->{input} and not exists $config->{chunk}) {
    die "Usage: $0 --input file --chunk size [--output file]\n";
} else {
    run($config->{input}, $config->{output}, $config->{chunk}, $config->{max});
    
}

sub run {
    my ($input, $output, $chunk, $max) = @_;

    my $marcfile = MARC::File::USMARC->in($input);
    
    my $fh = $output eq 'input' ? create_file($input) : create_file($output);
    my $cpt = 1;
        my $total = 0;
    while (my $record = $marcfile->next) {
        $total++;
        
        if (defined $max) {
            last if $total > $max;
        }
        if ($cpt++ > $chunk) {
            close $fh;
            $fh = $output eq 'input' ? create_file($input) : create_file($output);
            $cpt = 1;
        } 

        print $fh $record->as_usmarc;
    }   
    close $fh;
}

sub create_file {
    my ($output) = @_;
    my $cpt = 0;
    
    my $filename = sprintf('%s.%03d', $output, $cpt++);
    while (-e $filename) {
        $filename = sprintf('%s.%03d', $output, $cpt++);
    }

    open my $fh, '>', $filename;
    return $fh;
}

Cet outil est l'exemple même de solution qu'un bibliothécaire - documentaliste devrait être à même de programmer (pour autant qu'il souhaite programmer, bien entendu). L'algorithme employé est loin d'être compliqué (même si cela reste un bon exercice), et il s'agit d'une exploitation de modules existants (vive le CPAN !) pour lesquels il existe de la documentation. Bref, un bel exemple de paresse et de spécicialisation.

Néanmoins, une meilleure solution que ce marcsplit.pl est sans aucun doute l'utilisation de l'utilitaire yaz-marcdump comme l'indique Sébastien Hinderer. Voici quelques exemples :

  • yaz-marcdump -C 5000 export.mrc : cela créera des fichiers de 5000 notices dont le nom sera de la forme suivante : 0000001, 0000002, etc
  • yaz-marcdump -C 5000 -s export_by_5000- export.mrc : permettra de spécifier un préfixe aux fichiers créés, dans l'exemple, cela nous donnera des fichiers de la forme suivante : export_by_5000-0000001, export_by_5000-0000002, etc

Un coup d'oeil sur les calendriers

| Aucun Commentaire | Aucun Trackback

Depuis quelques années maintenant, une initiative de la communauté Perl, que l'on peut appeler une tradition maintenant, s'organise à cette période. Il s'agit d'un calendrier de l'Avent. Du premier décembre au jour de Noël (l'Avent donc), un article est publié pour expliquer tantôt un module, tantôt une technique, ou encore un élément de la culture d'un monger 1.

A ma connaissance, il existe quatre calendriers de l'Avent dans la communauté Perl cette année. Chacun est consacré à un projet particulier de la communauté :

J'ai fait une courte recherche pour savoir si des communautés d'autres langages de programmation avaient suivi l'initiative, mais je n'ai rien trouvé de vraiment suivi :

  • Ruby en a fait un en 2006 et en 2008, mais visiblement rien cette année ;
  • PHP en a fait un en 2007, et un cette année ;
  • je n'ai rien trouvé pour Python ;
  • et je me suis arrêté là ! N'hésitez pas à déposer un commentaire pour me faire découvrir d'autres calendriers de ce type.

Personnellement, je trouve que c'est une initiative intéressante, d'une part cela permet d'en apprendre plus sur un langage ou un logiciel en particulier, et puis cela permet également d'assurer une sorte de promotion pour l'objet du calendrier.

Bref, en ce qui me concerne, bien plus intéressant que le calendrier d'une célèbre marque de pneus, par exemple ;-)

Notes de bas de page:

1 en français, on parlera de mongueur

A long time ago

| Aucun Commentaire | Aucun Trackback

Cela fait maintenant un bail que je n'ai plus publié de billets sur ce blog, mais cela ne signifie pas que Perl ne m'a pas été utile dans l'intervalle. En fait, ce serait même plutôt le contraire ! Pour le moment, il m'est surtout utile pour faire des prototypes me permettant de mieux comprendre certaines technologies.

Ainsi, dans le GNU/Linux Magazine France du mois de novembre 2009, il y a un article (Mettez un sphinx dans votre moteur de recherche !) sur un outil sur lequel j'avais déjà jetté un bref coup d'oeil : Sphinx. Je n'ai pas encore eu le temps de finir l'article (je suis en retard sur tout, je vous dis !), mais le principe est de fournir un point d'entrée à une base de données via une requête. Les résultats de cette requête est alors indexée par un logiciel extérieur (Sphinx en l'occurrence). Ensuite lorsque l'on veut effectuer une recherche en texte intégral sur cette base de données, on commence par interroger Sphinx pour obtenir les identifiants des données, on peut ensuite récupérer les données directement dans la base de données.

Je n'ai pas de bases de données suffisamment importantes sous la main que pour pouvoir vérifier si les promesses de performances sont au rendez-vous, mais d'après l'auteur de l'article, c'est le cas !

Je m'interroge donc sur la possibilité d'utiliser Sphinx pour créer des OPACs « nouvelle génération ». L'avantage étant que le simple fait d'ajouter Sphinx dans le jeu permet d'exploiter un langage de requête bien plus riche que les OPACs classiques.

J'ai déjà utilisé cette technique de l'indexation par un programme extérieur pour mettre à disposition une base de données Winisis via le protocole Z39.50. J'avais utilisé pour cela Perl, avec les modules suivants :

Bref, tout cela me donne envie de tenter de réaliser un équivalent de Sphinx, mais en Perl. En exploitant la versatilité de DBI, cela permettrait d'offrir ce service d'indexation à quantité de bases de données !