[RESOLU] Extraire entre 2 balises avec preg_match_all

Répondre


Cette question est un moyen d’empêcher des soumissions automatisées de formulaires par des robots.
Smileys
:D :) :( :o :shock: :? 8-) :lol: :x :P :oops: :cry: :evil: :twisted: :roll: :wink: :!: :?: :idea: :arrow: :| :mrgreen: =D> #-o =P~ :^o :non: :priere: 8-|
Voir plus de smileys
  Revue du sujet
 

  Étendre la vue Revue du sujet : [RESOLU] Extraire entre 2 balises avec preg_match_all

Re: Extraire entre 2 balises avec preg_match_all

par ecumastor » 15 mai 2011, 12:43

Bien vu pour "s". Ca évite la ligne $code_page = str_replace("\n", "", $code_page);
Merci du tuyau.

Re: Extraire entre 2 balises avec preg_match_all

par Skw33d » 15 mai 2011, 11:40

mais je ne comprend pas pourquoi le retour à la ligne n'est pas considéré comme un "n'importe quel caractère"
Cette exception existe pour des raisons historiques. Les premiers programmes qui utiliser les expressions régulières fonctionnaient ligne par ligne. Les fichiers étaient lus ligne par ligne, et les programmes appliquaient l’expression régulière séparément pour chaque ligne. Résultat : La chaîne ne contenait donc jamais de retour à la ligne, et le point ne pouvait donc pas les prendre.
mais doit y avoir une explication et un moyen plus propre de le faire :
Et bien, recherchant aussi à prendre tout entre deux balises, je m'y suis penché il y a quelques jours, et je vous avoue que .... ÇA M'A BIEN PRIS LA TÊTE !! ^^ Mais j'ai tout de même la solution. :P
Ton code devient tout simplement celui ci :

Code : Tout sélectionner

$url="http://www.gerardmer.net/bibliotheque-mediatheque_francais.php"; $code_page = file_get_contents($url); preg_match('/<div class="nom_adherent">([\S\s]*?)</div>/i', $code_page, $sortie); print_r($sortie);
De plus, j'ai lu sur un forum que en terme de rapidité le \S\s > \s\S > (.|\n)*. La personne a fait des tests de performances et a trouvé ça.
Voilà, normalement ça devrait fonctionner. Moi je m'en servais pour remplacer le contenu mais pour extraire ou remplacer mais la regex ne change pas.

Re: Extraire entre 2 balises avec preg_match_all

par Ryle » 15 mai 2011, 11:30

Code : Tout sélectionner

#<div class="nom_adherent">(.*)</div>#Us
C'est pas ça, plutôt? ;)
Bien vu, je n'avais jamais fait attention à l'option "s" et pensais que par défaut le point remplaçait n'importe quel caractère, y compris les nouvelles lignes... Merci pour le tuyau :)

[Résolu] Extraire entre 2 balises avec preg_match_all

par ecumastor » 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.

Re: Extraire entre 2 balises avec preg_match_all

par sebounet » 15 mai 2011, 00:12

Code : Tout sélectionner

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

Re: Extraire entre 2 balises avec preg_match_all

par Ryle » 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'

Re: Extraire entre 2 balises avec preg_match_all

par ecumastor » 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:

Re: Extraire entre 2 balises avec preg_match_all

par Ryle » 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 ?

Re: Extraire entre 2 balises avec preg_match_all

par ecumastor » 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:

Re: Extraire entre 2 balises avec preg_match_all

par Ryle » 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... :)

Re: Extraire entre 2 balises avec preg_match_all

par ecumastor » 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.

Re: Extraire entre 2 balises avec preg_match_all

par moogli » 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 ;)

@+

Re: Extraire entre 2 balises avec preg_match_all

par ecumastor » 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

Re: Extraire entre 2 balises avec preg_match_all

par Ryle » 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)

Re: Extraire entre 2 balises avec preg_match_all

par dunbar » 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: