Navigation – Plan du site

AccueilNumérosN°3, vol. 2Théories & MéthodesDe la sociologie en AmériqueAnnexe 2 : Collecte automatique de d(…)

De la sociologie en Amérique

Annexe 2 : Collecte automatique de données, l’exemple des évaluateurs anonymes (referees) de l’ASR

Programme réalisé par Alexandre Hobeika et Etienne Ollion (CMH-ETT)
Alexandre Hobeika et Étienne Ollion

Texte intégral

1À la page 280 de l’article, on écrit que :

« Les referees des principaux journaux, ces évaluateurs anonymes extérieurs auxquels sont confiés les manuscrits soumis à la revue, sont pour plus de 90 % d’entre eux affiliés principalement à une université étasunienne. »

2Ce calcul a été réalisé en partie grâce à une procédure automatisée de collecte des données sur internet. On explique ci-dessous la méthodologie qui a permis de parvenir à ce résultat.

1. Question de départ

3On cherche à savoir dans quelle université les personnes qui évaluent les articles de l’American Sociological Review. On dispose pour cela d’une information essentielle, qui est la liste de ces évaluateurs (referees), publiée chaque année par la revue1. Mais c’est à peu près tout, le reste des données n’étant pas public. Une possibilité consiste à prendre successivement chaque auteur et à collecter manuellement ces informations (soit sur internet, soit à partir des informations de l’American Sociological Association). Fiable, cette procédure est cependant particulièrement chronophage, puisqu’en 2010, l’ASR a sollicité 1093 individus pour évaluer des manuscrits. On va tenter ici de l’automatiser, au moins partiellement.

2. Méthodologie

4La multiplication d’informations disponibles sur internet, tout comme l’existence de certains langages de programmation, offrent une alternative au moins partielle au codage manuel. Pour ce faire, on utilise un langage appelé Perl. Gratuit, disponible en ligne, et utilisé par une vaste communauté internationale, il permet notamment de réaliser des séries d’opérations sur des fichiers, des bases de données et des lignes de code de format très différents. Il est particulièrement puissant pour la manipulation de chaînes de caractères, donc pour tous les fichiers contenant du texte sous une forme relativement structurée par des motifs identifiables ou récurrents.

A. L’idée centrale : rechercher les adresses email

5L’idée est ici de « faire faire » à un programme ce qu’on pourrait faire à la main, à savoir collecter des informations sur chacun des auteurs. On va plus précisément lui demander d’aller chercher dans un moteur de recherche (type Google, Yahoo, etc.) ces informations en saisissant leurs prénom et nom, puis en scannant les premières pages de sortie. Le plus souvent, on arrive assez rapidement sur la page du chercheur en question, sur laquelle il est aisé d’identifier son affiliation (soit à partir du site même, soit à partir de son CV).

6Le problème est que les referees sont trop nombreux, et que pour chaque auteur, on se retrouve rapidement avec une masse d’information à la fois importante et diverses. Pire : là où un cerveau humain  parviendrait à s’adapter aux petites variations, l’ordinateur peine à sélectionner l’information pertinente faute de structure exactement similaire. Les pages internet ne se ressemblent en effet pas : les données qu’on recherche ne sont pas toutes disponibles, pas au même endroit, ni dans le même ordre…

7On peut cependant tenter d’extraire des informations pertinentes depuis le maelström de données recueillies. C’est ici que l’intuition entre en jeu : à condition de trouver un indicateur simple et fiable, on peut utiliser les résultats de la recherche.

8Dans ce cas, on a décidé de chercher un élément qui nous paraissait bien approcher la position institutionnelle des auteurs : leur adresse email. Elle est dotée d’une structure régulière ([texte]@[texte].[texte]), elle est presque toujours présente, et elle contient souvent le nom de l’institution. Certes, l’indice n’est pas parfait : les auteurs peuvent avoir plusieurs adresses emails, ils peuvent avoir plusieurs rattachements, ils peuvent avoir changé d’université récemment. Pire : les pages web retournées par la recherche peuvent contenir d’autres adresses que celle du chercheur (dans le meilleur des cas des collaborateurs du même département, dans le pire des chercheurs affiliés à une autre université). Il faut donc mettre en place une procédure qui trouve la bonne adresse email.

B. Méthode

  • 2 Voir http://www.perl.org pour l’installation détaillée de Perl, la documentation du langage, commen (...)

9C’est là que Perl intervient. Il permet en particulier d’utiliser les « expressions régulières » (regular expressions, ou regex), petites expressions formelles qui permettent d’opérer des manipulations complexes sur des données structurées2. Les fonctions rechercher/remplacer que l’on trouve dans les traitements de texte usuels sont une exemple trivial de ce qu’elles peuvent faire. Plus généralement, elles permettent de repérer et d’extraire de façon très rapide des motifs [patterns], même dans de très gros fichiers. Les regex permettent de repérer rapidement toutes les chaines de caractères disposant de la même structure dans un texte. Perl est très à l’aise avec les expressions régulières, c’est d’ailleurs la fonction première pour laquelle il a été développé. Il est depuis devenu un langage de programmation généraliste, et dispose d’une très grande variété de fonctions, en particulier pour le web.

10On lui demande ici, pour chacun des referees, de lancer une recherche sur Yahoo, puis de parcourir les liens renvoyés par celui-ci à la recherche d’adresses email, et enfin d’estimer quelle est la bonne adresse. Les regex sont un ingrédient central du programme.

C. Protocole

11Pour éviter les homonymes et d’accroitre les chances de trouver la bonne personne, on choisit de faire des requêtes de la forme « Prénom Nom Sociology Email ». Les tests effectués en amont et « à la main » montrent que c’est ainsi qu’on obtient les meilleurs résultats.

12Suite à un ensemble d’autres tests, on décide d’un critère : au-dessus d’un certain pourcentage d’adresses similaires dans les dix premiers résultats renvoyés par le moteur de recherche, on considérera que l’auteur est bien affilié dans l’université nommée. Dans le cas inverse, il faudra regarder manuellement (en espérant que cette situation ne se reproduise pas trop).

13Par exemple, si on cherche à savoir où Robert Park travaille, on enverra une requête «Robert Park sociology email». Si l’adresserobert@uchicago.edu revient bien plus régulièrement dans les pages retournées que n’importe quelle autre, on pourra en déduire de manière relativement sûre que Robert Park est affilié à l’Université de Chicago.

14En réalité, on programme plusieurs petits algorithmes qui tentent, chacun, de deviner la « bonne » adresse email et l’affiliation du sociologue. Cela nous permet d’affiner la recherche et de calculer un indice de fiabilité, élevé si tous les algorithmes renvoient le même résultat et faible sinon, qui facilite le traitement secondaire des données récoltées.

Figure 1 : La sortie sur le terminal pour le premier referee de la liste 3

Figure 1 : La sortie sur le terminal pour le premier referee de la liste 3

D. Résultats

15Le programme nous renvoie ainsi pour chaque personne une série de résultats sur son affiliation possible, puis un nom de domaine dont on pense qu’il est le plus probable, suivi d’un indice de fiabilité évalué de 1 à 5 (1 = faible ; 5 = fort).

16Réalisé sur les 1093 individus, le programme nous renvoie La distribution suivante en termes d’indices de fiabilité.

Figure 2 : Distribution de l’indice de fiabilité des résultats

Figure 2 : Distribution de l’indice de fiabilité des résultats

17Après une vérification effectuée manuellement sur 110 auteurs (10 %), on constate qu’à partir du seuil de 3, le taux d’erreur est proche de 0 % (il est de 50 % pour 2). On décide donc d’accepter le résultat pour les évaluateurs ayant un indice de confiance égal ou supérieur à 3, et de le rejeter dans le cas inverse. Dès lors, 80 % du travail est déjà effectué par le programme. Par ailleurs, les données récoltées permettent d’identifier presque immédiatement plus d’une dizaine d’autres auteurs.

18On arrive alors au résultat annoncé dans l’article : ce sont près de 90 % des auteurs qui sont affiliés principalement à une université étasunienne.

3. Le programme pas à pas

A. Récupérer les informations en ligne

19On passe pour ce faire par les moteurs de recherche. Tous utilisent une interface, ou API (un programme auquel on envoie des instructions et qui renvoie des réponses structurées selon une forme particulière). Il existe des modules qui font le lien entre cette API et notre programme. Ici on va utiliser Yahoo, car Google n’accepte qu’un nombre limité de requêtes gratuites par jour et son service payant a des tarifs beaucoup plus élevés que Yahoo.

20Attention : il y a quelques mois encore, il était possible d’utiliser certains moteurs de recherche gratuitement. Ce n’est plus le cas aujourd’hui. On utilise ici Yahoo, qui facture $0.80 les 1000 requêtes – soit ce dont nous avons besoin ici.

21Le module Webservice::Yahoo::BOSS, répertorié sur cpan.org, nous permet de faire le lien facilement entre Perl et Yahoo. C’est une extension open source, gratuite, documentée et testée par de nombreux utilisateurs, comme il en existe des milliers.

22Le premier programme ci-contre se connecte à l’interface BOSS de Yahoo, lit le fichier contenant la liste des referees, et pour chacun d’entre eux lance une requête, la traite et stocke les informations (ici les 10 premières URLs) dans un fichier qui sera lu par un second programme.

#!perl
use strict;
use File::Slurp;
use WebService::Yahoo::BOSS;
use Text::Unaccent;
## Donnees pour se connecter a l interface (API) BOSS de Yahoo ; codes de facturation,
## s'enregistrer sur http://developer.yahoo.com/​search/​boss/​boss_api_guide/​ pour les obtenir
my $Boss = WebService::Yahoo::BOSS->new(ckey => 'premier-code', csecret => 'second-code');
## Liste des referees a traiter, et enlevement des accents
## my $r definit la variable de boucle, qui prend chaque valeur de @referees
my @referees = read_file( 'referees.txt' ) ;
foreach my $r ( @referees ) { $r = unac_string( "UTF-8", $r ); }
## Ouverture du fichier de sortie, ecriture sans ecrasement (>>)
open SORTIE, ">>:encoding(utf-8)", "referees-urls.txt";
## Boucle, traitement de chaque referee
foreach my $re ( @referees ){
  ## Mise de $re sous la forme "Prenom (tab) Nom"
  ## s/// est la fonction susbtitute, chomp est un detail ici
  chomp( $re ); $re =~ s/\"(.*?), (.*?)\"/$2\t$1/;
  ## Indique a l utilisateur a quel referee on en est
  print "$re\n";
 
  ## Definit et lance la requete a Yahoo BOSS, stocke la reponse dans l'objet $Results
  my $Results = $Boss->Web( q => "$re sociology email", start => 0 );
  ## Extrait les 10 premieres URLs de la reponse, les stocke dans le tableau @urls
  my @urls = ();
  for( my $i = 0; $i < 10; $i++ ) {
      push( @urls, $Results->results->[$i]->{url} ) ;
  }
  
  ## Mise sous la forme : "Prenom (tab) Nom (tab*2) URL1 (tab) URL2..."
  my $t = $re."\t\t".join( "\t", @urls )."\n";
  ## Ecriture a la fin du fichier de sortie
  print SORTIE $t;
}
## Fermeture du fichier de sortie
close SORTIE ;

23Une fois arrivé ici, on dispose d’un tableau avec des séries de résultats assez massives pour chaque auteur (les 10 premières sorties sur le moteur de recherche, qu’on a rapatriées sous forme d’un fichier). On va désormais travailler à partir de ce fichier, et tenter de synthétiser les informations.

B. Trier les informations recueillies

24On va désormais écrire un second programme, qui utilise les données renvoyées par Yahoo. À ce stade, on dispose pour chaque referee de 10 URLs, l’adresse de dix pages HTML (parfois un fichier PDF, qu’on a choisi ici de ne pas ignorer). Le programme visite chaque URL et y repère toutes les adresses email. Une fois que toutes les URLs correspondant à un referee sont scannées, il procède à des des manipulations pour estimer le bon email et un degré de confiance de son estimation (une note de 1 à 5). Les algorithmes sont ici programmés ad hoc, mais correspondent à des exercices de programmation simples.

25Contrairement à l’étape précédente, l’exécution de ce programme va prendre plusieurs heures. On charge en effet successivement plus de dix mille pages web, les serveurs ont des temps de réponse variables et quelques pages HTML (ou fichiers PDF) peuvent être longs à charger – la recherche des adresses mail par Perl dans un fichier est en revanche très rapide, prend une fraction de seconde. Il suffit toutefois de lancer le programme et d’attendre (on peut suivre la progression sur le terminal).

#!perl
## Modules dont on a besoin ici
use strict;
use File::Slurp;
use WWW::Mechanize;
## Lecture du fichier contenant la base d'URLs constituée précédemment
my @base = read_file('referees-urls.txt');
## Initialisation d'un robot web
my $mech = WWW::Mechanize->new( autocheck => 0 );
## D2finition d'un pattern de test, utile plus tard
my $regex_no_dotcom = qr/(sagepub|blackwell|amazon|getCITED|ecampus
|macmillan|google|abebooks|\.com|oxfordjournals|academia\.edu)/si;
## Boucle : traitement de chaque referee
foreach my $re_urls (@base) {
   chomp $re_urls;
   #### PREPARATION, DEFINITION DES VARIABLES UTILES
   ## Variables ou l'on va stocker les resultats
   my @MAILS;  my @DOMAINES;  my @ERRORS;
   ## Recuperation de : Prenom Nom URL1 URL2 URL3...
   my $nom;  my $prenom;  my @urls;  my $urls;
   if ( $re_urls =~ m/^(.*?)\t(.*?)\t\t(.*)/ ) {
       $prenom = $1;  $nom = $2;  $urls   = $3;
   }
   while ( $urls =~ m/(.*?)\t(.*)$/ ) {
       push( @urls, $1 ); $urls = $2;
   }   push( @urls, $urls );
   ## Versions abregees des prenom et nom, et initiales
   my $n = $nom;  my $p = $prenom;  my $p_i;  my $n_i;
   if ( $prenom =~ m/^(\w+)\s/ ) { $p   = $1; }
   if ( $nom    =~ m/^(\w+)\s/ ) { $n   = $1; }
   if ( $p      =~ m/^(\w)/ )    { $p_i = $1; }
   if ( $n      =~ m/^(\w)/ )    { $n_i = $1; }
   print "\nNom : $nom\nPrenom : $prenom\n\n";
   ## Patterns de test
   my $regex_prenom_nom = qr/($prenom|$nom)/si;
   my $regex_initials   = qr/^($p_i$n_i|$n_i$p_i)\@\d*/si;
   #### CONNEXION A CHAQUE URL, EXTRACTION DES MAILS TROUVES
   ## Boucle : traitement de chaque URL
   my $k_0 = 0;
   foreach my $u (@urls) {
       ## Le robot va chercher la page web designee par l'URL
       my $text = "";
       my @errors;
       $mech->quiet(1);
       $mech->get($u);
       if ( $mech->success() && $mech->is_html() ) {
           $text = $mech->response()->decoded_content;
       }
       else { push( @errors, "$nom\t$prenom\t$u" ); }
       ## Extraction des adresses email presentes dans cette page, stockage dans @MAILS
       my @mails;
       while ( $text =~ m/\b([A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4})\b(.*)/is )
       {
           $text = $2;
           my $em = $1;
           if ( $em !~ /$regex_no_dotcom/ ) { push( @mails, $em ) }
           ;    ## on evite les sites des marchands et des revues
       }
       $MAILS[$k_0] = join ",", @mails;
       ## Extraction des noms de domaines correspondant aux adresses email, stockage dans @DOMAINES
       my @domaines;
       foreach (@mails) {
           if (/(\w+\.\w{2}\.\w{2}\b|\w+\.\w+\b)$/) { push( @domaines, $1 ); }
       }
       $DOMAINES[$k_0] = join( ",", @domaines );
       $k_0++;
       push( @ERRORS, @errors );
   }
   ## Resultats sans doublons : definition de variable et construction
   my @M;  my @D;
   foreach (@MAILS) {
       foreach ( split( ",", $_ ) ) {
           if ( $_ !~ grep $_, @M ) { push( @M, $_ ); }
       }
   }
   foreach (@DOMAINES) {
       foreach ( split( ",", $_ ) ) {
           if ( $_ !~ grep $_, @D ) { push( @D, $_ ); }
       }
   }
   #### BATTERIE DE TRAITEMENTS DES DONNEES POUR
   #### EXTRAIRE AUTOMATIQUEMENT L'AFFILIATION INSTITUTIONNELLE
   #### Guess ADR 0 : test simple du nom, du prenom et des initiales
   ##     On attrape robert@uchicago, rp1864@uchicago, on manque rob@uchicago (surnom)
   ##     et rep@uchicago (middle initial) - on pourrait le faire si besoin
   my $ADR_0 = "";
   foreach (@M) {
       if    (m/$regex_prenom_nom/) { $ADR_0 = $_; last }
       elsif (m/$regex_initials/)   { $ADR_0 = $_; last }
   }
   print 'Guess email #0: ' . "$ADR_0\n";
   #### GUESS ADR 1 : adresse email la plus frequente
   ## Preparation, definition des variables
   my $ADR_1 = "";    ## Variable dans laquelle on stockera le resultat
   ## Regroupe toutes les adresses, en fait un tableau (contient des blancs, enleves plus bas)
   my @adr = split( ",", join( ",", @MAILS ) );
   ## Definit un compteur de frequence des adresses
   my %adr_count;
   ## Decompte
   foreach (@adr) { $adr_count{$_}++; }
   ## Enleve les adresses "vides" et leur decompte (detail)
   delete( $adr_count{""} );
   ## Tri des frequences des adresses, on ne garde que la plus frequente
   ## Adresses triees par frequence decroissante
   my @adr_s = sort { $adr_count{$b} <=> $adr_count{$a} } keys %adr_count;
   ## La plus frequente, sauf ex-aequo
   $ADR_1 = $adr_s[0];
   ## Cas avec egalites de compte : identification puis traitement
   ## Nombre d'ex-aequo -1, que l'on determine juste apres
   my $c_eq = 0;
   for (my $k = 0 ; $k < $#adr_s && $adr_count{ $adr_s[$k] } == $adr_count{ $adr_s[ $k + 1 ] };
       $k++){ $c_eq++; }
   foreach ( @adr_s[ 0, $c_eq ] ) {
       ## Test si adresse contient prenom/nom/initiales, on sort des qu'on a trouve
       if    (m/$regex_prenom_nom/) { $ADR_1 = $_; last }
       elsif (m/$regex_initials/)   { $ADR_1 = $_; last }
   }
   print 'Guess email #1: ' . "$ADR_1\n";
   #### GUESS ADR 2 : la premiere adresse qui revient dans deux pages differentes
   my $ADR_2 = "";
   foreach my $m (@M) {
       if ( ( join "\,", @M ) =~ /.*$m.*$m.*/ ) { $ADR_2 = $m; last; }
   }
   print 'Guess email #2: ' . "$ADR_2\n";
   #### GUESS DOM 1 : domaine le plus frequent parmi
##     tout ce qu'on a recupere pour un referee donne - cf. supra
   my $DOM_1    = "";
   my $dom_list = join ",", @DOMAINES;
   my @dom      = split( ",", $dom_list );
   my %dom_count;
   foreach (@dom) { $dom_count{$_}++; }
   delete( $dom_count{""} );
   my @dom_s = sort { $dom_count{$b} <=> $dom_count{$a} } keys %dom_count;
   $DOM_1 = $dom_s[0];
   print 'Guess domain #1: ' . "$DOM_1\n";
   ## Guess DOM 2 : premier domaine qui revient dans deux URLS differentes
   my $DOM_2 = "";
   my @DOM_URLS;
   foreach (@urls) {
       if (   $_ =~ m#^\w+://.*?(\w+\.\w{2}\.\w{2}|\w+\.\w+)/#
           && $1 !~ /$regex_no_dotcom/ )
       {
           push( @DOM_URLS, $1 );
       }
   }
   foreach my $d (@DOM_URLS) {
       if ( ( join "\,", @DOM_URLS ) =~ /.*$d.*$d.*/ ) { $DOM_2 = $d; last; }
   }
   print 'Guess domain #2: ' . "$DOM_2\n";
   #### SYNTHESE : domaine le plus frequent (parmi ces cinq tests)
##     et son compte (= "indice de confiance")
   my $final;
   my $conf;
   my @FINAL;
   ## Extraction des domaines des adresses email
   foreach ( ( $ADR_0, $ADR_1, $ADR_2 ) ) {
       if ( $_ =~ m/\@.*?(\w+\.\w{2}\.\w{2}|\w+\.\w+)$/i ) {
           push( @FINAL, lc($1) );
       }
   }
   push( @FINAL, ( $DOM_1, $DOM_2 ) );
   ## Decompte et tri des frequences des noms de domaine
   my %f_count;
   foreach (@FINAL) { $f_count{$_}++; }
   my @f_s = sort { $f_count{$b} <=> $f_count{$a} } keys %f_count;
   ## Resultats synthetiques
   $final = $f_s[0];
   $conf  = $f_count{ $f_s[0] };
   print "\n";
   print join "\n", @FINAL;
   print "\n";
   print "Domaine estime : $final\n";
   print "Indice de confiance : $conf sur 5\n";
   print "-----\n";
## Ecriture des resultats dans le fichier de sortie
write_file( 'referees-resultats.txt', {append => 1},
 "$nom\t$prenom\t\t$final\t$conf\t".join("\t",@FINAL)."\n" );

26Le résultat est un tableur au format .csv, que l’on peut ensuite analyser à partir de n’importe quel logiciel de statistiques.

Haut de page

Notes

1  http://asr.sagepub.com/content/75/6/981.full

2 Voir http://www.perl.org pour l’installation détaillée de Perl, la documentation du langage, comment exécuter des programmes, et une série de ressources utiles pour l’usage de ce langage.

Haut de page

Table des illustrations

Titre Figure 1 : La sortie sur le terminal pour le premier referee de la liste 3
URL http://journals.openedition.org/sociologie/docannexe/image/1126/img-1.png
Fichier image/png, 426k
Titre Figure 2 : Distribution de l’indice de fiabilité des résultats
URL http://journals.openedition.org/sociologie/docannexe/image/1126/img-2.png
Fichier image/png, 10k
Haut de page

Pour citer cet article

Référence électronique

Alexandre Hobeika et Étienne Ollion, « Annexe 2 : Collecte automatique de données, l’exemple des évaluateurs anonymes (referees) de l’ASR », Sociologie [En ligne], N°3, vol. 2 |  2011, mis en ligne le 12 novembre 2012, consulté le 19 mars 2024. URL : http://journals.openedition.org/sociologie/1126

Haut de page

Auteurs

Étienne Ollion

Articles du même auteur

Alexandre Hobeika

Haut de page

Droits d’auteur

Le texte et les autres éléments (illustrations, fichiers annexes importés), sont « Tous droits réservés », sauf mention contraire.

Haut de page

Rechercher dans OpenEdition Search

Vous allez être redirigé vers OpenEdition Search