Extraire des informations du DOM en php

Il arrive que l’on soit amené à rechercher des informations dans un fichier HTML ou XML. Si on parcourt des pages web à la recherche d’une information précise, telle qu’une adresse email par exemple, il va falloir extraire cette information du reste du code de la page. On peut faire cela principalement de deux manières : soit en utilisant les expressions rationelles, soit en utilisant le dom xpath de PHP. Cette dernière solution s’avére très puissante et efficace, surtout si l’on sait où se trouve l’information dans le DOM, elle aura aussi l’avantage d’être plus rapide – autant en vitesse d’exécution qu’en temps de développement.

xpath permet d’effectuer des recherches dans un arbre XML, donc l’HTML. La classe xpath a de multiples fonctions, nous verrons ici seulement la méthode query, qui permet d’effectuer des recherches dans l’arbre.

xpath est très puissant, notamment lorsqu’il s’agit de récupérer des informations localisées dans le DOM HTML, cependant, si vous ne savez pas où se situent les informations, ou pour exécuter des recherches ailleurs que dans le DOM, vous pouvez tirer parti des expressions rationnelles, alias REGEX.

La requete xpath suivante sélectionne l’ensemble des éléments du body :

//body

// permet de sélectionner un élément indépendamment de ce qu’il y a avant, c’est donc une adresse relative. Si on veut sélectionner l’ensemble des div de la page, on fera :

//body/div
//div

Ces deux requêtes sont dans ce cadre similaires puisque la première demande « toutes les div qui ont body pour parent » et la seconde demande « toutes les div de la page ». Dans le même principe, si l’on veut par exemple tous les textes des liens d’une liste (à savoir <li><a href="#">texte</a>) :

//li/a

Précisons un peu les choses ! Nous voudrions maintenant récupérer les textes des liens d’une liste qui ont la classe « test » :

//li/a[@class='test']

Il en va de même pour tous les attributs. Si l’on veut récupérer un contenu selon son attribut title, on fera a[@title='le titre'].

Puisque nous parlons d’attributs, si nous voulons maintenant mettre la main sur l’adresse du lien (donc son href) et non le texte, voici comment nous procéderions :

//li/a/@href

Il y a encore une petite chose qui est bien pratique au niveau des requêtes. Si nous voulons trouver la quatrième li d’une ul, voilà comment on peut procéder :

//ul/li[4]

Maintenant que nous savons créer les requêtes, voyons comment tout cela prend forme en php. La fonction query de xpath retourne un nœud dom, même s’il est vide.

$html = new DOMDocument();
@$html->loadHtmlFile('http://buzut.fr/extraire-des-informations-du-dom-en-php/');
$xpath = new DOMXPath($html);
$domExemple = $xpath->query("//pre");

$i = 0;
foreach ($domExemple as $exemple) {
    $result[$i++] = $exemple->nodeValue;
}

Sachez qu’il est également possible de charger du HTML directement depuis une variable, on utilisera pour ça loadHTML. Il est d’ailleurs souvent préférable de récupérer le HTML avec curl qui est bien plus puissant (loadHtmlFile échoue souvent). Petit exemple avec curl :

$ch = curl_init($url);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); 
$raw = curl_exec($ch);
curl_close($ch);

$html = new DOMDocument();
@$html->loadHTML($raw);
$xpath = new DOMXPath($html);
$domExemple = $xpath->query("//pre");

$i = 0;
foreach ($domExemple as $exemple) {
    $result[$i++] = $exemple->nodeValue;
}

$result contient maintenant un tableau de tous les blocs de codes d’exemple de cet article. Vous notez que $domExemple est un objet de type DOMNodeList. Pour en récupérer le contenu, on fait donc une boucle et on récupère donc le contenu de chacun des nœuds via la méthode nodeValue.

Vous n’avez rien de plus à savoir pour récupérer la plupart des contenus sur les pages web !

Déjà 7 réponses, rejoignez la discussion !

  • Dallil

    dit :

    bonjour et merci pour ce blog est très intéressant pour Extraire des informations à partir D’URL mais il y a un problème lorsque ont travail avec le Protocol https

  • Zer00CooL

    dit :

    Excellent tutoriel qui m’a permis d’avancer.

    Je cherche à récupérer le code HTML du sommaire de Mediawiki, pour l’inclure dans un PDF.
    Exemple du sommaire que je pourrais avoir à récupérer sur cette page : https://www.visionduweb.eu/wiki/index.php?title=Utiliser_PHP

    J’ai tenté avec $domExemple = $xpath->query(« //ul/li »); mais j’ai trop de réponses et mal formatées.

    J’ai tenté avec $domExemple = $xpath->query(« //ul/li[@class=’toclevel-1 tocsection-1′] »); qui me donne bien le résultat, mais, comment faire pour obtenir tous les toclevel et tocsection, sans avoir à préciser le numéro 1, ou 2, ou 3, … du toclevel ou tocsection.

    Enfin, j’aimerais faire un retour à la ligne car l’affichage de $domExemple = $xpath->query(« //ul/li[@class=’toclevel-1 tocsection-1′] »); n’est pas super, et affiche le menu à la suite, comme ceci :
    1 Utiliser PHP 1.1 Déployer du PHP avec Ansible 1.2 Faille include 1.3 error_reporting
    1.3.1 Configurer php.ini pour afficher les erreurs PHP 1.3.2 Afficher les erreurs PHP directement sur
    la page 1.4 Vérifier si des liens de pages web ne fonctionnent plus 1.5 Whois en PHP

    Récupérer le texte du sommaire c’est déjà très bien. Un lien peut être ajouté dans le PDF pour proposer la consultation du wiki. J’aurais tout de même souhaité conserver les liens dans le sommaire, pour pointer vers le wiki.

    Merci de votre avis.

    • Buzut

      dit :

      Hello,

      Par manque de temps, difficile de regarder de près ton cas. Bien que pas super intuitive, normalement tu dois pouvoir y arriver avec XPath (si ce que tu veux est sélectionnable avec les sélecteurs CSS, normalement, tu dois pouvoir le récupérer avec XPath).
      Faut creuser la doc.

      Sinon, tu peux aussi te tourner vers des bibliothèques tierces [en]

  • Zer00CooL

    dit :

    J’ai pu avancer.
    J’arrive maintenant bien à récupérer les éléments texte ou la numérotation du sommaire.
    Je reste bloqué pour utiliser les deux en même temps, pour afficher la numérotation devant le rendu texte.

    $new = new DOMDocument();
    @$new->loadHtml(« $resultat »);
    $xpath = new DOMXPath($new);
    // $domExemple = $xpath->query(« //ul/li »);
    //$domExemple = $xpath->query(« //ul/li[@class=’toclevel-1 tocsection-1′] »);
    //$domExemple = $xpath->query(« //span[@class=’tocnumber’] | //span[@class=’toctext’] »);
    $toctext = $xpath->query(« //span[@class=’toctext’] »);
    $tocnumber = $xpath->query(« //span[@class=’tocnumber’] »);

    $i = 0;
    foreach ($toctext as $text) {
    $result[$i++] = $text->nodeValue;

    foreach ($tocnumber as $number) {
    $result[$i++] = $number->nodeValue;
    }

    $html = $html . «  » . $number->nodeValue .  » « .$text->nodeValue;
    }

    // Le rendu sera du type :
    6.3 Utiliser PHP
    6.3 Déployer du PHP avec Ansible
    6.3 Faille include
    6.3 error_reporting

    On voit bien que le texte est correctement affiché, mais, la numérotation reste figée avec le dernier élément de numérotation.

    Je continue de chercher, merci.

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *