Journal Rapport signal bruit et filtre passe-haut

Posté par (page perso) . Licence CC by-sa
12
31
mai
2013

Sommaire

< Krunch> grima: tu as encore le temps de lire dlfp toi ?
< grima> avec un mois de retard souvent et je lis que les truc vraiment inter^W^W^Wplus gros trolls
< Krunch> en considérant que les gros trolls font 90% du contenu en terme de texte je suis pas sûr que tu gagnes du temps
< Krunch> oh oui, faudrait que je compte combien de mots il y a dans les commentaires de journaux à plus de 100 commentaires vs les autres

Implémentation

Bon bah ça tombe bien j'avais rien de prévu aujourd'hui. Donc on commence par recycler mon journals.pl de l'autre fois pour récupérer tous les URLs de journaux :

#!/usr/bin/perl -w
use strict;
use feature 'say';
use utf8;
use HTML::Parser;
use Date::Parse;
use Time::Local;

# prior art:
#       https://linuxfr.org/users/spack/journaux/les-journaux-linuxfr-org-les-moins-biens-notes-de-la-semaine-44-2012#comment-1405344

# We are trying to extract the URL, date/time and score from this:
#
#       <article class="node hentry score-1 diary">
#       <h1 class="entry-title">
#               <a href="/journaux" class="topic">
#               </a>
#               <a href="/users/trs80/journaux/cest-lheure">
#               </a>
#       </h1>
#       <div class="meta">
#               <time class="updated" datetime="2002-10-17T09:26:50+02:00">
#               </time>
#       </div>
#       <meta content="UserLikes:22" itemprop="interactionCount">
#       <meta content="UserComments:40" itemprop="interactionCount" />
#       </article>

my %current;  # with keys 'url', 'time', 'score' and 'comments'

sub debug {
        say STDERR @_ if undef;
}

sub in_article {
        my ($tag, $attrs, $self) = @_;
        if ($tag eq 'a') {
                return unless defined $attrs->{'href'};
                my $url = $attrs->{'href'};
                return unless $url =~ m|^/users/[^/]+/journaux/[^/]+$|;
                debug 'parsing url';
                $current{'url'} = $url;
        } elsif ($tag eq 'time') {
                return unless defined $attrs->{'class'};
                return unless defined $attrs->{'datetime'};
                return unless $attrs->{'class'} eq 'updated';
                debug 'parsing time';
                $current{'time'} = str2time($attrs->{'datetime'});
        } elsif ($tag eq 'meta') {
                return unless defined $attrs->{'content'};
                if ($attrs->{'content'} =~ /^UserLikes:(-?\d+)$/) {
                        $current{'score'} = $1;
                } elsif ($attrs->{'content'} =~ /^UserComments:(\d+)$/) {
                        $current{'comments'} = $1;
                }
        }
}

sub end_article($$) {
        my ($tag, $self) = @_;
        return unless $tag eq 'article';

        debug 'leaving article';

        $self->handler(end => undef);
        $self->handler(start => \&main_start, 'tagname,attr,self');

        printf "%4d %4d %d %s\n",
               $current{'score'},
               $current{'comments'},
               $current{'time'},
               $current{'url'};
        undef %current;
}

sub main_start($$$) {
        my ($tag, $attrs, $self) = @_;
        return unless $tag eq 'article';
        return unless defined $attrs->{'class'};
        return unless grep { /^diary$/ } split /\s+/, $attrs->{'class'};

        debug "entering article";

        $self->handler(start => \&in_article, 'tagname,attr,self');
        $self->handler(end => \&end_article, 'tagname,self');
}

my $parser = HTML::Parser->new(
        utf8_mode => 1,
        start_h => [ \&main_start, 'tagname,attr,self' ]
);
$parser->parse_file($_) for @ARGV;

Ça s'utilise comme ceci :

$ seq 42 -1 1 |
> while read i
> do ./journals.pl \
>       <(wget -U 'DLFP Troll Analyser 0.1' -O - \
>       http://linuxfr.org/journaux?page=${i} ) |
>       tee journaux.${i} ; sleep 3
> done

Vingt minutes plus tard on peut compter les mots :

$ cat journaux.* | while read score comments time url
> do
>       echo -n "$score $comments $time $url "
>       wget -U 'DLFP Troll Analyser 0.1' -O - http://linuxfr.org${url} |
>       wc -w ; sleep 3
> done | tee journaux.wc

Une fois qu'on s'est rendu compte que ça boucle infiniment et qu'on a supprimé les trucs en trop, yapluka agréger :

$ awk '{ if ($1 > 0) { p += $5 } else { np += $5 } if ($2 >= 100) { t += $5 } else { nt += $5 } } END { printf("%d troll words\n%d non troll words\n%d relevant words\n%d irrelevant words\n", t, nt, p, np) }' journaux.wc
30262941 troll words
105888259 non troll words
47892521 relevant words
88258679 irrelevant words

Conclusion

On constate donc que mon estimation était incorrecte puisque seul ~28% du contenu des journaux fait partie d'un journal ayant plus de cent commentaires tandis que les journaux ayant un score strictement positif forment ~54% de ce qui peut être lu dans les journaux.

Future directions

Évidemment mon implémentation du comptage de mots laisse à désirer puisque ça prend en compte tout le HTML, pas juste le texte des commentaires.

Pour ce qui est de la discrimination basé sur le score du journal, ça ne tient pas compte du fait que tous les « vieux » journaux ont un score de zéro.

La définition de « gros troll » pourrait être raffinée pour utiliser d'autres métriques que le nombre de commentaires ou le score du journal.

Gof suggère un réseau de neurones pour déterminer la recette d'un +10.

Prior art

https://linuxfr.org/users/krunch/journaux/dlfp-social-network
https://linuxfr.org/users/krunch/journaux/xp-analyzer-10
https://linuxfr.org/statistiques

  • # -1

    Posté par . Évalué à -9.

    Troll

  • # Trollomètre

    Posté par . Évalué à 5.

    Il y a quelques temps, Bruno Michel avait développé un trollomètre qui permettait d'avoir l'indice de troll pour un journal ou une dépêche. Par contre je ne sais plus si c'était pour la version RoR ou templeet.

    https://linuxfr.org/users/nono/journaux/faites-p%C3%A9ter-le-trollom%C3%A8tre

    • [^] # Re: Trollomètre

      Posté par (page perso) . Évalué à 3.

      Pour référence, ce trollomètre ne prend en compte que le nombre de mots total sur la page. Cette métrique, bien que simpliste, semble donc intuitivement séduisante et pas juste pour moi.

      pertinent adj. Approprié : qui se rapporte exactement à ce dont il est question.

  • # crawler

    Posté par . Évalué à 2.

    ça me fait penser, je crois que j'avais déjà demandé.
    est ce qu'il est possible de télécharger la base de contenus du site ?
    plutôt que de devoir crawler le web à chaque fois que qqun veut faire une stat ?
    à la wikipédia en somme.

    • [^] # Re: crawler

      Posté par (page perso) . Évalué à 3. Dernière modification le 31/05/13 à 18:27.

      Je ne pense pas que cela soit légalement possible

      Tout les contenus ne sont pas sous licence CC-by-sa, et ils ne me semblent pas que l'on cède nos droits à Linuxfr.org lorsque l'on s'enregistre vis à vis de l'ensemble du contenu qu'on serait amener à produire dessus. Du coup chacun garde tous ses droits vis à vis du contenu que lui meme produit. Je peux très bien avoir posté un commentaire, autoriser à ce qu'il soit affiché sur le site, mais pas vouloir qu'il soit inclus dans un gros package "contenus de LinuxFR" (qu'elle en serait la licence ?)

      Après évidemment je ne suis pas un juriste, et si quelqu'un à plus de précision ou si j'ai dit de la merde, n'hésitez pas à me corriger.

      Cela dit je serais également intéressé, dans le cas d'une API permettant d'avoir au contenu d'un site, dont une partie généré par ses utilisateurs, faut-il le prévoir explicitement dans les conditions d'utilisations ? J'imagine qu'au minimum il faut que le contenu apparaisse avec le nom de l'auteur (ou pseudonyme).

Suivre le flux des commentaires

Note : les commentaires appartiennent à ceux qui les ont postés. Nous n'en sommes pas responsables.