Précédent   Forum des professionnels en informatique > PHP > Langage > Regex
Regex Forum d'entraide sur les expressions rationnelles PHP. Avant de poster -> FAQ regex, Cours de regex et Sources de regex
Partagez cette discussion sur d'autres réseaux sociaux : Viadeo Twitter Google Facebook Digg Delicious MySpace Yahoo
Réponse Proposer ce sujet en actualité
 
Outils de la discussion
Publicité
'
Vieux 30/08/2005, 19h40   #1
Nouveau Membre du Club
 
Avatar de micatmidog
 
Inscription : février 2004
Messages : 94
Détails du profil
Informations personnelles :
Âge : 21
Localisation : France, Loiret (Centre)

Informations forums :
Inscription : février 2004
Messages : 94
Points : 38
Points : 38
Par défaut Récupérer tous les liens d'une page

Bonjour à tous,

J'aimerais récupérer tous les liens de n'importe quelle page.

Moi et un ami avons programmé ce code :

Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
$url_begin="http://www.example.com/";
 
function get_liens($url,$no_lien)
           {
              $html = file_get_contents($url);
 
              if (preg_match('#<a href="(.*)">(.*)</a>#', $html, $match))
                 return $match[$no_lien];
              else 
                 return FALSE;
           }
           function nb_liens($url)
           {
              $nb_liens=0;
              $html = file_get_contents($url);
              while(preg_match('#<a href="(.*)">(.*)</a>#', $html, $match)) $nb_liens++;
              return $nb_liens;
           }
for($i=1;$i<=$nb_liens+1;$i++)
           {
              echo get_liens("$url_begin",$i); echo" <br>";
              $i++;
           }
Mais cela n'affiche qu'un seul lien.

Pouvez-vous nous aider svp pour que ça affiche tous les liens de la page choisie ?

Merci d'avance.
micatmidog est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 30/08/2005, 20h46   #2
Membre chevronné
 
Inscription : mai 2005
Messages : 657
Détails du profil
Informations forums :
Inscription : mai 2005
Messages : 657
Points : 722
Points : 722
Salut,

Utilise preg_match_all pour trouver tout les résultat de ton expression régulière (preg_match ne cherche que le premier).

Je pense que quelque chose comme ceci devrait fonctionner (je le fais de tête alors je peux me tromper ) :
Code :
1
2
3
4
5
6
7
8
9
10
11
 
$html = file_get_contents($url);
 
if ($nb_liens = preg_match_all('#<a href="(.*)">(.*)</a>#', $html, $matches)) {
  echo "$nb_liens trouvés :<br />";
  foreach ($matches as $m) {
    echo "$m[0] (url: $m[1], texte: $m[2])<br />";
  }
} else {
  echo "Aucun lien trouvé";
}
Taum est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 30/08/2005, 21h10   #3
Nouveau Membre du Club
 
Avatar de micatmidog
 
Inscription : février 2004
Messages : 94
Détails du profil
Informations personnelles :
Âge : 21
Localisation : France, Loiret (Centre)

Informations forums :
Inscription : février 2004
Messages : 94
Points : 38
Points : 38
Merci pour ton aide, mais ça marque toujours "Aucun lien trouvé".

Edit: Ah si ça fonctionne, mais cela me donne un résultat étrange.

Pour developpez.com :

44 trouvés :
Citation:
(l'image du logo)(url: Forums | Tutoriels | F.A.Q's | Participez | Hébergement | Contacts, texte: Club)
http://www.developpez.com" onclick="xt_med('C','','click_logo','N') (url: http://www.developpez.net/forums/index.php" onclick="window.open(this.href); return false;" class="ntdrub">Forums | Tutoriels | F.A.Q's | Participez | Hébergement | (url: Contacts, texte: Club)
On peut dire que c'est à moitié résolu, merci bcp pour ton aide.
Je ne met pas [résolu] si d'autres personnes veulent bien nous aider à améliorer le code.

Merci
micatmidog est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 30/08/2005, 22h13   #4
Expert Confirmé Sénior
 
Homme Mathias Gaunard
Ingénieur développement logiciels
Inscription : décembre 2003
Messages : 3 543
Détails du profil
Informations personnelles :
Nom : Homme Mathias Gaunard
Localisation : France, Essonne (Île de France)

Informations professionnelles :
Activité : Ingénieur développement logiciels

Informations forums :
Inscription : décembre 2003
Messages : 3 543
Points : 4 408
Points : 4 408
Ce serait plutôt un truc du style #<a\s+href("|'|)(.*)\1\s*>(.*)</a>#is
loufoque est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 31/08/2005, 03h07   #5
Nouveau Membre du Club
 
Avatar de micatmidog
 
Inscription : février 2004
Messages : 94
Détails du profil
Informations personnelles :
Âge : 21
Localisation : France, Loiret (Centre)

Informations forums :
Inscription : février 2004
Messages : 94
Points : 38
Points : 38
Merci loufoque, mais ce que tu m'a donné est vraiment zarb O_°.

Sinon j'ai essayé ceci :

Code :
1
2
3
4
5
6
7
8
9
10
$html = file_get_contents($url_begin);
 
if ($nb_liens = preg_match_all('#<a href="(.*)">#', $html, $match)) {
  echo "$nb_liens trouvés :<br>";
  foreach ($match as $m) {
    echo "$m[0]<br>";
  }
} else {
  echo "Aucun lien trouvé<br>";
}
Résultat pour developpez.com :

Citation:
46 trouvés :

http://www.developpez.com" onclick="xt_med('C','','click_logo','N')
ça se rapproche déjà plus du résultat que je souhaite (donc l'url de tous les liens d'une page).
micatmidog est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 31/08/2005, 05h06   #6
Expert Confirmé Sénior
 
Homme Mathias Gaunard
Ingénieur développement logiciels
Inscription : décembre 2003
Messages : 3 543
Détails du profil
Informations personnelles :
Nom : Homme Mathias Gaunard
Localisation : France, Essonne (Île de France)

Informations professionnelles :
Activité : Ingénieur développement logiciels

Informations forums :
Inscription : décembre 2003
Messages : 3 543
Points : 4 408
Points : 4 408
Bon j'ai testé mon truc et je l'ai amélioré.
ça récupère tout, même si y'a pas de " ou de ', s'il y a d'autres arguments etc.

Code :
#<a\s.*?(?(?<!\s)\s)href=(["'])?((?(1).*?|\S*))(?(1)\1).*?\>(.*?)</a>#is
Je trouve 185 liens moi pour developpez.com

Tu veux que je t'explique la regex point par point ?
loufoque est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 31/08/2005, 15h54   #7
Nouveau Membre du Club
 
Avatar de micatmidog
 
Inscription : février 2004
Messages : 94
Détails du profil
Informations personnelles :
Âge : 21
Localisation : France, Loiret (Centre)

Informations forums :
Inscription : février 2004
Messages : 94
Points : 38
Points : 38
je veux bien

merci beaucoup
micatmidog est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 31/08/2005, 19h28   #8
Expert Confirmé Sénior
 
Homme Mathias Gaunard
Ingénieur développement logiciels
Inscription : décembre 2003
Messages : 3 543
Détails du profil
Informations personnelles :
Nom : Homme Mathias Gaunard
Localisation : France, Essonne (Île de France)

Informations professionnelles :
Activité : Ingénieur développement logiciels

Informations forums :
Inscription : décembre 2003
Messages : 3 543
Points : 4 408
Points : 4 408
Argh j'aurais pas du te proposer.
T'as réussi ton truc au moins, ça fonctionne bien ?

Bon, # sont les délimiteurs de l'expression régulière. On voit déjà que j'ai spécifié deux options : i (insensible à la casse) et s (le caractère . peut aussi récupérer des retours à la ligne)
Ce sont les options qu'on utilise la plupart du temps.

Je commence par chercher "<a" suivi d'un espace blanc (espace, retour à la ligne, tabulation, etc.)

Puis je recherche n'importe quel caractère (.) présent zéro ou un nombre indeterminé de fois (*) mais de façon non gourmande (?) c'est à dire que cela s'arrête dès la première fois où on trouve la suite de l'expression, alors que si c'était gourmand ça irait jusqu'à la dernière fois. (Voir plus bas sur des infos sur la gourmandise).
Tout ceci dans le but de permettre que l'élement <a> dispose d'autres attributs avant href. Cependant il manque encore quelque chose, là ça pourrait prendre <a truchref=etc. alors qu'on ne veut prendre que des trucs genre <a truc href=etc. On fait donc un motif conditionnel, en utilisant pour condition un lookbehind: on regarde si le dernier caractère (détecté par .*?) n'est pas un caractère blanc, et si c'est le cas on oblige l'expression a en contenir un.

Ensuite on recherche "href=" puis, éventuellement, le caractère " ou ' que l'on stocke dans 1.
On fait ensuite un motif conditionnel (que l'on capture dans 2, ce sera le lien) avec pour condition l'existence de 1.
Si 1 existe on prend n'importe quel caractère n'importe quel nombre de fois de façon non-gourmande (.*?) sinon on prend les caractères qui ne sont pas blancs n'importe quel nombre de fois.
Ensuite si 1 existe on s'arrête à la prochaine fois qu'on rencontre 1 (j'aurais bien aimé l'intégrer directement dans la première condition mais je n'arrivais alors pas à mettre les valeurs dans le même index)
C'est bon, on a récupéré la valeur de l'attribut href.

On permet ensuite n'importe quel caractère n'importe quel nombre de fois de façon non gourmande jusqu'à ">" (je l'ai échappé mais en fait y'a pas besoin), puis on capture dans 3 n'importe quel caractère n'importe quel nombre de fois de façon non-gourmande (ce sera l'intitulé du lien) puis on prend </a>. Cela ne pourra pas supporter des <a> imbriqués (ça necessiterait de remplacer le (.*?) par quelque chose de plus complexe) mais de toutes façons cela ne doit pas exister.

Voilà, ouf, on a réussi. ça devrait pouvoir récupérer tous les liens de façon parfaite.

Bon, les explications sur la gourmandise. On comprend bien avec un exemple, la balise
Citation:
en BBCode.
Si mon texte est "
Citation:
test
", utiliser .* ou .*? ne change rien
Si j'ai "
Citation:
test1
Citation:
test2
", avec .* j'aurais "test1
[quote]test2" alors qu'avec .*? j'aurais "test1" puis "test2"
Enfin si j'ai "
Citation:
foo
Citation:
test
bar
" avec .* j'aurais "foo
Citation:
test
bar" et avec .*? "foo
Citation:
test".
Je suppose qu'avec ces exemples, tu comprends (enfin j'espère).

