[RESOLU] Extraire entre 2 balises avec preg_match_all

Eléphanteau du PHP | 37 Messages

13 mai 2011, 18:04

Bonjour à tous,

Je ne parviens pas avec preg_match_all à extraire un morceau de code dans une page...

Ce que je cherche, c'est un masque du style

Code : Tout sélectionner

ob_start (); $scan = file_get_contents($url); if(preg_match('#<div class="nom_adherent">(.*)</div>#', $scan, $sortie)){ $resultat = $sortie[1]; $nom_adherent=$resultat; echo"<h1>Y'en a un : $nom_adherent</h1>"; } ob_end_flush();
... qui permettrait d'extraire le nom de l'adhérent.

Par exemple, depuis le code-source ci-dessous,
<div class="nom_adherent">

BIBLIOTHEQUE MEDIATHEQUE </div>
on sortirait "BIBLIOTHEQUE MEDIATHEQUE".

Il y a plein d'espaces avant et après le nom à extraire, je crois que c'est surtout ceux-ci qui m'embêtent, et je ne suis pas très à l'aise avec preg_match_all...

Si j'utilise eregi() à la place, le code sélectionne de "<div class="nom_adherent">" à la toute dernière balise </div>. C'est bien trop. De toute façon, je crois bien que cette fonction n'est plus à la page.

Comment peut-on ainsi programmer en php :
" Dans le code source, tu commences au premier <div class="nom_adherent"> rencontré, tu choppes tout jusqu'à la prochaine </div> et stop !

Souhaitant m'exprimer le plus clairement possible, je vous salue bien bas, en espérant que quelqu'un puisse m'éclairer.

Ecumastor.
-- Ecumastor

ViPHP
ViPHP | 2291 Messages

13 mai 2011, 19:35

Salut,

Comme ceci peut-être ?
<?php

$nom_adherent = '<div class="nom adherent"></div>';
preg_match('|<div class="(.*)"></div>|', $nom_adherent, $resultat);


echo '<pre>';
 echo $resultat[1];
echo '</pre>';

?>
A+
ImageCe que l'on apprend par l'effort reste toujours ancré beaucoup plus longtemps.

Eléphant du PHP | 60 Messages

13 mai 2011, 20:50

@dunbar
ce ne serait pas plutôt
preg_match('|<div class="nom adherent">(.*)</div>|', $nom_adherent, $resultat);
au lieu de
preg_match('|<div class="(.*)"></div>|', $nom_adherent, $resultat);
?

cf. Test du code modifié
"La connaissance s'acquiert par l'expérience, tout le reste n'est que de l'information"
Albert Einstein.

ViPHP
ViPHP | 2291 Messages

13 mai 2011, 21:52

@dunbar
ce ne serait pas plutôt
preg_match('|<div class="nom adherent">(.*)</div>|', $nom_adherent, $resultat);
au lieu de
preg_match('|<div class="(.*)"></div>|', $nom_adherent, $resultat);
?

cf. Test du code modifié
Effectivement oups trop stupide autant pour moi :cry:
ImageCe que l'on apprend par l'effort reste toujours ancré beaucoup plus longtemps.

Avatar du membre
Modérateur PHPfrance
Modérateur PHPfrance | 10684 Messages

13 mai 2011, 21:58

En l’occurrence c'est nom_adherent, et vu que c'est le code qu'il a posté dans son topic de départ, j'aurais tendance à dire que ce n'est pas la réponse qu'il attend ;)

Regarde plutôt du côté des options des expressions régulières... notamment l'option U (ungreedy) qui permet de spécifier si php s'arrête au premier au premier </div> qu'il va trouver ou s'il doit aller jusqu'au dernier.

Les espaces qui précèdent ne posent pas de problème dans ton expression, il seront inclus dans le .* (par contre faudra peut être faire un trim si tu veux les enlever une fois ta valeur récupérée, ou tu peux les prévoir dans ton expression pour ne pas les capturer)
Ce n'est pas en améliorant la bougie que l'on a inventé l'ampoule...

Eléphanteau du PHP | 37 Messages

14 mai 2011, 00:48

Bon...
D'abord, merci à vous, Ryle, Dunbar et GiorgioLino pour vos aides, ça fait plaisir.

En fonction de vos dires, j'ai fait quelques tests afin d'extraire ce fameux "nom_adherent" :
<?
$scan = '<div class="nom_adherent"> BIBLIOTHEQUE MEDIATHEQUE </div>';
preg_match('|<div class="nom_adherent">(.*)</div>|', $scan, $sortie);
echo "Resultat scan : $sortie[1]<br>";
?>
Ca fonctionne très bien si $scan est bien défini.

Moi, je lui fais scanner toute la page, d'où un essai comme ça :
<?
$scan = '<div class="nom_adherent">

							BIBLIOTHEQUE MEDIATHEQUE                                   </div>'; // j'ai volontairement copié le code tel quel avec les espaces depuis le code-source
echo "Pas transformé : $scan<br>";
$scan=htmlspecialchars($scan)."<br>";
echo "Transformé : $scan<br>";
preg_match('|<div class="nom_adherent">(.*)</div>|', $scan, $sortie);
echo "Resultat scan : $sortie[1]<br>";
?>
Là ça ne renvoie rien. Pourtant ce code m'affiche :
Pas transformé :
BIBLIOTHEQUE MEDIATHEQUE

Transformé : <div class="nom_adherent"> BIBLIOTHEQUE MEDIATHEQUE </div>

Resultat scan :
... et cependant, une fois transformé, j'ai le même affichage qu'au début, à savoir <div class="nom_adherent"> BIBLIOTHEQUE MEDIATHEQUE </div> !!!

Le fait d'employer htmlspecialchars() modifie-t-il en quelque sorte la "valeur" de la ligne ? Ce n'est pas vu comme une chaîne, telle que dans le premier test ?

Le même test avec file_get_contents() au lieu de htmlspecialchars(), voire les deux combinés, ne m'apportent toujours pas le résultat escompté.

Vous y comprenez quelque-chose, vous ? 8-|

Jusqu'ici je m'en sortais avec eregi() pour extraire le titre (<title>....</title>) :
<?
$url="http://www.gerardmer.net/bibliotheque-mediatheque_francais.php";
$scan = file_get_contents($url);
if(eregi('<title>(.*)</title>', $scan, $sortie)){
echo "Resultat scan : $sortie[1]<br>";
}
?>
Résultat :
Resultat scan : Bibliothèque et médiathèque
La fête !
Mais cette méthode là plante dans mon cas.

Et quant à rajouter le "U" dans preg_match, je ferai ça par la suite. Merci pour l'idée. Déjà le premier résultat, on verra bien par la suite pour les autres. Je n'ai qu'un titre dans chaque page, mais plusieurs adhérents dans d'autres...
Pour l'histoire, je cherche à fabriquer de mes petites mains malhabiles un moteur de recherche. J'y suis presque...

Encore merci à vous.

Ecumastor
-- Ecumastor

Avatar du membre
Modérateur PHPfrance
Modérateur PHPfrance | 8758 Messages

14 mai 2011, 08:49

salut,

htmlentities va transformer en entitées html en leurs correspondt "html"
htmlentities() est identique à la fonction htmlspecialchars(), sauf que tous les caractères qui ont des équivalents en entités HTML sont effectivement traduits.
L'exemple 1 montre bien ton problème lors de sont utilisation dans ton code
<?php
$str = 'Un \'apostrophe\' en <strong>gras</strong>';

// Affiche : Un 'apostrophe' en <strong>gras</strong>
echo htmlentities($str);

// Affiche : Un 'apostrophe' en <strong>gras</strong>
echo htmlentities($str, ENT_QUOTES);
?>
Ensuite tu souhaite trouver une suite de mot qui sera présente entre ces balises avec un motif pas forcément identique à l'exemple ? (donc pas forcément avec des espaces autours) ou alors ce sera toujours le même motif ?

Suivant le cas ce ne sera pas la même chose ;)

@+
Il en faut peu pour être heureux ......

Eléphanteau du PHP | 37 Messages

14 mai 2011, 10:51

Bonjour Moogli.

Curieusement, je ne vois pas de différences à l'écran avec cet exemple :
Un 'apostrophe' en <strong>gras</strong>Un 'apostrophe' en <strong>gras</strong>
Mais j'ai essayé de voir si htmlentities agissait sur mon code-source :
<?
$url="http://www.gerardmer.net/bibliotheque-mediatheque_francais.php";
$code_page = file_get_contents($url);

