Ajax, scraping et ressources du navigateur ?

Ajax, scraping et ressources du navigateur ? - PHP - Programmation

Marsh Posté le 23-01-2013 à 22:14:54    

Bonjour à tous,
 
je me tourne vers vous car je suis coincé sur un petit projet perso. Je m'explique :
 
j'essaie de mettre en place le scrap automatique d'un site. Je parcours pour cela différentes page classées par date, chacune d'entre elle possédant une liste de lien (les pages que je souhaite justement récupéré en local sur ma machine).
 
J'ai donc développé avec mootools une fonction récursive pour parcourir les pages contenant les liens. La voici :  
 

Code :
  1. function callActionGetCoursesJour(date) {       
  2.     new Request.JSON({
  3.         url:'http://localhost/xxxxxxx/getCoursesJour?date='+date,
  4.         onSuccess: function(returnJSON){         
  5.             var pDate=new Element('p');
  6.             pDate.set('html', '<br /><br />'+date);
  7.             pDate.inject($('retour'));
  8.             Object.each(returnJSON.allCourses, function(value, key){
  9.                 new Request({
  10.                     onSuccess: function(){         
  11.                         var pCourse=new Element('p');
  12.                         pCourse.set('html', value);
  13.                         pCourse.inject($('retour'));
  14.                     }
  15.                 }).send();
  16.             });
  17.             setTimeout(function(){ callActionGetCoursesJour(returnJSON.demain); },Number.random(1000000000,100000000000));
  18.         }
  19.     }).send();
  20. }


 
Et voici la fonction php qui crawl la page demandé et récupère les différents liens (ceux dont je vais récupérer la page ultérieurement)
 

Code :
  1. public function processGetCoursesJour() {
  2.         $date=_request('date');
  3.         $return=array(); // tableau que je retourne en json
  4.         // je récupère un tableau listant les différentes courses du jour
  5.         $allCourses=array();
  6.         // je récupère le code html de la page listant les courses du jour
  7.         $url="http://xxxxxxxxxx?date=".$date;
  8.         $doc = new DOMDocument();
  9.         @$doc->loadHTMLFile($url);
  10.         $xpath=new DomXPath($doc);
  11.         // je récupère les divs contenant les liens vers les courses
  12.         $allInfosCourse=$xpath->query('//*[contains(@class,"infosCourse" )]');
  13.  
  14.         // pour chacun de ces div
  15.         foreach ($allInfosCourse as $uneInfoCourse) {
  16.             // je récupère les différentes lignes de la table contenant les différentes courses
  17.             $allLignes=$uneInfoCourse->getElementsByTagName('table')->item(0)->getElementsByTagName('tr');
  18.  
  19.             for ($i=1;$i<$allLignes->length;$i++) {
  20.                 // je récupère pour chaque ligne (sauf la 1ère) toutes les colonnes
  21.                 $allColonnes=$allLignes->item($i)->getElementsByTagName('td');
  22.  
  23.                 $urlFicheCourse=$allColonnes->item(1)->getElementsByTagName('a')->item(0)->getattribute('href');
  24.                 $allCourses[]=$urlFicheCourse;
  25.             }
  26.         }
  27.         $return['allCourses']=$allCourses;
  28.  
  29.         // puis j'affiche la date suivante pour la renvoyer et la récuperer via ajax
  30.         $dateExplode=explode('-',$date);
  31.         $demain = date("Y-m-d",mktime(0,0,0,$dateExplode[1],$dateExplode[2]-1,$dateExplode[0]));
  32.         $return['demain']=$demain;
  33.  
  34.         echo json_encode($return);
  35.  
  36.         return _arNone ();
  37.     }


 
Tout fonctionne correctement, je crawl bien la page 2013-01-13, puis 2013-01-12... je récupère bien les liens contenu à chaque fois dans la page... mais au bout de quelques minutes, mon navigateur stoppe tout. Les requêtes ne se font plus.
 
Quelqu'un aurait une idée ? Ou peut-être une autre manière de faire ? Je suis ouvert à toute suggestion ou discution.
 
Merci d'avance à tous !!


Message édité par pusse le 25-01-2013 à 11:04:16
Reply

Marsh Posté le 23-01-2013 à 22:14:54   

Reply

Marsh Posté le 23-01-2013 à 23:39:31    

Ca ressemble à un problème de fuite mémoire, trop de variables déclarées et jamais supprimées, occasionnant une augmentation excessive de la mémoire utilisée, jusqu'au crash.
 
Sachant que tu ne mets aucune condition d'arret à ton setTimeout.
 
Une question, pourquoi ne pas tout faire en PHP ?


Message édité par CyberDenix le 23-01-2013 à 23:41:09

---------------
Directeur Technique (CTO)
Reply

Marsh Posté le 24-01-2013 à 09:26:27    

J'ai bien pensé effectivement à tout faire en php mais je souhaitais mettre en place un système de temporisation afin "de ne pas trop attirer l'attention" dans les logs du site "cible".
 
Bien que je pense également utilisé un sytème de proxy (d'ailleurs as-tu un avis la dessus ?), je voulais doublé cette "protection" d'une temporisation aléatoire.
 
En réfléchissant cette nuit j'en était quand même arrivé à une conclusion semblable à la tienne. Je voulais tout simplement rechargé la page à chaque appel d'une nouvelle url ou quelque chose du genre. Qu'en penses-tu ?
 
Sachant qu'il s'agit d'un projet perso, j'aimerais m'amuser un peu à optimiser mon code (et son temps d'éexecution) au maximum

Reply

Marsh Posté le 24-01-2013 à 22:15:28    

Faire du JS et de l'AJAX ne t'apportera pas vraiment l'anonymat, puisque tu feras de toutes façons des requêtes GET à destination du serveur.
 
A mon avis ca reste plus simple à faire en php.
 
Tu peux très bien faire de la temporisation aléatoire en php avec une combinaison de mt_rand() et de usleep().
 
Et pour la mémoire, PHP c'est mieux, pas besoin de navigateur, le garbage collector est intégré en PHP 5.3+, et si besoin tu relances un process php en killant l'actuel (ce que je fais pour de longs processus d'importations qui durent plusieurs heures et qui ont malgré tout quelques memory leaks... donc à la longue vaut mieux killer).
 
Je te conseille de faire un CURL de la page : tu pourras gérer les codes HTTP, suivre les redirections automatiquement, setter un fake user-agent, un cookie si besoin, ...etc. Bref, véritablement tromper les logs serveur.
 
http://php.net/manual/fr/book.curl.php
http://php.net/manual/fr/function.curl-setopt.php
 
A propos des systèmes de proxy en PHP, je manque d'expérience à ce niveau, mais je pense que c'est probablement une excellente idée.
 
Enfin, si tu veux curler like a boss, pense au multi processing : un master et n slaves. Ca te permet de paralléliser tes requêtes. J'ai déjà testé et ça dépote grave niveau perf.
 
PS : déplace le sujet dans la section PHP.


Message édité par CyberDenix le 24-01-2013 à 22:16:10

---------------
Directeur Technique (CTO)
Reply

Marsh Posté le 25-01-2013 à 11:02:51    

En fait, je souhaitais passer par de l'Ajax pour mettre en place un système de temporisation. Je sais pas pourquoi mais j'étais persuadé qu'en php cela posait problème.  :pt1cable: Je dois avouer que ça m'arrange de faire ça en php.
 
Concernant Curl, je ne connais pas mais j'ai déjà repéré un script tout prêt permettant de gérer le mutli-processing avec gestion de différents proxy, différents user-agent....
De plus, le fait de pouvoir gérer les codes HTTP est vraiment intéressant puisque le scrap à pour but de récupérer des données pour faire des statistiques et que si je "loupe" certaines pages, tout risque d'être faussé (alors qu'avec une bonne gestion des retours HTTP normalement pas de problèmes).
 
Par contre j'ai 1/2 questions en plus si tu peux :

  • je n'ai pas bien compris ton passage concernant le fait de killer le process en php ? est-ce relatif au fait de rafraîchir la page de temps en temps ? Ou est-ce une autre manipulation avec une fonction php ? Et quel est le but ?
  • J'ai moi même très peu d'expérience en proxy mais le fait d'un utiliser un entraîne-t-il à ton avis une "inutilité" de changer le user-agent (si l'IP est différente, on se moque un peu que le user-agent soit toujours le même non ?)


En tout cas merci déjà pour tous ces compléments.
 
Et je déplace le tout en PHP :)

Reply

Marsh Posté le 25-01-2013 à 11:07:08    

Je verrais certes du php mais dont l'exécution serait lancée par un cron. En effet, avec usleep, y'aura toujours le pb de timeout du script php. Ou alors, faut que le résultat du script php affiche une page web avec un javascript qui va relancer au bout d'un certain temps le script php.


---------------
Astres, outil de help-desk GPL : http://sourceforge.net/projects/astres, ICARE, gestion de conf : http://sourceforge.net/projects/icare, Outil Planeta Calandreta : https://framalibre.org/content/planeta-calandreta
Reply

Marsh Posté le 25-01-2013 à 11:08:33    

Et si je supprime le timeout ? Sachant que je tourne en local sous Wamp, je fais les réglages un peu comme je veux non ?

Reply

Marsh Posté le 25-01-2013 à 14:45:41    

Comme le dit si bien rufo, il est préférable de lancer php en ligne de commande pour éviter le timeout de php et/ou du navigateur.
 
php monscript.php mon_paramètre_1 mon_paramètre_2 ...
 
Je suggérais plus haut un programme (process) master qui spawne des programmes esclaves, chaque esclave étant chargé de pomper une url.
Tu gardes une liste des affectations de travail en base de donnée (ou tout autre espace mémoire, genre Memcached), avec un statut (pas affecté, en cours, terminé).
 
Pour lancer des lignes de commande, voir les fonctions shell_exec (sous unix) ou system (sous windows)
 
foreach ($urls as $url) {
  shell_exec('php slave.php '.$url.' ...'); // avec les paramètres pour lancer en mode non bloquant (arrière plan)
}


Message édité par CyberDenix le 25-01-2013 à 18:08:15
Reply

Marsh Posté le 25-01-2013 à 21:28:39    

Ok je pense avoir compris le principe à part peut-être l'histoire "des affectations de travail en base de donné ou memcached". Je vous remercie tous les 2 pour vos réponses et si vous n'y voyais pas d'inconvénients, je pense revenir ici avec le code fait histoire d'avoir votre avis.
 
Merci pour tous messieurs et passez un bon week-end


Message édité par pusse le 25-01-2013 à 21:30:50
Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed