[Javascript] Réaliser son propre Crawler
Je l’avoue, c’est une idée qui m’avait effleurée l’esprit, mais que j’ai longtemps mis de coté …
Car j’ai toujours préférer développer mes crawler en PHP sur des serveurs, au détriment d’outil pour client léger.
Hier, j’ai été contacté pour réaliser une extraction de données … aussi ne disposant pas de toutes ma petite gamme d’outils (home made) … ni d’une connexion fiable à mon serveur …
J’ai dû faire avec les « moyens du bord » :
- Un navigateur Chrome / Firefox
- Un éditeur de texte
- Un outils de compression Zip
Aussi, j’ai voulu vous faire partager un peu le concept :
Prenons par exemple le site : www.mines-paristech.fr
En fouinant un peu … on tombe sur un annuaire !
Bien entendu, cet annuaire ne donne pas UNE liste, mais permet de faire des recherches avec des filtres !!!
Aussi …
Nous allons chercher le filtre qui permet de récupérer toute la liste, en un minimum d’action.
Maintenant qu’on a le filtre le plus « court » ..
Nous allons voir à quoi ressemble l’affichage de l’annuaire !
En lançant une petite recherche avec ce filtre, on constate un affichage homogène et sur une seule page !
Ce qui est encore mieux !!!!
Regardons à présent, le code source (HTML) pour UN résultat ….
(J’ai ici volontairement épuré un peu le code HTML, pour n’afficher que l’essentiel)
[pastacode lang= »markup » message= » » highlight= » » provider= »manual »]
<div class="person-result" id="person-result-16015">
<b><a href="#">Hayat ******* </a></b>
<div class="person-data">
<table>
<tr>
<td><i>Fonction: </i></td>
<td><b>Doctorant(e)</b></td>
</tr>
<tr>
<td><i>Centre: </i></td>
<td>MAT (Evry)</td>
</tr>
<tr>
<td><i>Téléphone: </i></td>
<td>01.xx.xx.xx.xx</td>
</tr>
<tr>
<td><i>Email:</i></td>
<td>
<script type="text/javascript">
/*<![CDATA[*/
eval("var a=\"kQNx80W@. ... ") /*]]>*/
</script>
</td>
</tr>
<tr>
<td><i>Promotion: </i></td>
<td>14</td>
</tr>
</table><a href="#person-result-16015">+ de détails...</a></div>
</div>
[/pastacode]
On constate donc que chaque élément est affiché dans une div qui porte la classe « person-result »
Donc nous pourrons récupérer tous les résultats avec ce code Javascript :
myRecords = document.getElementsByClassName(‘person-result‘);
Que le nom est prénom de chacun des membres est situé dans le premier lien « <a> » de cette div.
Que l’on pourra alors extraire directement :
myRecords[ Id record ].getElementsByTagName(‘a‘)[0];
Pour finir, toutes les données sont dans un bête tableau … aussi nous n’aurons qu’à extraire les TD :
myRecords[ Id record ].getElementsByTagName(‘td‘);
Petit bonus …
Préférez toujours dans vos dev’ la mise en place d’une image pour afficher vos mails …
ça demande de la ressource pour créer l’image, mais une fois créé, vous n’aurez plus à la régénérer …
Car sur l’exemple que je vous donne …
L’adresse email c’est ça :
<span id= »e722665973« >[javascript protected email address]</span><script type= »text/javascript« >/*<![CDATA[*/eval(« var a=\ »kQNx80W@vRoOVCtYE_ch.jiBa-gGH9X4+wylAfrz52s73ZUTqKSId6DMFnePJbLmpu1\ »;var b=a.split(\ »\ »).sort().join(\ »\ »);var c=\ »q2u2JN2s3ZPPZd26C6KDZPQF2eKPJZ7qNUe\ »;var d=\ »\ »;for(var e=0;e<c.length;e++)d+=b.charAt(a.indexOf(c.charAt(e)));document.getElementById(\ »e722665973\ »).innerHTML=\ »<a href=\\\ »\ »+String.fromCharCode(109,97,105,108,116,111)+\ »:\ »+d+\ »\\\ »>\ »+d+\ »</a>\ » »)/*]]>*/</script>
Oh mon Dieu !!!
ça peut être effrayant …
Sauf que ça n’est que du Javascript … par chance notre extension est en Javascript …
Aussi lorsque nous parcourons les données du tableau … sinon détectons un eval( quelque chose);
Nous exécutons le code, et nous récupérons le résultat …
[pastacode lang= »javascript » message= » » highlight= » » provider= »manual »]
td = datas[k].innerText;
if ((test = /eval\("(.*)\);/.exec(td))) {
while (test[1].indexOf('\\') != -1) test[1] = test[1].replace('\\', '');
eval(test[1] + ");");
td = d;
}
[/pastacode]
En Assemblant un peu tout ça … nous obtenons ce joli morceau de code à injecter dans dans notre page, ou à packager dans une extension Chrome ou Firefox :
[pastacode lang= »javascript » message= » » highlight= » » provider= »manual »]
var trim = function(str, charlist) {
var whitespace = [' ','\n','\r','\t','\f','\x0b','\xa0','\u2000','\u2001','\u2002','\u2003','\u2004','\u2005',
'\u2006','\u2007','\u2008','\u2009','\u200a','\u200b','\u2028','\u2029','\u3000'].join('');
var l = 0,i = 0;
str += '';
if (charlist) whitespace = (charlist + '').replace(/([\[\]\(\)\.\?\/\*\{\}\+\$\^:])/g, '$1')
l = str.length;for (i = 0; i < l; i++) if (whitespace.indexOf(str.charAt(i)) === -1) { str = str.substring(i);break } l = str.length; for (i = l - 1; i >= 0; i--)
if (whitespace.indexOf(str.charAt(i)) === -1) {
str = str.substring(0, i + 1);break
}
return whitespace.indexOf(str.charAt(0)) === -1 ? str : ''
}
var Crawl = function(){
dmp = document.createElement('textarea');
dmp.setAttribute('id', 'dmp_crawl');
dmp.setAttribute('style', 'width:100%;height:1000px;border:1px solid black');
document.getElementsByTagName('html')[0].appendChild(dmp);
var list = document.getElementById('localityName').addEventListener('change', function(e){
var localityName = e.target.value;
$.get("http://www.mines-paristech.fr/libmines/Annuaire/Commun/ajax-search.php?&localityName="+localityName, function(e){
var parser = new DOMParser(), doc = parser.parseFromString(e, "text/html");
var personnes = doc.getElementsByClassName('person-result');
for (var j in personnes){
if (!personnes[j].getElementsByTagName) continue;
var datas = personnes[j].getElementsByTagName('td'), info=personnes[j].getElementsByTagName('a')[0].innerText;
for (var k in datas) {
td = datas[k].innerText;
if ((test = /eval\("(.*)\);/.exec(td))){
while (test[1].indexOf('\\')!= -1) test[1]=test[1].replace('\\', '');
eval(test[1]+");");
td=d;
}
info+=";"+trim(td);
}
document.getElementById('dmp_crawl').value+="\n"+info;
}
alert("Dumped !");
});
});
}
window.addEventListener('load', Crawl);
[/pastacode]
Qui va donc à chaque clic, parcourir tous les résultats, extraire le nom/Prenom, les données, le mettre au format CSV (séparation des données par des points virgule)
et stocker tout ça dans une textarea.
Dyrk.org


