Publié le 14/07/2022
Auteur fobec
Réseaux sociaux
0 partages
0 tweets
0 plus
0 commentaires

Scraper une page web

Le web scraping est la collecte automatisée d'information à partir de pages internet. Le but est d'extraire et de valoriser les données publiées notamment sur Internet. De plus, à ce qu'il parait, nous sommes entrés dans l'ère de la Big Data, de l'information à profusion qui ne demande qu'à être collectée pour ses propres projets.

Le but de l'article est de détailler la méthodologie de base, charger une page web et trouver les données intéressantes. Bien que le sujet soit traité autour d'un script PHP, le principe est le même pour un autre langage de programmation ou en utilisant des librairies externes.

Charger le code HTML de la page


La première étape consiste à simuler le chargement des ressources par un navigateur internet. De la même manière que Chrome ou Firefox, nous allons demander au serveur web de nous fournir le code source de la page web contenant les informations utiles.

Face au vol de données et aux attaques en tout genre, tous les serveurs d'hébergement ont mis en place des protections plus ou moins élaborées. Dans notre exemple, nous allons charger une page sur Wikipédia dont l'infrastructure est généreuse. Il suffit de demander poliment et sans harceler pour obtenir la page internet.

Voici un exemple pour charger la page sur Wikipédia avec cUrl. La requête est effectuée en mode GET, avec HTTPS et en indiquant un UserAgent.

<?php
 
class WebLoader {
 
    /**
     * User agent de la requete
     * Chrome 11 sur Linux
     */
    const USERAGENT = 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36';
 
    /**
     * Délai max
     * 5 secondes
     */
    const TIMEOUT = 5; //5 sec
 
    /**
     * Résultat de la requete
     * Si différent de 200, une erreur est survenue
     * @var int
     */
    static public int $http_code = 404;
 
    
    /**
     * Charger le code HTML
     * @param string $url
     * @return type
     */
    static public function get_url(string $url) {
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_TIMEOUT, self::TIMEOUT);
        curl_setopt($ch, CURLOPT_USERAGENT, self::USERAGENT);
        curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($ch, CURLOPT_HEADER, 0);
        curl_setopt($ch, CURLOPT_URL, $url);
        $buf = curl_exec($ch);
        $info = curl_getinfo($ch);
        curl_close($ch);
 
        //Erreur interne
        if (!isset($info['total_time']) || !isset($info['http_code'])) {
            self::$http_code = 500;
        }
        //Dépassement du délai
        else if (isset($info['total_time']) && $info['total_time'] > self::TIMEOUT) {
            self::$http_code = 408;
        }
        //Les autres cas
        else {
            self::$http_code = intval($info['http_code']);
        }
 
        return $buf;
    }
}

Exemple d'utilisation de la class WebLoader

<?php
 
/**
 * Charger la page internet
 */
$URL = 'https://fr.wikipedia.org/wiki/PHP';
$html = WebLoader::get_url($URL);
 
//Vérifier le chargement de la page
if (WebLoader::$http_code != 200) {
    echo 'Echec du chargement de la page internet';
    exit(0);
}

Lister les titres de la page Wikipedia


Passons à la partie intéressante de l'extraction de données sur une page internet. Le but est de trouver comment sont marqués les titres dans le code HTML. Pour ce faire, après avoir affiché le code source de la page, nous allons trouver les balises HTML qui servent à délimiter l'information.

<li id="toc-Présentation"
class="sidebar-toc-list-item sidebar-toc-level-1">
<a class="sidebar-toc-link" href="#Présentation">
<div class="sidebar-toc-text">
<span class="sidebar-toc-numb">1</span>Présentation</div>
</a>

<ul id="toc-Présentation-sublist" class="sidebar-toc-list">
</ul>
</li>

En y regardant de plus près, on se rend compte que les titres sont encapsulés dans une balise span dont la class css est sidebar-toc-numb. Lister les titres de la page revient à chercher tous les span de la class sidebar-toc-numb puis d'en extraire le contenu.

Extraire des données avec un Regex

La première technique est d'utiliser un parseur utilisant les Regex. L'avantage de cette méthode est sa rapidité et qu'elle s'adapte à tous les types de texte.
Voici une implémentation de l'extraction à l'aide d'une Regex.

<?php
 
$URL = 'https://fr.wikipedia.org/wiki/PHP';
$html = WebLoader::get_url($URL);
 
//Vérifier le chargement de la page
if (WebLoader::$http_code != 200) {
    echo 'Echec du chargement de la page internet';
    exit(0);
}
 
$list_title = HtmlParser::list_title($html);
var_dump($list_title);
 
class HtmlParser {
 
    /**
     * Regex d'extraction des titres
     */
    const PATTERN = '/<span class="sidebar-toc-numb">([\d.]*)<\/span>([\w\s\.]*)<\/div>/u';
 
    static public function list_title(string $html): array {
        $b = preg_match_all(self::PATTERN, $html, $matches);
 
        //Echec de la fonction
        if (!$b || !isset($matches[2][0])) {
            return [];
        }
 
        //Lister le numéro et le libellé des titres
        $list_title = [];
        for ($i = 0; $i < count($matches[0]); $i++) {
            $list_title[] = $matches[1][$i] . ' ' . $matches[2][$i];
        }
 
        return $list_title;
    } 
}