Mais alors, comment faire pour, avec
"
Citation:
test1
Citation:
test2
Citation:
foo
Citation:
test3
bar
" obtenir "test1", "test2" puis "foo
Citation:
test3
bar" ?
Et bien il faut utiliser un motif récursif (?R), ce qui donne
((?:(?:(?!\
).)*(?R).*?)+|.*?)
(mettre ?: au début d'une parenthèse permet de ne pas la capturer, les parenthèses servant ici à grouper les élements pour y appliquer des * ou des +)
(?!truc) est un lookahead.
loufoque est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 30/09/2005, 23h47   #9
Nouveau Membre du Club
 
Avatar de micatmidog
 
Inscription : février 2004
Messages : 94
Détails du profil
Informations personnelles :
Âge : 21
Localisation : France, Loiret (Centre)

Informations forums :
Inscription : février 2004
Messages : 94
Points : 38
Points : 38
il ne fonctionne pas chez moi ce regex,

merci en tout cas pour ce mini-cours.

PS: Vive les expressions régulières

J'ai acheté le gros book :

PHP 5 / MySQL 5 : La Référence chez Campus Press (900 pages)

Malgré un sous chapitre entièrement consacré aux expressions régulières, ben j'ai toujours du mal à m'en servir mdr... c'est du chinois !
micatmidog est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 30/09/2005, 23h53   #10
Membre Expert
 
Avatar de ska_root
 
Homme
Développeur informatique
Inscription : août 2005
Messages : 1 179
Détails du profil
Informations personnelles :
Sexe : Homme
Âge : 42
Localisation : France

Informations professionnelles :
Activité : Développeur informatique
Secteur : Service public

Informations forums :
Inscription : août 2005
Messages : 1 179
Points : 1 580
Points : 1 580
j'admire ta patience loufoque,
on voit que les regexp c'est vraiment ton truc
__________________
http://cdemarche.developpez.com/

Tu as la réponse à ta question ? N'oublies pas le petit en bas à gauche de ton message...
ska_root est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 01/10/2005, 00h12   #11
Nouveau Membre du Club
 
Avatar de micatmidog
 
Inscription : février 2004
Messages : 94
Détails du profil
Informations personnelles :
Âge : 21
Localisation : France, Loiret (Centre)

Informations forums :
Inscription : février 2004
Messages : 94
Points : 38
Points : 38
ouep, puis moi ça fonctionne toujours pas :

Code :
1
2
3
4
5
6
7
8
$chaine = file_get_contents("http://www.zonewindows.com/");
 
$motif='#<a href="(.*)">#is';
preg_match_all($motif,$chaine,$out);
$nb=count($out[0]);
for($i=0;$i<$nb;$i++){
echo $out[0][$i].'<br/>';
}
Rien ne marche...

Inspiré de l'exemple de la fonction preg_match_all ici :

http://www.expreg.com/pregmatchall.php
micatmidog est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 01/10/2005, 00h30   #12
Membre Expert
 
Avatar de ska_root
 
Homme
Développeur informatique
Inscription : août 2005
Messages : 1 179
Détails du profil
Informations personnelles :
Sexe : Homme
Âge : 42
Localisation : France

Informations professionnelles :
Activité : Développeur informatique
Secteur : Service public

Informations forums :
Inscription : août 2005
Messages : 1 179
Points : 1 580
Points : 1 580
et ça ?

Code :
1
2
3
4
5
6
7
8
9
10
 
$chaine = file_get_contents("http://www.zonewindows.com/");
 
$motif='#<a href="(.*?)"(.*?)>#is';
 
preg_match_all($motif,$chaine,$out,PREG_PATTERN_ORDER);
 
foreach ($out[1] as $link) {
echo "$link<br />";
}
__________________
http://cdemarche.developpez.com/

Tu as la réponse à ta question ? N'oublies pas le petit en bas à gauche de ton message...
ska_root est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 01/10/2005, 00h32   #13
Nouveau Membre du Club
 
Avatar de micatmidog
 
Inscription : février 2004
Messages : 94
Détails du profil
Informations personnelles :
Âge : 21
Localisation : France, Loiret (Centre)

Informations forums :
Inscription : février 2004
Messages : 94
Points : 38
Points : 38
Loooooool, merci beaucoup
micatmidog est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 03/11/2006, 01h37   #14
Nouveau Membre du Club
 
Avatar de micatmidog
 
Inscription : février 2004
Messages : 94
Détails du profil
Informations personnelles :
Âge : 21
Localisation : France, Loiret (Centre)

Informations forums :
Inscription : février 2004
Messages : 94
Points : 38
Points : 38
Après une hibernation de quelques mois, je reviens en force pour vous demander encore une fois de l'aide pour la même chose.

Cette fois-ci j'aimerais que ma regex prennent seulement les liens possédant http:// au début.

Code :
#<a href="(http://.*?)"(.*?)>#is
Ceci me semble fonctionner, mais je n'ai pas l'impréssion que ce soit très propre.
Si quelqu'un sait comment l'optimiser...

Merci d'avance.
micatmidog est déconnecté   Envoyer un message privé Réponse avec citation 00
Réponse Proposer ce sujet en actualité
Outils de la discussion



Fuseau horaire GMT +2. Il est actuellement 18h48.


 
 
 
 
Partenaires

Hébergement Web