$scan=htmlentities($code_page);
preg_match('|<div class="nom_adherent">(.*)</div>|', $scan, $sortie);
echo "Resultat nom_adherent : ".$sortie[1]."<br>";
preg_match('|<title>(.*)</title>|', $scan, $sortie);
echo "Resultat titre : ".$sortie[1]."<br>";
echo substr($scan,20000,5000);
echo"<hr>";

$scan=htmlentities($code_page,ENT_QUOTES);
preg_match('|<div class="nom_adherent">(.*)</div>|', $scan, $sortie);
echo "Resultat nom_adherent : ".$sortie[1]."<br>";
preg_match('|<title>(.*)</title>|', $scan, $sortie);
echo "Resultat titre : ".$sortie[1]."<br>";
echo substr($scan,20000,5000);
echo"<hr>";

$scan=htmlentities($code_page,ENT_QUOTES,'UTF-8');
preg_match('|<div class="nom_adherent">(.*)</div>|', $scan, $sortie);
echo "Resultat nom_adherent : ".$sortie[1]."<br>";
preg_match('|<title>(.*)</title>|', $scan, $sortie);
echo "Resultat titre : ".$sortie[1]."<br>";
echo substr($scan,20000,5000);
echo"<hr>";

$scan=htmlentities($code_page,ENT_NOQUOTES,'UTF-8');
preg_match('|<div class="nom_adherent">(.*)</div>|', $scan, $sortie);
echo "Resultat nom_adherent : ".$sortie[1]."<br>";
preg_match('|<title>(.*)</title>|', $scan, $sortie);
echo "Resultat titre : ".$sortie[1]."<br>";
echo substr($scan,20000,5000);
echo"<hr>";
?>
Résultat :
Resultat nom_adherent :
Resultat titre :
tre" src="/images/logos/loisirs.png"> Bibliothèque / Médiathèque</h1> <div class="imprimer-la-liste"><a href="imprimer-pages/imprimer.php?page_cible=bibliotheque-mediatheque" target="_blank"> <img src='../images/divers/imprimer-la-liste.png'></a></div> <table border="0" width="650px" style="margin-bottom:30px;text-align:left;color:white;"> <a name="ancre_139670">&nbsp;</a> <a name="ancre_777000295">&nbsp;</a> <a name="BIBLIOTHEQUE MEDIATHEQUE_vosges">&nbsp;</a> <tr bgcolor="#816D6D"> <td colspan="4"> <table border="0" width="100%" height="50px" cellpadding="0" cellspacing="0"> <tr> <td align="left"> <div class="nom_adherent"> BIBLIOTHEQUE MEDIATHEQUE </div> Act. Culturelle / artisanale </td> <td align="right" width="100px"> </td> </tr> </table> </td> </tr> <tr> <!-- photo petit cadre --> <td width="100px" height="50px" valign="top" class="vignettes"> <img src='/aspirations/optimisees_100-777000295_4.jpg' alt='Act. Culturelle / artisanale : BIBLIOTHEQUE MEDIATHEQUE'> </td> <td valign="top" style="font-size:0.7em"> BIBLIOTHEQUE MEDIATHEQUE<br>ESPACE TILLEUL<br>16 RUE CHARLES DE GAULLE <br>88400 GERARDMER <br>T&eacute;l. : 03 29 63 00 70<br> </td> <td rowspan="2" valign="top" style="font-size:0.7em"> <table id="tableau_affichage_details_adherents" width="290px"> <tr><td><item>Animaux acceptés</item></td><td><item_desc>Non <b</item_desc></td></tr><tr><td><item>Groupes acceptés</item></td><td><item_desc>Non <b</item_desc></td></tr><tr><td><item>Localisation</item></td><td><item_desc>En centre-ville <b</item_desc></td>



Resultat nom_adherent :
Resultat titre :
rif;text-align:justify;font-size:1em;'> <a name="top"></a> <h4> <a href='index_francais.php'>Accueil</a> > <a href='loisirsdetente_francais.php'>Loisirs et d&eacute;tente</a> > Bibliothèque / Médiathèque</h4> <h1> <img class="logo_titre" src="/images/logos/loisirs.png"> Bibliothèque / Médiathèque</h1> <div class="imprimer-la-liste"><a href="imprimer-pages/imprimer.php?page_cible=bibliotheque-mediatheque" target="_blank"> <img src='../images/divers/imprimer-la-liste.png'></a></div> <table border="0" width="650px" style="margin-bottom:30px;text-align:left;color:white;"> <a name="ancre_139670">&nbsp;</a> <a name="ancre_777000295">&nbsp;</a> <a name="BIBLIOTHEQUE MEDIATHEQUE_vosges">&nbsp;</a> <tr bgcolor="#816D6D"> <td colspan="4"> <table border="0" width="100%" height="50px" cellpadding="0" cellspacing="0"> <tr> <td align="left"> <div class="nom_adherent"> BIBLIOTHEQUE MEDIATHEQUE </div> Act. Culturelle / artisanale </td> <td align="right" width="100px"> </td> </tr> </table> </td> </tr> <tr> <!-- photo petit cadre --> <td width="100px" height="50px" valign="top" class="vignettes"> <img src='/aspirations/optimisees_100-777000295_4.jpg' alt='Act. Culturelle / artisanale : BIBLIOTHEQUE MEDIATHEQUE'> </td> <td valign="top" style="font-size:0.7em"> BIBLIOTHEQUE MEDIATHEQUE<br>ESPACE TILLEUL<br>16 RUE CHARLES DE GAULLE <br>88400 GERARDMER <br>T&eacute;l. : 03 29 63 00 70<br> </td> <td rowspan="2" valign="top" style="font-size:0.7em"> <table id="tableau_affichage_details_adherents" width="290px"> <tr><td><item>Anima



Resultat nom_adherent :
Resultat titre :
rc="/images/logos/loisirs.png"> Bibliothèque / Médiathèque</h1> <div class="imprimer-la-liste"><a href="imprimer-pages/imprimer.php?page_cible=bibliotheque-mediatheque" target="_blank"> <img src='../images/divers/imprimer-la-liste.png'></a></div> <table border="0" width="650px" style="margin-bottom:30px;text-align:left;color:white;"> <a name="ancre_139670">&nbsp;</a> <a name="ancre_777000295">&nbsp;</a> <a name="BIBLIOTHEQUE MEDIATHEQUE_vosges">&nbsp;</a> <tr bgcolor="#816D6D"> <td colspan="4"> <table border="0" width="100%" height="50px" cellpadding="0" cellspacing="0"> <tr> <td align="left"> <div class="nom_adherent"> BIBLIOTHEQUE MEDIATHEQUE </div> Act. Culturelle / artisanale </td> <td align="right" width="100px"> </td> </tr> </table> </td> </tr> <tr> <!-- photo petit cadre --> <td width="100px" height="50px" valign="top" class="vignettes"> <img src='/aspirations/optimisees_100-777000295_4.jpg' alt='Act. Culturelle / artisanale : BIBLIOTHEQUE MEDIATHEQUE'> </td> <td valign="top" style="font-size:0.7em"> BIBLIOTHEQUE MEDIATHEQUE<br>ESPACE TILLEUL<br>16 RUE CHARLES DE GAULLE <br>88400 GERARDMER <br>T&eacute;l. : 03 29 63 00 70<br> </td> <td rowspan="2" valign="top" style="font-size:0.7em"> <table id="tableau_affichage_details_adherents" width="290px"> <tr><td><item>Animaux acceptés</item></td><td><item_desc>Non <b</item_desc></td></tr><tr><td><item>Groupes acceptés</item></td><td><item_desc>Non <b</item_desc></td></tr><tr><td><item>Localisation</item></td><td><item_desc>En centre-ville <b</item_desc></td></tr><tr><td



