Extracteur de liens - pb de regex

Signaler
Messages postés
329
Date d'inscription
samedi 4 janvier 2003
Statut
Membre
Dernière intervention
29 mars 2015
-
Messages postés
373
Date d'inscription
samedi 9 juillet 2005
Statut
Membre
Dernière intervention
11 août 2008
-
    Saluté...
Je bosse sur un système de moteur de recherche en ce moemtnet j'essaye d'optimiser tout ça avec des regex... bon l'idée est de pouvoir récupérer tous les liens d'une page depuis son code source ...
le problème est qu'il existe pluiseurs types de liens
ceux commencant
par http
par ./
par ../
par dossier/
par /dossier/

ou ceux étant simplement un nom de fichier
genre [index.php accueil]

ensuite on a les variables passées en get à prendre en compte ...donc tout ce qui siut le nom de fichier et qui commence par un ?

ok ...deja tout ça c'est pas mal ... mais bien sur il faut éviter de prendre les javascript tout en récupérant les liens qui peuvent y être
genre la dedans

[javascript:window.open('pagepopup.php','newsletter_exemple', 'status= yes,resizable=yes,scrollbars=yes,width=610,height=500'); void(0); Titres du jour ] : Du lundi au vendredi, les titres de l'actualité développés sur Le Monde.fr.

il faut récupérer pagepopup.php

bon ...j'ai bossé sur une regex qui est pas mal mais qui ne fonctionne pas encore au top :(
j'aurai besoin d'un coup de main pour la paufiner ... pour mes tests j'utilise le code source de la page "lemonde.fr" qui comporte plein de types de liens ou ue page de tests à moi...

voici ma regex
// recuperation de la source
$fichier = fopen($_GET['url'], 'r', false);
$src = '';
while ($str=fread($fichier, 16))
{
  $src .= $str;
}
fclose($fichier);

 preg_match_all('%(("|\')(http|./|../|/|[a-z0-9]+/)(.+?)(\.html|\.php|\.php3|\.php4|\.php5|\.htm|\/|\.asp)("|\'))|(("|\')([a-z0-9])+(\.html|\.php|\.php3|\.php4|\.php5|\.htm|\/|\.asp)(\?)(.+?)+("|\'))%im', $fichier, $lnk2, PREG_OFFSET_CAPTURE);
  echo '<textarea rows="20" cols="50" style="width:700px;">';
 print_r($lnk2);
 echo '</textarea>';

bon je suis pas un pro des regex mais j'y travaille ;)

ma regex me sort pour l'instant des liens mais avec trop d'options
genre

Array
(
    [0] => Array
        (
            [0] => Array
                (
                    [0] => "/web/recherche_resultats/1,13-0,1-0,0.html"
                    [1] => 4393
                )

            [1] => Array
                (
                    [0] => "/web/inscription_newsletter/1,27-0,1-0,0.html"
                    [1] => 6121
                )

            [2] => Array
                (
                    [0] => "http://www.lemonde.fr/web/sequence/0,2-3208,1-0,0.html"
                    [1] => 6944
                )

            [3] => Array
                (
                    [0] => "http://medias.lemonde.fr/mmpub/img/tit/nav-une.gif"  alt="Home" border="0" height="27"></td><td id="m_ann_1129">[http://www.lemonde.fr/web/sequence/0,2-3208,1-0,0.html 7111
                )

            [4] => Array
                (
                    [0] => "http://medias.lemonde.fr/mmpub/img/tit/nav-act.gif"  alt="Actualités" border="0" height="27">]</td><td id="m_ann_1130"> 7409
                )

etc etc...
d'ou le pb... j'aimerai récupérer juste les liens :(

à vot bon coeur !
mercii !
@+

13 réponses

Messages postés
329
Date d'inscription
samedi 4 janvier 2003
Statut
Membre
Dernière intervention
29 mars 2015
3
    au passage j'ai l'impression que le pb vient du fait que ce petit bout de code   (.+?)  accepte les espace et ne devrai pas ...
Messages postés
2483
Date d'inscription
jeudi 30 novembre 2006
Statut
Membre
Dernière intervention
14 janvier 2011
18
Salut,

Rendre des URLs cliquables
Postée le 20-08-2000


$chaine = eregi_replace("([[:alnum:]]+)://([^[:space:]]*)([[:alnum:]#?/&=])",
"\\1://\\2\\3",$chaine);


Rend cliquable toutes les chaînes du type http://..., ftp://..., mailto://..., etc, contenues dans un texte.



Source : http://www.phpinfo.net/page/archives/regex/

Ca devrait t'aider à t'inspirer pour ton expression régulière, non ?
Messages postés
329
Date d'inscription
samedi 4 janvier 2003
Statut
Membre
Dernière intervention
29 mars 2015
3
    saluté.
il me semble que eregi ne fonctionne pas sur la même base des expressions regulière que preg_match_all
en revanche l'expression qie je cherche pourrait se traduire comme ça

commence par
  " ou '




http
ou
./
ou
../
ou
un nom de dossier suivi de slash
continue avec
une chaine de caractère quelconque mais pas d'espace
continue avec
un point suivi d'une extension parmis htm, html, php, php3, php4, php5, asp (à compléter...)
suivi éventuellement par un ?
suivi par une chaine de caractère sans espaces
termine par "ou ' (obligatoirement le même qu'au debut)

en gros avec ça on doit pouvoir exreaire tous les liens ... reste à le formaliser ... même ceux contenus dans les javascript ...
je pense que ce qui cloche dans ma regex (le rincipal pb) est que

(.+?)
signifie toute chaine de caractère ... alors que je voudrai avoir lettres plus chiffres plus _ plus -  uniquement
ce qui devrai se traduire par
[a-z0-9-_]* mais quand je rentre ça ça ne marhce pas ... j'obtient un gros vide en sortie...

j'espère qu'un calé en regex pourra m'aiguiller ..
@++
Messages postés
373
Date d'inscription
samedi 9 juillet 2005
Statut
Membre
Dernière intervention
11 août 2008

Salut,
Essayes ceci :
<?php
$fp = fopen($_GET['url'], 'r', FALSE);
if ($fp !== FALSE) {
    $temp = '';
    while (!feof($fp)) $temp .= fgets($fp, 4096);
    fclose($fp);

    preg_match_all('``sim', $temp, $templink);
   
    $i = -1;
    $link = array();
    while (isset($templink[1][++$i])) {
        if (substr($templink[1][$i], 0, 7) !== 'http://') {
            if (substr($templink[1][$i], 0, 1) === '/') $link[] = $_GET['url'].substr($templink[1][$i], 1);
            else $link[] = $_GET['url'].$templink[1][$i];
        }
        else $link[] = $templink[1][$i];
    }
   
    print_r($link);
}
?>
Perso j'ai essayé avec $_GET['url'] = 'http://www.php.net/'.

For every choice, a consequence (Fable)
Messages postés
329
Date d'inscription
samedi 4 janvier 2003
Statut
Membre
Dernière intervention
29 mars 2015
3
    re salut
j'ai testé avec lemonde.fr et il reste des javascript qui passent à travers ...
puis le script ne gère pas tous les cas de figure ... par ex un lien qui commence par un nom de dossier suivi de slash
ou l'extraction d'une url contenue dans cette balise
[javascript:window.open('./dossier/pagepopup.php','newsletter_exemple',
'status=yes,resizable=yes,scrollbars=yes,width=610,height=500');
void(0); Titres
du jour]
je pense qu'on peut y arriver avec juste une regex bien pensée ... du moment que la syntaxe du lien est correcte c'est forcément possible de la détecter ...
Je continuerai de chercher demain de toutes façons mais je pense que j'ai besoin d'aide sur ce coup là ;)
j'ai cherché sur le web bien sur mais je n'ai trouvé que des regex basiques ne prenant pas en compte tout les styles de liens expliqués ci avant ...
ya un challenge là :) lol ^^
bon allé faut dormir à un moment donné !
@++ et merci pour ton script en tout cas !
Messages postés
329
Date d'inscription
samedi 4 janvier 2003
Statut
Membre
Dernière intervention
29 mars 2015
3
    yep ...
bon ben j'ai finalement trouvé la regex ultime d'extraction de liens ...

 $p = '(("|\')([a-z0-9-_]*|(https?\://|\./|\.\./|/?[a-z0-9-_]*/)[-A-Z0-9+&@#/=?_|!:,.;\%]*)(\.)(php[2-5]?|x?html?|aspx?){1}(\?[-A-Z0-9+&@#/=~_|!:,.;\%]*)?("|\'))';
 
   preg_match_all('%'.$p.'%i', $src, $lnk2);
  echo '<textarea rows="20" cols="50" style="width:700px;">';
 print_r($lnk2);
 echo '</textarea>';
 echo count($lnk2[0]);
 

@+
Messages postés
2483
Date d'inscription
jeudi 30 novembre 2006
Statut
Membre
Dernière intervention
14 janvier 2011
18
Si je puis me permettre... Le seul handicap de ton expression régulière, c'est qu'elle cherche spécifiquement des pages.
Et t'es pas à l'abri qu'un lien soit de la forme :
http://www.monsite.com/mapage.bidule

Si je dis à mon serveur que les extensions .bidule doivent être interprétés par telle ou telle application (php, jsp, asp, python, shell,...) ton extracteur ne les trouvera pas. Et c'est ballot...
Messages postés
373
Date d'inscription
samedi 9 juillet 2005
Statut
Membre
Dernière intervention
11 août 2008

Woua avec une expression régulière comme çà ton serveur doit bien galerer lol
<?php
$fp = fopen($_GET['url'], 'r', FALSE);
if ($fp !== FALSE) {
    $temp = '';
    while (!feof($fp)) $temp .= fgets($fp, 4096);
    fclose($fp);

    preg_match_all('``sim', $temp, $templink);
   
    $i = -1;
    $link = array();
    while (isset($templink[1][++$i])) {
        if (substr($templink[1][$i], 0, 7) === 'http://' OR substr($templink[1][$i], 0, 8) === 'https://') $link[] = $templink[1][$i];
        else{
            $explode = explode('#', $templink[1][$i]);
            $explode = explode('?', $explode[0]);
            $type1 = substr($explode[0], -3);
            $type2 = substr($explode[0], -4);            if ($type1 'asp' OR $type1 'htm' OR $type1 === 'php' OR $type2 === 'aspx' OR $type2 === 'xhtml' OR $type2 === 'php3' OR $type2 === 'php4' OR $type2 === 'php5') {
                if (substr($templink[1][$i], 0, 1) === '/') $link[] = $_GET['url'].substr($templink[1][$i], 1);
                elseif (substr($templink[1][$i], 0, 2) === './')  $link[] = $_GET['url'].substr($templink[1][$i], 2);
            }
        }
    }
    print_r($link);
}
?>

For every choice, a consequence (Fable)
Messages postés
2483
Date d'inscription
jeudi 30 novembre 2006
Statut
Membre
Dernière intervention
14 janvier 2011
18
MDR

Je suis pas sûr qu'une seule Expression Régulière (surtout une regex posix) soit moins performante qu'une série de 3 à 8 substr() et de je ne sias pas combien d'explode(), sans compter tous les tests et boucles...

Je demande à voir... Qui fait un benchmark ?
Messages postés
373
Date d'inscription
samedi 9 juillet 2005
Statut
Membre
Dernière intervention
11 août 2008

Je ne sais pas si mon code est plus rapide mais en tout cas il est plus modifiable...

For every choice, a consequence (Fable)
Messages postés
329
Date d'inscription
samedi 4 janvier 2003
Statut
Membre
Dernière intervention
29 mars 2015
3
    saluté :)
je vois avec enthousiasme que le sujet à intéréssé du monde ...
j'ai pas testé de benchmark mais je pense aussi que la regex est plus rapide ...

pour extraire les liens du type
http://www.monsite.com/mapage.bidule
ou les liens réécrits pour de l'url rewriting j'ai utilisé une autre regex un peu plus permissive (quoique) ...

puis un petit array_unique(arraymerge($tab1,$tab2)); et hop ...que les liens uniques ;)
ça marche bien ...
si ça vous intéresse de tester je vous envoie demaine une page de test avec tous les types d'url possibles et imaginables à extraire :)
plus de mauvaises syntaxes à éviter :)

pour infos deux bonnes pages à tester pour avoir des liens différents sont scoopeo.com et lemonde.fr
le code source que je vous envoie demain est aussi sympathique ;)
Voili voilo ;)
@++
Messages postés
329
Date d'inscription
samedi 4 janvier 2003
Statut
Membre
Dernière intervention
29 mars 2015
3
    pour ceux qui voudraient tester un peu voici un exemple de code html avec plein de types de liens

  <head>
    <meta http-equiv= "content-type" content="text/html" charset="iso-8859-1" />
    <LINK REL="SHORTCUT ICON" href="http://www.cogestar.fr/images/cogestar.ico">
    <meta name="verify-v1" content="3+Cder878frfLI+zclivbHtKTFv6aKKnwpB5a8L+dg4=" />
    <meta name="description" content="cogestar propose des logiciels de gestion électronique de documents, des scanners de documents, du matériel de micrographie et du matériel d'impression.">
    <meta name="keywords" content="ged, geide, gestion electronique de documents, gestion electronique documentaire, gestion documentaire, archivage, ingenierie documentaire, logiciel ged, documents, scanner, micrographie, microfilmage, microforme, microfiches, microfilms, consommables informatiques, consommables bureautiques, materiel informatique, materiel  bureautique, ocr, lecteur, reproducteur, numeriseur, numerisation, indexation, capture, acquisition, dematerialisation, com, cold, lad, solution documentaire, duplication, personnalisation, solution ged, solutions ged, editique, edition numerique, impression numerique, reprographie, traçage, traceur, plans, imagerie, filaire, plastification, contre collage, façonnage, multifonctions, progiciel, logiciel, facility management, cd, dvd,">
    <meta name="subject" content="solutions materielles et logicielles de ged">
    <meta name="author" content="cogestar">
    <meta name="copyright" content="© cogestar 2007">

    <meta name="robots" content="all">
    <meta name="location" content="france, france">
    <meta http-equiv="content-script-type" content="text/javascript">
    <meta http-equiv="content-style-type" content="text/ccs">
    <meta http-equiv="content-language" content="fr">
    <link href="css/styles.css" rel="stylesheet" type="text/css" media="all" />
    <title>
      Cogestar, Gestion électronique de documents, logiciel GED GEIDE, scanner de production ged
    </title>
  </head>
<head><title>Scoopeo - La une</title>
<META NAME="KEYWORDS" CONTENT="news,scoop,billet,post,rss,nouvelle,nouvelles,flash,billet,journal,journalisme,digglike,digg-like,click,paris,bruxelles,marseille,lyon,scoops,chaud,apple,ipod,france,belgique,suisse,canada,technologie,gadget,gsm,gazette,blog,blogs,digg,dugg,shoutwire,delicious,flickr,aggrégateur,aggrégation,blogosphère,web 2.0,la une,billet,podcast,digg.com,youtube,flickr,pirlouit,goemaere,emerge,web3,">
<link href="/stylesheets/scoopeo.css?1176201596" media="screen" rel="Stylesheet" type="text/css" /><link href="/stylesheets/clicker.css?1162971637" media="screen" rel="Stylesheet" type="text/css" /><script src="/javascripts/prototype.js?1159464975" type="text/javascript"></script>
<meta name="copyright" content="(c) Copyright 2005-2007 Scoopeo">
<link REL="shortcut icon" HREF="/favicon.ico" TYPE="image/x-icon">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"><script>if (location.hostname "scoopeo.com") {location.href location.href.replace("scoopeo.com", "www.scoopeo.com");}</script>
<link rel="alternate" type="application/rss+xml" title="Scoopeo" href="http://rss.scoopeo.com/"/>

</head>
/presidentielles2007/la-loi-fillon-ne-suffisent-pas-a-tenir-jusquen-2020Présidentielles 2007
[./presidentielles2007 Présidentielles 2007]
Voir la suite

[toto.php1?osCsid=13854354 toto]  <- mauvais lien
[toto.xml toto]
[toto.css toto]
[toto.jpg toto]
[toto.gif toto]
toto
toto

[dossier/toto.xml'osCsid=13854354 toto]

[javascript:window.open('/presidentielles2007/la-loi-fillon-ne-suffisent-pas-a-tenir-jusquen-2020','newsletter_exemple', 'status=yes,resizable=yes,scrollbars=yes,width=610,height=500'); void(0); Titres du jour ] : Du lundi au vendredi, les titres de l'actualit&eacute; d&eacute;velopp&eacute;s sur Le Monde.fr.

[javascript:window.open('http://www.lemonde.fr/web/newsletter_exemple/0,30-0,62-0@60-5@45-2,0.html','newsletter_exemple', 'status =yes,resizable= yes,scrollbars=yes,width=610,height=500'); void(0); Titres du jour ] : Du lundi au vendredi, les titres de l'actualit&eacute; d&eacute;velopp&eacute;s sur Le Monde.fr.

[javascript:window.open('dossier/newsletter_exemple/0,30-0,62-0@60-5@45-2,0.html','newsletter_exemple', 'status =yes,resizable= yes,scrollbars=yes,width=610,height=500'); void(0); Titres du jour ] : Du lundi au vendredi, les titres de l'actualit&eacute; d&eacute;velopp&eacute;s sur Le Monde.fr.

[javascript:window.open('pagepopup.php','newsletter_exemple', 'status =yes,resizable= yes,scrollbars=yes,width=610,height=500'); void(0); Titres du jour ] : Du lundi au vendredi, les titres de l'actualit&eacute; d&eacute;velopp&eacute;s sur Le Monde.fr.

=13854354&maman=123 mamn123
tat456
https://site.com/toto.php3?osCsid=13854354&maman=123&phpsessid=5deg654dtg687dr68g4toto
[toto.htm toto]
[toto.asp toto]
[toto.php3 toto]
[toto.php4 toto]
[toto.php5 toto]
[toto.aspx toto]

[toto.xhtml toto]

toto
toto
toto
toto
toto
toto
[dossier/toto.php5 toto]
[./dossier/toto.php4 toto]

[toto.php?osCsid=13854354 toto]
[toto.php?osCsid=13854354&maman=123 mamn123]
[toto.php?osCsid=13854354&maman=123&tat=456 tat456]
[toto.php?osCsid=13854354&maman=123&phpsessid=5deg654dtg687dr68g4

]toto
[toto.php4?osCsid=13854354&maman=123 mamn123]
[toto.php5?osCsid=13854354&maman=123&tat=456 tat456]
[toto.php6?osCsid=13854354&maman=123&phpsessid=5deg654dtg687dr68g4
]toto
[toto.php?dthdth=13854354 toto]

[dossier/toto.php3?osCsid=13854354 toto]
mamn123
tat456
https://site.com/toto.php?osCsid=13854354&maman=123&phpsessid=5deg654dtg687dr68g4toto

phpsessid
[?osCsid=13854354&maman=123&phpsessid=5deg654dtg687dr68g4 aaa]

/ ... , yo ~#{[|`\^@]} &é"'   (-è_çà    )= salut toi !
document    documents documents   je  tu il   nous vous ils
mericredi    meri    emerider mer mer documentaire documentaire

lien avec ./  [./pagepointslash.php pslh]

lien avec ../  [../pagepointpointslash.php pslh]

lien avec truc/pahe.php  [dossier/pagesh.php pslh]

lien avec trucmaj/pahe.php  [DOSSIER/pagesh.php pslh]

lien avec /dgx/pahe.php  pslh

++
Messages postés
373
Date d'inscription
samedi 9 juillet 2005
Statut
Membre
Dernière intervention
11 août 2008

Je viens de tester et je vois que ma méthode est plus rapide
(Les expressions régulières c'est beau mais en vouloir faire trop avec n'est pas forcement bon ...)
De plusmon code contient un boucle de 3 à 8 "substr" et de temps en temps 2 "explode" mais il ne faut pas oublier qu'il "nettoye" l'URL pour pouvoir être plus facilement utilisées.

Voilà le code qui m'a permis de tester (pas le temps de mettre des couleurs lol) :
"<?php
$fp = fopen($_GET['url'], 'r', FALSE);
if ($fp !== FALSE) {
 $temp = '';
 while (!feof($fp)) $temp .= fgets($fp, 4096);
 fclose($fp);




 // Test Bench pour l'expression régulière.
 $time = microtime(true);
 preg_match_all('%(("|\')([a-z0-9-_]*|(https?\://|\./|\.\./|/?[a-z0-9-_]*/)[-A-Z0-9+&@#/=?_|!:,.;\%]*)(\.)(php[2-5]?|x?html?|aspx?){1}(\?[-A-Z0-9+&@#/=~_|!:,.;\%]*)?("|\'))%i', $temp, $link);
 echo 'Temps de la méthode avec "REGEX POSIX" : ',microtime(true)-$time,"
\n";
 
 // Test Bench pour la méthode "substr".
 $time = microtime(true);
 preg_match_all('``sim', $temp, $templink);
 $i = -1;
 $link = array();
 while (isset($templink[1][++$i])) {
  if (substr($templink[1][$i], 0, 7) === 'http://' OR substr($templink[1][$i], 0, 8) === 'https://') $link[] = $templink[1][$i];
  elseif (substr($templink[1][$i], 0, 1) === '?') $link[] = $_GET['url'].$templink[1][$i];
  else{
   $explode = explode('#', $templink[1][$i]);
   $explode = explode('?', $explode[0]);
   $type1 = substr($explode[0], -3);
   $type2 = substr($explode[0], -4);   if ($type1 'asp' OR $type1 'htm' OR $type1 === 'php' OR $type2 === 'aspx' OR $type2 === 'xhtml' OR $type2 === 'php3' OR $type2 === 'php4' OR $type2 === 'php5') {
    if (substr($templink[1][$i], 0, 1) === '/') $link[] = $_GET['url'].substr($templink[1][$i], 1);
    elseif (substr($templink[1][$i], 0, 2) === './')  $link[] = $_GET['url'].substr($templink[1][$i], 2);
   }
  }
 }
 echo 'Temps de la méthode avec "substr" : ',microtime(true)-$time,"
\n";
}
?>"







For every choice, a consequence (Fable)