2017-09-22 10 views
0

J'ai écrit un script CasperJS qui fonctionne très bien, sauf qu'il faut un (très très) long moment pour gratter les pages.Meilleures pratiques pour exécuter plus rapidement un script CasperJS qui supprime des milliers de pages

En un mot, voici le code pseudo:

  1. mes fonctions à la ferraille les éléments
  2. mon casper.start() pour démarrer la navigation et connectez-vous
  3. casper.then() où je boucle à travers un tableau et stocker mes liens
  4. casper.thenOpen() pour ouvrir chaque lien et appeler mes fonctions à la ferraille.

Cela fonctionne parfaitement (et assez rapidement) pour mettre au rebut un tas de liens. Mais quand il s'agit de milliers (maintenant je cours le script avec un tableau de liens 100K), le temps d'exécution est sans fin: les premiers liens 10K ont été mis au rebut en 3h54m10s et les 10K suivants en 2h18m27s.

Je peux expliquer un peu la différence entre les deux lots 10K: le premier comprend le stockage en boucle & de la matrice avec les liaisons 100K. À partir de ce point, les scripts n'ouvrent que des pages pour les supprimer. Cependant, j'ai remarqué que le tableau était prêt à partir après environ 30 minutes, donc cela n'explique pas exactement l'écart de temps.

J'ai placé mon casper.thenOpen() dans la boucle for en espérant qu'après chaque nouveau lien construit et stocké dans le tableau, la mise au rebut aura lieu. Maintenant, je suis sûr que j'ai échoué mais cela changera-t-il quelque chose en termes de performance? C'est la seule piste que j'ai à l'esprit en ce moment et je serais très reconnaissant si quelqu'un est disposé à partager ses meilleures pratiques pour réduire de manière significative la durée de l'exécution du script (ne devrait pas être difficile!) .

EDIT # 1

Voici mon code ci-dessous:

var casper = require('casper').create(); 
var fs = require('fs'); 

// This array maintains a list of links to each HOL profile 

// Example of a valid URL: https://myurl.com/list/74832 
var root = 'https://myurl.com/list/'; 
var end = 0; 
var limit = 100000; 
var scrapedRows = []; 

// Returns the selector element property if the selector exists but otherwise returns defaultValue 

function querySelectorGet(selector, property, defaultValue) { 
    var item = document.querySelector(selector); 
    item = item ? item[property] : defaultValue; 
    return item; 
} 

// Scrapping function 
function scrapDetails(querySelectorGet) { 

    var info1 = querySelectorGet("div.classA h1", 'innerHTML', 'N/A').trim() 
    var info2 = querySelectorGet("a.classB span", 'innerHTML', 'N/A').trim() 
    var info3 = querySelectorGet("a.classC span", 'innerHTML', 'N/A').trim() 

    //For scrapping different texts of the same kind (i.e: comments from users) 
    var commentsTags = document.querySelectorAll('div.classComments'); 
    var comments = Array.prototype.map.call(commentsTags, function(e) { 
    return e.innerText; 
    }) 

// Return all the rest of the information as a JSON string 
    return { 
    info1: info1, 
    info2: info2, 
    info3: info3, 

    // There is no fixed number of comments & answers so we join them with a semicolon 
    comments : comments.join(' ; ') 
    }; 
} 

casper.start('http://myurl.com/login', function() { 
this.sendKeys('#username', 'username', {keepFocus: true}); 
this.sendKeys('#password', 'password', {keepFocus: true}); 
this.sendKeys('#password', casper.page.event.key.Enter, {keepFocus: true}); 

    // Logged In 
    this.wait(3000,function(){ 

    //Verify connexion by printing welcome page's title 
    this.echo('Opened main site titled: ' + this.getTitle()); 
    }); 
}); 

casper.then(function() { 

    //Quick summary 
    this.echo('# of links : ' + limit); 
    this.echo('scraping links ...') 

    for (var i = 0; i < limit; i++) { 

    // Building the urls to visit 
    var link = root + end; 

     // Visiting pages... 
     casper.thenOpen(link).then(function() { 
      // We pass the querySelectorGet method to use it within the webpage context 
      var row = this.evaluate(scrapDetails, querySelectorGet); 
      scrapedRows.push(row); 

      // Stats display 
      this.echo('Scraped row ' + scrapedRows.length + ' of ' + limit); 
     }); 

    end++; 
    } 

}); 

casper.then(function() { 
    fs.write('infos.json', JSON.stringify(scrapedRows), 'w') 
}); 

casper.run(function() { 
    casper.exit(); 
}); 

Répondre

0

A ce stade, j'ai probablement plus de questions que de réponses, mais nous allons essayer.

Y a-t-il une raison particulière pour laquelle vous utilisez CasperJS et non Curl par exemple? Je peux comprendre le besoin de CasperJS si vous voulez gratter un site qui utilise Javascript par exemple. Ou vous voulez prendre des captures d'écran. Sinon, j'utiliserais probablement Curl avec un langage de script tel que PHP ou Python et tirer parti des fonctions d'analyse DOM intégrées. Et vous pouvez bien sûr utiliser des outils de raclage dédiés comme Scrapy. Il y a quelques outils disponibles. Puis la question «évidente»: avez-vous vraiment besoin d'avoir des tableaux aussi grands que? Ce que vous essayez de réaliser n'est pas clair, je suppose que vous voulez stocker les liens extraits dans une base de données ou quelque chose. N'est-il pas possible de diviser le processus en petites séries?

Une chose qui devrait aider est à allouer de la mémoire suffisante en déclarant un tableau de taille fixe à savoir: var theArray = new Array(1000);

Redimensionner le tableau est constamment lié à causer des problèmes de performance. Chaque fois que de nouveaux éléments sont ajoutés au tableau, des opérations coûteuses d'allocation de mémoire doivent avoir lieu en arrière-plan et sont répétées au cours de l'exécution de la boucle.

Puisque vous ne montrez pas de code, nous ne pouvons pas suggérer des améliorations significatives, juste des généralités.

+0

Merci pour votre réponse @Anonyme! Je n'ai pas considéré Curl comme je savais seulement que PhantomJS, CasperJS et SlimmerJS étaient les langages les plus populaires pour la mise au rebut sur le web. En fonction de votre réponse, je pense que Curl pourrait faire l'affaire, donc je vais définitivement essayer. J'ai utilisé import.io pour gratter mais je ne peux pas payer leurs plans alors j'ai décidé de m'enseigner moi-même à CasperJS. J'ai besoin de gratter des centaines de milliers de pages Web pour qu'à un certain point, j'ai besoin de grands tableaux pour stocker les URL. Je n'ai pas alloué de mémoire donc ici encore, je vais essayer aussi et comparer les résultats. J'ai mis à jour ma question avec mon code;) – DFATPUNK