[RESOLU] Fonction récursive : Help

Eléphanteau du PHP | 48 Messages

06 janv. 2016, 13:47

Salut,

Je cherche à faire un genre de mini-crawler et pour cela, voici ma page :

Code : Tout sélectionner

<?php function in_multi_array($value, $array) { foreach ($array as $key => $item) { if (!is_array($item)) { if ($item == $value) return true; } else { if (in_array($value, $item)) return true; else if (in_multi_array($value, $item)) return true; } } return false; } function racine($site) { $site = explode('/', $site); if( strstr($site[2], 'www.') ) { $site = explode('www.', $site[2]); return $site[1]; } else { return $site[2]; } } function crawlcurl($url) { $ch = curl_init(); $timeout = 5; curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout); curl_setopt($ch, CURLOPT_USERAGENT, $_SERVER['HTTP_USER_AGENT']); $code_brute = curl_exec($ch); curl_close($ch); return $code_brute; } function crawl($url, &$urls, $limite) { $code_brute = crawlcurl($url); $doc = new DOMDocument(); $doc->loadHTML($code_brute); $balise_a = $doc->getElementsByTagName('a'); foreach($balise_a as $balise) { $href = $balise->getAttribute('href'); if( !in_multi_array($href, $urls) && strstr($href, racine($url)) && !strstr($href, 'pdf') ) { if( $limite >= 0 ) { $urls[] = $href; $urls[] = crawl($href, $urls, ($limite - 1)); } else { $urls[] = $href; } } $limite = ($limite - 1); } return $urls; } $liste = crawl('http://www.canardduweb.fr', $liste, 1); print_r($liste); ?>
Je voudrais qu'avec la limite de 1, le script puisse crawler a une profondeur de 1, donc récupérer toutes les URLs de l'url active.
Avec une limite de 2, le script devrait récupérer toutes les URLs de la page active, puis vérifier toutes les URLs de ces urls et une fois de plus... Etc.

Le problème est que je récupère uniquement les liens du premier de la liste uniquement...

Bref mon code bloque quelque part et après plusieurs jours dessus, je ne trouve pas encore comment faire fonctionner ce code...

Merci de votre aide.

Mammouth du PHP | 881 Messages

06 janv. 2016, 14:40

Tu as un appel en boucle

Code : Tout sélectionner

function crawl($url, &$urls, $limite) { ... foreach($balise_a as $balise) { $href = $balise->getAttribute('href'); if( !in_multi_array($href, $urls) && strstr($href, racine($url)) && !strstr($href, 'pdf') ) { if( $limite >= 0 ) { $urls[] = $href; $urls[] = crawl($href, $urls, ($limite - 1)); // ICI la fonction crawl appelle la fonction crawl ...
Soyez artisans de paix

Eléphanteau du PHP | 48 Messages

06 janv. 2016, 15:40

En fait, c'est le principe de la fonction récursive mais je l'ai mal appliquée je pense, j'ai besoin d'aide pour savoir comment modifier ce code.

Mammouth du PHP | 1967 Messages

06 janv. 2016, 17:42

Je n'arrive pas à suivre ton code, tu as plus d'une fonction récursive, et je pense que la profondeur dans ton tableau $urls est inutile

Mais pour avoir déjà fait un robot de parcours de site,
J'ai suivi une tout autre voix.
à partir d'une adresse, je récupère tous les href, si il sont dans mon tableau, j'ajoute une entrée "parent" avec l'url courante sinon j'ajoute dans mon tableau avec l'entrée "parent". Je parcours mon tableau avec une boucle while et une variable $i qui s'incrémente à chaque boucle. Mais comme j'augmente mon tableau d'url au fur et à mesure, je continue de le parcourir (ma condition while est empty($tableau[$i]))
Et si tu veux y adjoindre un contrôle de profondeur, il suffit de l'ajouter dans ton tableau (avec un fonction min(), car tu dois savoir sa profondeur minimum dans ta hiérarchie) et une condition d'exclusion en début de while

La structure de mon tableau d'url

Code : Tout sélectionner

$array = array( array( 'url' => 'MonUrl', 'parent' => 'UrlParent' 'depth' => min('profondeur') ) )
Spols
pour les fan de rubik's cube ou pour les curieux ==> le portail francophone du rubik's cube

ynx
Mammouth du PHP | 586 Messages

06 janv. 2016, 17:57

Salut,

Le troisième paramètre $limite de la fonction récursive crawl(), qui correspond à la profondeur du crawl, doit donc être décrémenté à chaque appel de cette fonction (ce que tu fais bien avec la ligne $urls[] = crawl($href, $urls, ($limite - 1));).
Par contre tu décrémentes également cette variable à chaque fois qu'un lien est récupéré (à la fin de la boucle foreach($balise_a), ce qui ne me semble pas correct puisque en parcourant tous les liens d'une page tu es toujours au même niveau de profondeur.

Sauf erreur (pas testé donc c'est pas impossible), il suffit que tu supprimes cette décrémentation dans la boucle pour faire fonctionner correctement ta fonction récursive.

Bonne journée,
Modifié en dernier par ynx le 06 janv. 2016, 17:57, modifié 1 fois.

Eléphanteau du PHP | 48 Messages

06 janv. 2016, 17:57

Salut,

merci pour ces informations et ces idées. Mais j'ai un besoin bien précis à ce sujet, c'est la première partie seulement et j'ai du coup besoin d'une fonction avec laquelle je peux définir la profondeur que je souhaite crawler à partir de l'URL que je donne.

Eléphanteau du PHP | 48 Messages

06 janv. 2016, 18:02

Salut,

Le troisième paramètre $limite de la fonction récursive crawl(), qui correspond à la profondeur du crawl, doit donc être décrémenté à chaque appel de cette fonction (ce que tu fais bien avec la ligne $urls[] = crawl($href, $urls, ($limite - 1));).
Par contre tu décrémentes également cette variable à chaque fois qu'un lien est récupéré (à la fin de la boucle foreach($balise_a), ce qui ne me semble pas correct puisque en parcourant tous les liens d'une page tu es toujours au même niveau de profondeur.

Sauf erreur (pas testé donc c'est pas impossible), il suffit que tu supprimes cette décrémentation dans la boucle pour faire fonctionner correctement ta fonction récursive.

Bonne journée,
Voici ce que ça donne si je supprime la décrémentation à la fin de la boucle, sur un petit site :

Code : Tout sélectionner

Array ( [0] => http://www.jscourses.com [1] => http://www.jscourses.com/ [2] => http://www.jscourses.com/services [3] => http://www.jscourses.com/tarifs [4] => http://www.jscourses.com/reserver [5] => http://www.jscourses.com/gare-de-lyon [6] => http://www.jscourses.com/gare-de-lyon/taxi-moto-gare-de-lyon [7] => Array ( [0] => http://www.jscourses.com [1] => http://www.jscourses.com/ [2] => http://www.jscourses.com/services [3] => http://www.jscourses.com/tarifs [4] => http://www.jscourses.com/reserver [5] => http://www.jscourses.com/gare-de-lyon [6] => http://www.jscourses.com/gare-de-lyon/taxi-moto-gare-de-lyon ) [8] => Array ( [0] => http://www.jscourses.com [1] => http://www.jscourses.com/ [2] => http://www.jscourses.com/services [3] => http://www.jscourses.com/tarifs [4] => http://www.jscourses.com/reserver [5] => http://www.jscourses.com/gare-de-lyon [6] => http://www.jscourses.com/gare-de-lyon/taxi-moto-gare-de-lyon [7] => Array ( [0] => http://www.jscourses.com [1] => http://www.jscourses.com/ [2] => http://www.jscourses.com/services [3] => http://www.jscourses.com/tarifs [4] => http://www.jscourses.com/reserver [5] => http://www.jscourses.com/gare-de-lyon [6] => http://www.jscourses.com/gare-de-lyon/taxi-moto-gare-de-lyon ) ) )
Je pense que c'est pas encore ça... Mais on s'en rapproche peut-être 8-|

Mammouth du PHP | 881 Messages

06 janv. 2016, 21:16

Bonjour à tous,

je vois que CoeurBis progresse bien dans son projet.
Une petite présentation du code nous permettrait de savoir où c'en est. Je vois qu'il y eut beaucoup de progrès depuis.

Le résultat affiché ci-haut n'est-il pas ce que vous souhaitez?
Soyez artisans de paix

Eléphanteau du PHP | 48 Messages

06 janv. 2016, 21:28

Bonjour à tous,

je vois que CoeurBis progresse bien dans son projet.
Une petite présentation du code nous permettrait de savoir où c'en est. Je vois qu'il y eut beaucoup de progrès depuis.

Le résultat affiché ci-haut n'est-il pas ce que vous souhaitez?
Salut Patriboom,

J'ai mis tout au début, le code complet de la page, qui est actuellement en phase de tests. Une fois réussi, je pourrais l'adapter plus précisément. Ce code est donc indépendant actuellement.

Le résultat que je veux c'est :

Code : Tout sélectionner

Array ( [0] => page1.html [1] => Array ( [0] => page1a.html [1] => page1b.html [2] => page1c.html [3] => page1d.html [4] => page1e.html } [2] => page2.html [3] => Array ( [0] => page2a.html [1] => page2b.html [2] => page2c.html [3] => page2d.html [4] => page2e.html } [4] => page3.html [5] => Array ( [0] => page3a.html [1] => page3b.html [2] => page3c.html [3] => page3d.html [4] => page3e.html } )
Et pour une profondeur de 3 par exemple ce serait :

Code : Tout sélectionner

Array ( [0] => page1.html [1] => Array ( [0] => page1a.html [1] => Array ( [0] => page1aa.html [1] => page1ab.html [2] => page1ac.html [3] => page1ad.html [4] => page1ae.html } [2] => page1b.html [3] => Array ( [0] => page1ba.html [1] => page1bb.html [2] => page1bc.html [3] => page1bd.html [4] => page1be.html } [4] => page1c.html [5] => Array ( ...
Enfin, agencé comme ça ou même un peu différemment, mais ce sont bien ces données qu'il me faut.

Eléphanteau du PHP | 48 Messages

06 janv. 2016, 21:36

D'ailleurs, j'ai l'impression que ma fonction in_multi_array ne fonctionne pas...

Mammouth du PHP | 881 Messages

06 janv. 2016, 22:16

Si ta fonction in_multi_array n'est pas appelée, il faut que tu te questionne sur la façon de l'appeler.
Quant moi, j'ai des doutes relativement à

Code : Tout sélectionner

strstr($href, racine($url))
dans

Code : Tout sélectionner

if( !in_multi_array($href, $urls) && strstr($href, racine($url)) && !strstr($href, 'pdf') )
Est-ce qu'une URL complète peut être dans sa racine?
La logique ne nous demanderait-elle pas l'inverse (que la racine se trouve dans l'URL complète ) ?
Soyez artisans de paix

Eléphanteau du PHP | 48 Messages

06 janv. 2016, 22:19

En fait, je fais des tests sur des sites qui ont des URLs absolues, donc avec la racine complète.

Si ça marche, ensuite je pense prendre ceux sans la racine (relatifs) et ajouter le préfix afin de les crawler... Donc le problème ne vient pas de là à mon avis.

Mammouth du PHP | 881 Messages

06 janv. 2016, 23:13

N'empêche, ton test ne devrait-il pas être plutôt ainsi :

Code : Tout sélectionner

strstr(racine($url), $href)
Soyez artisans de paix

Eléphanteau du PHP | 48 Messages

07 janv. 2016, 00:28

Non, car je recherche bien si la racine du site ext présent dans l'URL en question, par exemple :

Code : Tout sélectionner

strstr('http://www.monsite.com/mapage.html', 'monsite.com');

Mammouth du PHP | 881 Messages

07 janv. 2016, 01:14

bref, as-tu vérifié si ta routine passe par ta fonction in_multi_array ? Insères-y des echo, des marqueurs qui te permettent de vérifier si la sous-routine est appelée.

Si elle n'est pas appelée, insère des echo affichant les variables qui sont vérifiées par ton if (!in_multi_array)
comme ceci:

Code : Tout sélectionner

$href = $balise->getAttribute('href'); echo 'Voici href = '.$href.'<br />'; echo 'Voici urls = '.$urls).'<br />'; echo 'Voici racine(url) = '.racine($url)).'<br />'; echo 'Voici est-ce un pdf = '. ((strstr($href, 'pdf') ) ? 'oui' : 'non').'<br />'; if( !in_multi_array($href, $urls) && strstr($href, racine($url)) && !strstr($href, 'pdf') )
Soyez artisans de paix