66 votes

Comment gérer un "pool" d'instances PhantomJS

Je suis la planification d'un webservice pour ma propre utilisation en interne qui prend un argument, une URL et retourne html représentant l' résolu DOM à partir de cette URL. Par résolu, je veux dire que le webservice d'abord obtenir la page à l'URL, puis utilisez PhantomJS pour "restituer" la page, et ensuite de retour à l'résultant de la source après tout, DHTML, AJAX appels, etc sont exécutées. Cependant le lancement de fantôme sur une demande de base (dont je fais maintenant) est manière trop lente. Je préférerais avoir un pool de PhantomJS cas, avec une toujours disponible pour servir le dernier appel à mon webservice.

A aucun travail sur ce genre de chose avant? Je préfère la base de ce webservice sur le travail des autres que d'écrire un gestionnaire de pool / serveur proxy http pour moi-même à partir de zéro.

Plus de Contexte: j'ai listé les 2 projets similaires que j'ai vu jusqu'à présent ci-dessous et pourquoi j'ai évité de chacun, ce qui entraîne dans cette question à propos de la gestion d'un pool de PhantomJS instances de la place.

jsdom - de ce que j'ai vu il a une grande fonctionnalité pour l'exécution de scripts sur une page, mais il ne tente pas de reproduire le comportement du navigateur, donc, si je devais l'utiliser comme un objectif général de "DOM " resolver" il y aurait finissent par être beaucoup de codage supplémentaire pour gérer tous les types de bords des cas, l'appel, etc. Le premier exemple que j'ai vu était manuellement l'appel de la onload() fonction de la balise body pour une application de test j'ai configuré l'aide d'un noeud. Il semblait que le début d'un profond trou de lapin.

Sélénium - Il a juste soo beaucoup plus de pièces mobiles, de sorte que la configuration d'un pool de gérer longue durée de vie instances de navigateur en sera que plus compliqué que d'utiliser PhantomJS. Je n'ai pas besoin de c'est l'enregistrement de la macro / script avantages. Je veux juste un webservice qui est aussi performant à obtenir une page web et de le résoudre DOM comme si j'étais la navigation vers cette URL dans un navigateur (ou même plus vite, si je peux le faire ignorer les images, etc.)

62voto

JasonS Points 1312

J'ai installé une PhantomJs Service de Cloud computing, et il a à peu près fait ce que vous demandez. Il m'a fallu environ 5 semaines de travail à mettre en œuvre.

Le plus grand problème que vous rencontrerez dans l'est connu que le problème de fuites de mémoire dans PhantomJs. La façon dont j'ai travaillé autour de ce est le cycle de mon cas tous les 50 appels.

Le deuxième plus grand problème que vous rencontrerez dans l'est par le traitement de la page est très cpu et de la mémoire intensive, donc vous aurez seulement être en mesure d'exécuter 4 cas par UC.

Le troisième plus grand problème que vous rencontrerez dans l'est que PhantomJs est assez loufoque avec page-finition des événements et des redirections. Vous serez informé que votre page est rendu terminé avant qu'il ne l'est réellement. Il y a un certain nombre de façons de composer avec cette, mais rien de "standard", malheureusement.

Le quatrième plus grand problème que vous aurez à traiter est de l'interopérabilité entre nodejs et phantomjs heureusement, il y a beaucoup de packages npm qui traitent de cette question à choisir.

Donc, je sais que je suis partial (comme je l'ai écrit la solution que je vais proposer), mais je vous suggère de vérifier PhantomJs.Cloud qui est gratuit pour une utilisation faible.

17voto

Brandon Tilley Points 49142

La bibliothèque JavaScript asynchrone fonctionne en Nœud et a un queue fonction qui est très pratique pour ce genre de chose:

queue(worker, concurrency)

Crée une file d'attente de l'objet spécifié avec le la concurrence. Les tâches ajoutées à la file d'attente va être traitées en parallèle (jusqu'à la concurrence de la limite). Si tous les travailleurs sont en cours, la tâche est en attente jusqu'à ce que l'on est disponible. Une fois qu'un travailleur a terminé une tâche, la tâche de rappel est appelée.

Certains pseudo-code:

function getSourceViaPhantomJs(url, callback) {
  var resultingHtml = someMagicPhantomJsStuff(url);
  callback(null, resultingHtml);
}

var q = async.queue(function (task, callback) {
  // delegate to a function that should call callback when it's done
  // with (err, resultingHtml) as parameters
  getSourceViaPhantomJs(task.url, callback);
}, 5); // up to 5 PhantomJS calls at a time

app.get('/some/url', function(req, res) {
  q.push({url: params['url_to_scrape']}, function (err, results) {
    res.end(results);
  });
});

Découvrez l' ensemble de la documentation pour queue dans le readme du projet.

0voto

Fred B Points 62

Si vous utilisez nodejs, vous pouvez utiliser https://github.com/sgentle/phantomjs-node , ce qui vous permettra de connecter un nombre arbitraire de processus phantomjs à votre processus NodeJS principal, d'où la possibilité d'utiliser async.js. et beaucoup de goodies de noeud.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X