IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Langage PHP Discussion :

Récupérer tous les liens d'une page [Tutoriel]


Sujet :

Langage PHP

  1. #1
    Membre régulier Avatar de micatmidog
    Profil pro
    Inscrit en
    Février 2004
    Messages
    94
    Détails du profil
    Informations personnelles :
    Âge : 33
    Localisation : France, Loiret (Centre)

    Informations forums :
    Inscription : Février 2004
    Messages : 94
    Points : 71
    Points
    71
    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 : Sélectionner tout - Visualiser dans une fenêtre à part
    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.

  2. #2
    Membre éprouvé

    Profil pro
    Inscrit en
    Mai 2005
    Messages
    657
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2005
    Messages : 657
    Points : 910
    Points
    910
    Par défaut
    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 : Sélectionner tout - Visualiser dans une fenêtre à part
    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é";
    }
    Toute la documentation Ruby on Rails : gotapi.com/rubyrails
    Mes articles :
    > HAML : langage de template pour Ruby on Rails

  3. #3
    Membre régulier Avatar de micatmidog
    Profil pro
    Inscrit en
    Février 2004
    Messages
    94
    Détails du profil
    Informations personnelles :
    Âge : 33
    Localisation : France, Loiret (Centre)

    Informations forums :
    Inscription : Février 2004
    Messages : 94
    Points : 71
    Points
    71
    Par défaut
    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 :
    (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

  4. #4
    Expert confirmé
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Décembre 2003
    Messages
    3 549
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

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

    Informations forums :
    Inscription : Décembre 2003
    Messages : 3 549
    Points : 4 625
    Points
    4 625
    Par défaut
    Ce serait plutôt un truc du style #<a\s+href("|'|)(.*)\1\s*>(.*)</a>#is
    Boost ftw

  5. #5
    Membre régulier Avatar de micatmidog
    Profil pro
    Inscrit en
    Février 2004
    Messages
    94
    Détails du profil
    Informations personnelles :
    Âge : 33
    Localisation : France, Loiret (Centre)

    Informations forums :
    Inscription : Février 2004
    Messages : 94
    Points : 71
    Points
    71
    Par défaut
    Merci loufoque, mais ce que tu m'a donné est vraiment zarb O_°.

    Sinon j'ai essayé ceci :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    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 :

    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).

  6. #6
    Expert confirmé
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Décembre 2003
    Messages
    3 549
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

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

    Informations forums :
    Inscription : Décembre 2003
    Messages : 3 549
    Points : 4 625
    Points
    4 625
    Par défaut
    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 : Sélectionner tout - Visualiser dans une fenêtre à part
    #<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 ?
    Boost ftw

  7. #7
    Membre régulier Avatar de micatmidog
    Profil pro
    Inscrit en
    Février 2004
    Messages
    94
    Détails du profil
    Informations personnelles :
    Âge : 33
    Localisation : France, Loiret (Centre)

    Informations forums :
    Inscription : Février 2004
    Messages : 94
    Points : 71
    Points
    71
    Par défaut
    je veux bien

    merci beaucoup

  8. #8
    Expert confirmé
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Décembre 2003
    Messages
    3 549
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

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

    Informations forums :
    Inscription : Décembre 2003
    Messages : 3 549
    Points : 4 625
    Points
    4 625
    Par défaut
    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
    en BBCode.
    Si mon texte est "
    test
    ", utiliser .* ou .*? ne change rien
    Si j'ai "
    test1
    test2
    ", avec .* j'aurais "test1
    [quote]test2" alors qu'avec .*? j'aurais "test1" puis "test2"
    Enfin si j'ai "
    foo
    test
    bar
    " avec .* j'aurais "foo
    test
    bar" et avec .*? "foo
    test".
    Je suppose qu'avec ces exemples, tu comprends (enfin j'espère).

    Mais alors, comment faire pour, avec
    "
    test1
    test2
    foo
    test3
    bar
    " obtenir "test1", "test2" puis "foo
    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.
    Boost ftw

  9. #9
    Membre régulier Avatar de micatmidog
    Profil pro
    Inscrit en
    Février 2004
    Messages
    94
    Détails du profil
    Informations personnelles :
    Âge : 33
    Localisation : France, Loiret (Centre)

    Informations forums :
    Inscription : Février 2004
    Messages : 94
    Points : 71
    Points
    71
    Par défaut
    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 !

  10. #10
    Membre chevronné
    Avatar de ska_root
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2005
    Messages
    1 203
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 54
    Localisation : France

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

    Informations forums :
    Inscription : Août 2005
    Messages : 1 203
    Points : 1 839
    Points
    1 839
    Par défaut
    j'admire ta patience loufoque,
    on voit que les regexp c'est vraiment ton truc

  11. #11
    Membre régulier Avatar de micatmidog
    Profil pro
    Inscrit en
    Février 2004
    Messages
    94
    Détails du profil
    Informations personnelles :
    Âge : 33
    Localisation : France, Loiret (Centre)

    Informations forums :
    Inscription : Février 2004
    Messages : 94
    Points : 71
    Points
    71
    Par défaut
    ouep, puis moi ça fonctionne toujours pas :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    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

  12. #12
    Membre chevronné
    Avatar de ska_root
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2005
    Messages
    1 203
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 54
    Localisation : France

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

    Informations forums :
    Inscription : Août 2005
    Messages : 1 203
    Points : 1 839
    Points
    1 839
    Par défaut
    et ça ?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    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 />";
    }

  13. #13
    Membre régulier Avatar de micatmidog
    Profil pro
    Inscrit en
    Février 2004
    Messages
    94
    Détails du profil
    Informations personnelles :
    Âge : 33
    Localisation : France, Loiret (Centre)

    Informations forums :
    Inscription : Février 2004
    Messages : 94
    Points : 71
    Points
    71
    Par défaut
    Loooooool, merci beaucoup

  14. #14
    Membre régulier Avatar de micatmidog
    Profil pro
    Inscrit en
    Février 2004
    Messages
    94
    Détails du profil
    Informations personnelles :
    Âge : 33
    Localisation : France, Loiret (Centre)

    Informations forums :
    Inscription : Février 2004
    Messages : 94
    Points : 71
    Points
    71
    Par défaut
    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 : Sélectionner tout - Visualiser dans une fenêtre à part
    #<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.

Discussions similaires

  1. [RegEx] Récupérer tous les liens d'une certaine classe CSS
    Par Lost In Translation dans le forum Langage
    Réponses: 17
    Dernier message: 02/07/2009, 16h54
  2. Récupérer tous les liens d'une page html
    Par lapras123 dans le forum C
    Réponses: 28
    Dernier message: 08/08/2006, 11h30
  3. [RegEx] récupérer tous les liens d'une page
    Par italiasky dans le forum Langage
    Réponses: 15
    Dernier message: 08/04/2006, 18h55
  4. [TWebBrowser] Comment trouver tous les liens dans une page ?
    Par xenos dans le forum Composants VCL
    Réponses: 1
    Dernier message: 15/01/2006, 23h36

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo