Annexe 2 : Collecte automatique de données, l’exemple des évaluateurs anonymes (referees) de l’ASR
Plan
Haut de pageTexte 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.
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é.
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.
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 pageDocuments annexes
-
Texte intégral disponible sur le portail Cairn (Lien externe)
-
Annexes électroniques de l’article « De la sociologie en Amérique » (Annexes électroniques)
-
Annexe 1 : Représentations graphiques supplémentaires (Annexes électroniques)
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 |
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 27 septembre 2023. URL : http://journals.openedition.org/sociologie/1126
Haut de page