web-dev-qa-db-fra.com

phantomjs peut-il fonctionner avec node.js?

Je voudrais utiliser phantomjs dans mon script node.js. il y a un phantomjs-node library .. mais malheureusement, l'auteur a utilisé ce code script script bizarre pour expliquer ce qu'il fait:

phantom = require 'phantom'

phantom.create (ph) ->
  ph.createPage (page) ->
    page.open "http://www.google.com", (status) ->
      console.log "opened google? ", status
      page.evaluate (-> document.title), (result) ->
        console.log 'Page title is ' + result
        ph.exit()

maintenant, si j’utilisais phantomjs directement avec javascript, cela ressemblerait à quelque chose comme this :

var page = require('webpage').create();
page.open(url, function (status) {
    var title = page.evaluate(function () {
        return document.title;
    });
    console.log('Page title is ' + title);
});

donc, fondamentalement, j'essaie d'écrire l'équivalent du premier fragment de code ci-dessus en javascript normal (en lisant le script café documentation .. c'est ce que j'ai fait:

// file name: phantomTest.js

var phantom = require('phantom');

phantom.create(function(ph) {
    ph.createPage(function(page) {
        page.open('http://www.google.com', function(status) {
            console.log('opened google?', status);
            var title = page.evaluate(function() {
                return document.title;
            });
            console.log('page title is ' + title);              
        });
    });
    ph.exit();
});

malheureusement ça ne marche pas! Si je cours

node phantomTest.js

sur le shell, rien ne se passe .. rien ne retourne et le processus ne s'arrête pas .. des idées?

mettre à jour:

Je viens de lire ceci dans le phantomjs faq

Q: Pourquoi PhantomJS n’est-il pas écrit en tant que module Node.js?

A: La réponse courte: "Personne ne peut servir deux maîtres."

Une explication plus longue est la suivante.

À l'heure actuelle, il est techniquement très difficile de le faire.

Chaque module Node.js est essentiellement "un esclave" du noyau de Node.js, c'est-à-dire "le maître". Dans son état actuel, PhantomJS (et son inclus WebKit) doit avoir le contrôle total (de manière synchrone) sur tout: boucle d'événement, pile réseau et exécution de JavaScript.

Si l’intention est juste d’utiliser PhantomJS à partir d’un script fonctionnant dans Node.js, une telle "liaison lâche" peut être obtenue avec lancer un processus PhantomJS et interagir avec lui.

mmm .. cela pourrait-il avoir quelque chose à voir avec cela? mais alors toute cette bibliothèque n'aurait aucun sens!

mise à jour 2:

J'ai trouvé ce code dans le web qui fait la même chose:

var phantom = require('phantom');
phantom.create(function(ph) {
  return ph.createPage(function(page) {
    return page.open("http://www.google.com", function(status) {
      console.log("opened google? ", status);
      return page.evaluate((function() {
        return document.title;
      }), function(result) {
        console.log('Page title is ' + result);
        return ph.exit();
      });
    });
  });
});

malheureusement ça ne marche pas non plus .. même résultat!

28
abbood

phantomjs-node n'est pas un paquet officiel npm pris en charge par phantomjs. Au lieu de cela, il implémente un "pont astucieusement astucieux" entre noeud et fantôme en créant un serveur Web utilisant des websockets pour servir de canal IPC entre noeud et fantôme. Je n'invente rien :

Nous communiquons donc avec PhantomJS en créant une instance d'ExpressJS, en ouvrant Phantom dans un sous-processus et en la pointant sur une page Web spéciale transformant les messages socket.io en appels alert (). Ces appels alert () sont captés par Phantom et le tour est joué!

Donc, je ne serais pas surpris si phantomjs-node fonctionne, ne fonctionne pas, échoue en silence ou de façon spectaculaire. Je ne m'attendrais pas non plus que l'auteur de phantomjs-node soit en mesure de dépanner phantomjs-node.

La réponse à votre question initiale est la réponse de la FAQ phantomjs: Non. Le fantôme et le noeud ont des différences irréconciliables. Tous deux s'attendent à avoir un contrôle complet sur les fonctionnalités fondamentales de bas niveau, telles que la boucle d'événements, la pile réseau et l'exécution JS, de sorte qu'ils ne puissent pas coopérer dans le même processus.

39
Rein Henrichs

Je suis maintenant le nouveau responsable du paquet phantom-node. Il n'utilise plus coffeescript. Vous pouvez faire quelque chose comme

var phantom = require('phantom');

phantom.create().then(function(ph) {
  ph.createPage().then(function(page) {
    page.open('https://stackoverflow.com/').then(function(status) {
      console.log(status);
      page.property('content').then(function(content) {
        console.log(content);
        page.close();
        ph.exit();
      });
    });
  });
});

La nouvelle version est beaucoup plus rapide et résiliente. De plus, il n'utilise plus de websockets. 

9
Amir Raminfar

Vous pouvez également essayer phridge a try. Votre exemple aurait été écrit comme ceci:

var phantom;

// spawn a new PhantomJS process
phridge.spawn()
    .then(function (ph) {
        phantom = ph;
        return phantom.openPage("http://www.google.com");
    })
    .then(function (page) {
        return page.run(function () {
            // this function runs inside PhantomJS with this bound to a webpage instance
            return this.title;
        });
    })
    .then(function (title) {
        console.log('Page title is ' + title);
        // terminates the process cleanly
        phantom.dispose();
    });
9
Johannes Ewald

Vous pouvez simplement abandonner PhantomJS comme je l’ai fait parce que c’était trop pénible avec ces enveloppes qui ne fonctionnaient pas bien et aller avec Zombie.js , qui est également très populaire.

1
PositiveGuy

changez votre code pour ceci, et cela fonctionnera:

 var phantom = require('phantom');
 phantom.create(function(ph) {
   ph.createPage(function(page) {
     page.open("http://www.google.com", function(status) {
       console.log("opened google? ", status);
       page.evaluate((function() {
         return document.title;
       }), function(result) {
         console.log('Page title is ' + result);
         ph.exit();
       });
     });
   });
 });
1
Billy Shea

Semble que cela fonctionne ..

var phantom = require('phantom');

phantom.create().then(function(ph) {
  ph.createPage().then(function(page) {
    page.open('https://stackoverflow.com/').then(function(status) {
      console.log(status);
      page.property('content').then(function(content) {
        console.log(content);
        page.close();
        ph.exit();
      });
    });
  });
});

Mais j'essaie de générer une page html avec un fichier de script externe. Il est impossible d'injecter un fichier de script. J'ai essayé comme suivre. Le rappel ne revient pas de la ligne page.injectJs('./jQuery.min.js',function() { 

var phantom = require('phantom');

    phantom.create().then(function(ph) {
      ph.createPage().then(function(page) {
        page.injectJs('./jQuery.min.js', function() {
          page.property('content').then(function(content) {
            console.log(content);
            page.close();
            ph.exit();
          });
        });
      });
    });
1
Vishnu

J'ai rencontré les mêmes problèmes que vous et apparemment, il existe un problème connu avec phantomjs-node et des versions plus récentes de nodejs. On dirait que cela a cessé de fonctionner quelque part autour du noeud 0.9.3, selon les commentaires de ce numéro. Donc, jusqu'à ce que cela soit résolu, vous devez soit rétrograder nodejs, soit essayer un module différent, comme node-phantom , ou simplement utiliser exec/spawn.

0
NilsH