Le résultat de l'extraction des titres par Regex
array(26) { [0]=> string(15) "1 Présentation" [1]=> string(10) "2 Histoire" [2]=> string(15) "2.1 Utilisation" [3]=> string(12) "2.2 Versions" [4]=> string(17) "2.2.1 Version 8.1"
.....

En quelques lignes de code, le script PHP extrait les 25 titres de la page web. Les Regex fonctionnent sur n'importe quelle source de texte et de plus la majorité des langages de programmation supportent cette fonctionnalité.
Voyons comment parcourir les noeuds HTML d'un DomDocument.

Extraire un bloc de donnée avec Xpath


La méthode avec Xpath se base sur l'objet DOMDocument qui est le moteur interne de tous les navigateurs internet. Puisque les balises HTML sont imbriquées l'une dans l'autre, DOMDocument construit un arbre que l'on peut parcourir pour trouver l'information.

Dans la page Wikipedia, les exemples de script PHP se présentent sous la forme

<div class="mw-highlight mw-highlight-lang-php mw-content-ltr" dir="ltr"><pre><span></span>
<span class="o">&lt;?=</span> <span class="s1">'Hello World'</span>

Pour lister les scripts PHP de la page, il suffit de trouver les éléments HTML div dont la class css est mw-highlight. Au lieu de passer en revue tous les div, utilisons le plugin Xpath proposé avec l'objet DOMDocument qui propose un moteur de recherche.

<?php
$URL = 'https://fr.wikipedia.org/wiki/PHP';
$html = WebLoader::get_url($URL);
 
//Vérifier le chargement de la page
if (WebLoader::$http_code != 200) {
    echo 'Echec du chargement de la page internet';
    exit(0);
}
 
/*$list_cs = HtmlParser::list_code_source($html);
var_dump($list_cs);*/
 
class HtmlParser {    
 
    static public function list_code_source(string $html): array {
        $list_cs = [];
 
        $doc = new DOMDocument();
        $doc->loadHTML($html);
        $xpath = new DOMXpath($doc);
 
        $elements = $xpath->query('//div[@class="mw-highlight mw-highlight-lang-php mw-content-ltr"]');
        foreach ($elements as $element) {
            $list_cs[]=$element->nodeValue;
        }
        
        return $list_cs;
    }
}

L'ensemble des scripts PHP de la page est ajouté dans la variable $list_cs. L'avantage de Xpath sur les regex est que la recherche s'appuie sur la structure HTML du document. Ainsi, l'extraction peut être affinée pour obtenir des résultats plus précis et réduire le nombre de faux positifs.

Précisions sur l'extraction automatisée de donnée


L'exemple choisi pour cet article est volontairement basique par contre la technique reste la même pour des collectes plus élaborées. Par contre, je voudrais attirer l'attention sur trois points :

Scraper est une activité essentielle
Quel que soit le projet, l'information est disponible sur Internet et il serait dommage de se palucher à la mano un dataset de données. De plus, l'IA nécessite de grandes quantités de données pour optimiser et régler les réseaux de neurones. Donc, on peut gagner beaucoup de temps en scrapant et en formatant l'information dans sa propre base de donnée.

Scraper est un casse-tête
Quel webmaster n'a pas pesté au moins une fois, parce qu'on lui avait volé ses données ? Du coup, que ce soit en natif ou que ce soit par ajout de couches logicielles, l'extraction de contenu devient de plus en plus difficile. Au hasard, prenons l'exemple des recherches Google. Que se passe-t-il au bout de quelques téléchargements des SERP .... un joli captcha !
C'est bien le téléchargement de pages web qui est l'opération la plus difficile dans laquelle il faudra correctement configurer ses scripts et s'équiper de proxy.

Scraper demande de l'éthique
Quelle est la différence entre parcourir Wikipedia pour se constituer un corpus et extraire l'ensemble des données d'un concurrent ?
Et oui, la portée de ses actes n'est pas la même et l'intention de nuire est clairement affichée dans le second cas. Donc attention aux copyrights, aux droits d'auteur et à la propriété intellectuelle qui peuvent emmener des ennuis ...
N'oublions pas qu'Internet est une communauté de partage et d'entraide, veillez à scraper le web en respectant l'effort et le travail de chacun.

Ajouter un commentaire

Les champs marqués d'un * sont obligatoires, les adresses emails se sont pas publiées.

A lire aussi

Réseaux sociaux
Présentation de l'article
Catégorie
php5 - class
Mise a jour
14/07/2022
Visualisation
vu 22 fois
Public
Internaute
Auteur de la publication
Fobec
Admin
Auteur de 266 articles
|BIO_PSEUDO|
Commentaires récents

Publié par Tom dans java

Hello!
Cependant, mon Eclipse ne reconnait pas HttpLoader comme type valide...
Comment faire pour que ca marc...

Publié par claude77 dans tuto

Super application, fonctionne bien
exemple sur une image

Publié par fobec dans tuto

Effectivement, l'interface du site a evolue. Le lien de telechargement est ici: http://www.rainforestnet.com/download/sample.zip

Publié par Verkork dans java

Le probleme c'est que ce code ne convient pas quand une partie de la page est dynamique, ie qu'elle est rafraichit toutes les minutes par exemple. Par exemple pour une telle page, c'est...

Publié par fobec dans logiciel

MAJ: mise en cache du FAI et optimisation du script de Geolocalisation.