Resultat nom_adherent :
Resultat titre :
><item>Prestations proposées / Activités</item></td><td><item_desc>Pratique libre <br>Location de matériel <b</item_desc></td></tr><tr><td colspan='2'><item_desc>- Section adultes : prêt de livres ou consultation sur place - espace convivial Bandes...<a href='bibliotheque-mediatheque_777000295.php'><img src='/images/divers/suite.png'></a></item_desc></td></tr></table> </td> <td width="30" rowspan="2" valign="top"> <a href="/carte-adherent-777000295_francais.php"><img src="/images/hebergements/localisation.png"></a> <a href="/infos-supp-777000295_francais.php"><img src="/images/hebergements/details.png"></a> <a href='#top'><img src='images/divers/top.png'></a> </td> </tr> <tr> <td colspan="2" valign="top" class="vignettes"> <table border="0" width="270"> <tr> <td style="font-size:0.7em"> Site : <a href='http://mairie-gerardmer.fr/culture/la-mediatheque' target='_blank'>mairie-gerardmer.fr/culture/la-mediatheque</a><br> </td> <td width="70" class="thumbshot"> <div><a href='http://mairie-gerardmer.fr/culture/la-mediatheque' target='_blank'><img src='http://open.thumbshots.org/image.pxf?ur ... ediatheque' height='50px' alt='Site de bibliotheque mediatheque'></a></div> </td> </tr> </table> <table> <tr> <td valign="top" style="font-size:0.7em"> </td> </tr> </table> </td> </tr> <tr> <td colspan="3" style="font-size:0.7em" valign="top"> </td> </tr> <tr> <td colspan="3"> </td> </tr> <tr id="petit_bandeau_affichage_maj"> <td colspan="4" style="text-align:center;font-size:0.6em;color:white"> &nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Photos et descriptifs non contractu


Les affichages des portions de code-source différent un peu, leur taille aussi, mais cela ne m'affiche ni le titre, ni la balise que je cherche à extraire (<div class="nom_adherent">on_veut_ça</div>
Ensuite tu souhaite trouver une suite de mot qui sera présente entre ces balises avec un motif pas forcément identique à l'exemple ? (donc pas forcément avec des espaces autours) ou alors ce sera toujours le même motif ?
J'ai des pages avec plusieurs adhérents : Exemple ici http://www.gerardmer.net/artisanat-du-cuir_francais.php
Il me faudra au final extraire "ATELIER CUIR" et "EQUI'VAL - MD CUIR". Et plus encore sur d'autres pages plus fournies !
Tous ces noms ont pour point commun la balise <div classs="nom_adherent">nom_adherent</div> : mes point de repères de déprt et d'arrivée pour les extraction.
-- Ecumastor

Avatar du membre
Modérateur PHPfrance
Modérateur PHPfrance | 10684 Messages

14 mai 2011, 14:23

Ce que tu vois à l'écran est l'interprétation du code source par le navigateur, ta véritable chaine est dans la source de la page...

Que ce soit htmlspecialchars ou htmlentities, ces deux fonctions vont effectivement altérer ta chaine. Le meilleur exemple étant que le caractère "<" va être remplacé par la chaine "<". De fait, si tu continues de chercher le caractère "<" dans ton expression régulière, tu ne risques plus de le trouver... :)
Ce n'est pas en améliorant la bougie que l'on a inventé l'ampoule...

Eléphanteau du PHP | 37 Messages

14 mai 2011, 16:42

Merci pour ta réponse, Ryle.

D'accord, mais alors dans ce cas, peut-on importer l'ensemble du code-source, de manière à ce qu'il soit vu comme une chaîne ?
Car, même avec file_get_contents(), qui lui semble gérer le code comme une chaîne (je peux en extraire la balise <title>), comment se fait-il qu'il ne puisse accéder à la balise <div class="nom_adherent>...extraire...</div> ???
Ce sont les guillements qui gênent ?

J'ai essayé alors de traiter la chaine obtenue, en remplaçant avec preg_match :
<title>(.*)</title> par <title>(.*)</title> et aussi <div class="nom_adherent">(.*)</div> par <div class="nom_adherent">(.*)</div>

Ca marche pour retrouver le titre, pas encore pour retrouver le nom_adherent.

Y a t-il encore là dedans (<div class="nom_adherent">(.*)</div>) des caractères qui gênent ?
<?
$url="http://www.gerardmer.net/bibliotheque-mediatheque_francais.php";
$code_page = file_get_contents($url);

$scan=htmlentities($code_page,ENT_QUOTES);
preg_match('|<div class="nom_adherent">(.*)</div>|', $scan, $sortie);
echo "Resultat nom_adherent : ".$sortie[1]."<br>";
preg_match('|<title>(.*)</title>|', $scan, $sortie);
echo "Resultat titre : ".$sortie[1]."<br>";
echo htmlspecialchars($scan);
echo"<br><br><hr><br><br>";
?>
Résultat :
Resultat nom_adherent :
Resultat titre : Bibliothèque et médiathèque
... je passe sur l'affichage du code-source qui fait 20 pages !

On va y arriver ! Nom de d'là... :roll:
-- Ecumastor

Avatar du membre
Modérateur PHPfrance
Modérateur PHPfrance | 10684 Messages

14 mai 2011, 19:16

Et question bête, mais... pourquoi as-tu besoin de faire un htmlentities avant de parser ta page ?

Tu pourrais faire une recherche toute simple avec ton masque initial sur le code source que tu récupères... si ensuite tu as besoin de protéger ce code, tu pourras toujours le faire après non ?
Ce n'est pas en améliorant la bougie que l'on a inventé l'ampoule...

Eléphanteau du PHP | 37 Messages

14 mai 2011, 20:13

Eh bien, pour récupérer un code source, je crois que htmlentities est bien, car je vois le code. J'ai essayé ça, aussi htmlspecialchars, sans trop connaître.
Aussi parce que afficher file_get_contents tout seul m'affichait la page comme sur le site...
Donc je me suis rapproché du code, puisque c'est de lui que je veux extraire des morceaux. Htmlentities et htmlspecialchars vont dans ce sens.
pourquoi as-tu besoin de faire un htmlentities avant de parser ta page ?
J'en sais rien ! Je tâtonne pour extraire cette p***** de balise depuis quelques jours. J'ignorais par ailleurs que je "parsais" ma page !

Mon moteur de recherche fonctionne gentiment, mais je pourrais l'améliorer en lui donnant plus de grain à moudre, donc plus de termes extraits de mes pages...

Pour l'instant ça marche pour les balises keywords, description, h1, et h2.
Un plus serait d'en extraire aussi le nom de l'adhérent.... <div class="nom_adherent>je_veux_ça</div>. Je sais que ça doit être possible.

... Et je suis un vosgien têtu ! :wink:
-- Ecumastor

Avatar du membre
Modérateur PHPfrance
Modérateur PHPfrance | 10684 Messages

14 mai 2011, 21:55

Ok, alors effectivement, htmlentities n'est pas à utiliser dans le cas présent (elle sert en fait à "protéger" une chaine qui contient des caractères spéciaux et à les convertir en entités html pour qu'elles soient correctement interprétés quelque soit la langue du navigateur, le charset de la page, etc.)

Bref, dans ton cas, file_get_contents va lire et retourner le code source de la page. C'est ce code source que tu parses avec la fonction preg_match pour y trouver le masque que tu recherches.


Quoi qu'il en soit, si ton expression ne fonctionne pas, c'est à cause des retours à la lignes qui sont présents dans la balise div et que php semble avoir du mal à interpréter (en tout cas il ne sont pas reconnus dans le .* ). Une solution serait de les supprimer de la chaine (mais doit y avoir une explication et un moyen plus propre de le faire) :
$url="http://www.gerardmer.net/bibliotheque-mediatheque_francais.php";
$code_page = file_get_contents($url);

$code_page = str_replace("\n", "", $code_page);

preg_match('#<div class="nom_adherent">(.*)</div>#Ui', $code_page, $sortie);
print_r($sortie);

Edit : sinon ça fonctionne aussi en intégrant le \n dans l'expression, mais je ne comprend pas pourquoi le retour à la ligne n'est pas considéré comme un "n'importe quel caractère" ...
'#<div class="nom_adherent">(.*\n?)*</div>#Ui'
Ce n'est pas en améliorant la bougie que l'on a inventé l'ampoule...

Petit nouveau ! | 4 Messages

15 mai 2011, 00:12

Code : Tout sélectionner

#<div class="nom_adherent">(.*)</div>#Us
C'est pas ça, plutôt? ;)

Eléphanteau du PHP | 37 Messages

15 mai 2011, 00:47

Ouaiiiiiis ! :D
Merci Ryle !

Après moult pérégrinations, le dilemme est résolu. C'était donc le retour chariot qui coinçait... Je n'avais pas songé à ça. Mon moteur va s'en trouver amélioré !
Tu as passé du temps là dessus, sois-en remercié. Ca va beaucoup m'aider.

Ecumastor.
-- Ecumastor