2010-01-21 4 views
1

Je développe une application qui est, pour le dire simplement, un moteur de recherche de niche. Dans l'application, j'ai inclus une fonction crawl() qui explore un site web puis utilise la fonction collectData() pour stocker les données correctes du site dans la table "products" comme décrit dans la fonction. Les pages visitées sont stockées dans une base de donnéesFuite de mémoire CakePHP Web Crawler

Le crawler fonctionne plutôt bien, comme décrit à l'exception de deux choses: Timeout et Memory. J'ai réussi à corriger l'erreur de délai mais la mémoire reste. Je sais que l'augmentation de memory_limit ne résout pas le problème.

La fonction est exécutée en visitant "EXAMPLE.COM/products/crawl".

Une fuite de mémoire est-elle inévitable avec un robot d'indexation PHP? OU Y at-il quelque chose que je fais mal/ne pas faire.

Merci d'avance. (CODE CI-DESSOUS)

function crawl() { 

     $this->_crawl('http://www.example.com/','http://www.example.com'); 
    } 

    /*** 
    * 
    * This function finds all link in $start and collects 
    * data from them as well as recursively crawling them 
    * 
    * @ param $start, the webpage where the crawler starts 
    * 
    * @ param $domain, the domain in which to stay 
    * 
    ***/ 

    function _crawl($start, $domain) { 
     $dom = new DOMDocument(); 
     @$dom->loadHTMLFile($start); 

     $xpath = new DOMXPath($dom); 
     $hrefs = $xpath->evaluate("/html/body//a");//get all <a> elements 

     for ($i = 0; $i < $hrefs->length; $i++) { 

      $href = $hrefs->item($i); 
      $url = $href->getAttribute('href'); // get href value 
      if(!(strpos($url, 'http') !== false)) { //check for relative links 
       $url = $domain . '/' . $url; 
      } 

      if($this->Page->find('count', array('conditions' => array('Page.url' => $url))) < 1 && (strpos($url, $domain) !== false)) { // if this link has not already been crawled (exists in database) 

       $this->Page->create(); 
       $this->Page->set('url',$url); 
       $this->Page->set('indexed',date('Y-m-d H:i:s')); 
       $this->Page->save(); // add this url to database 

       $this->_collectData($url); //collect this links data 
       $this->_crawl($url, $domain); //crawl this link 
      } 
     } 
    } 

Répondre

1

Vous créez plus de deux fois plus de requêtes de base de données comme il y a des liens sur la page, je dirais que c'est là votre problème. Essayez de simplement accumuler les liens dans un tableau, faire une grosse requête par lots pour filtrer les doublons et insérer de nouveaux enregistrements avec un saveAll().


En fait, en regardant à nouveau, vous ramper récursive tous les liens aussi bien, mais sans aucune limite de profondeur ou abandonner condition. En d'autres termes, le script continuera tant qu'il y aura des liens à suivre, potentiellement infinis. Vous devriez juste traiter une page à la fois et explorer d'autres liens dans une autre instance, par exemple en utilisant un modèle de file d'attente/travailleur.

+0

Merci pour vos commentaires. Des conseils sur la mise en œuvre de cela? Le concept est relativement simple, mais je ne suis pas sûr de créer une instance distincte. Devrais-je, par exemple, appeler EXAMPLE.COM/products/crawl depuis le script pour exécuter une instance distincte? – KTastrophy

+0

Non, vous préférez travailler avec des tâches cron ou un démon. Il y a beaucoup de discussions ici sur SO pour vous aider à démarrer: http://stackoverflow.com/search?q=php+queue+worker – deceze