Dyrk.org
Do You Really Know

[Javascript] Réaliser son propre Crawler

Publié le 12 mai 2016 par #Ro0t

Capture

 

 

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 !

 

 

Capture

 

 

 

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.

 

 

 

Capture

 

 

 

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 !!!!

 

 

Capture

 

 

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.