2013-04-01 16 views
27

Vorrei utilizzare phantomjs nel mio script node.js. c'è una biblioteca phantomjs-node .. ma purtroppo l'autore ha usato questo codice di script caffè strano per spiegare quello che sta facendo:i phantomjs possono funzionare con node.js?

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() 

ora se dovessi usare phantomjs direttamente con javascript, sarebbe simile a 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); 
}); 

quindi fondamentalmente sto cercando di scrivere l'equivalente del primo frammento di codice di cui sopra in javascript normale (leggendo la sceneggiatura del caffè documentation .. questo è quello che ho fatto:

// 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(); 
}); 

sfortunatamente non funziona! Se corro

node phantomTest.js 

sulla shell, non succede nulla .. non ritorna nulla e il processo non si ferma .. qualche idea?

aggiornamento:

Ho appena letto questo nelle phantomjs faq:

D: Perché è PhantomJS non scritti come modulo Node.js?

A: La risposta breve: "Nessuno può servire due padroni".

Una spiegazione più lunga è la seguente.

A partire da ora, è tecnicamente molto impegnativo farlo.

Ogni modulo Node.js è essenzialmente "uno schiavo" del core di Node.js, , ad esempio "il master". Allo stato attuale, PhantomJS (e il suo WebKit incluso) deve avere il controllo completo (su una questione sincrona) su tutto : loop eventi, stack di rete e esecuzione JavaScript.

Se l'intenzione è solo di utilizzare PhantomJS destra da uno script in esecuzione all'interno Node.js, un tale "sciolto vincolante" può essere raggiunto con avviando un processo PhantomJS e interagire con esso.

mmm .. questo potrebbe avere qualcosa a che fare con esso? ma allora quella intera biblioteca non avrebbe senso!

aggiornamento 2:

Ho trovato questo codice nella web che fa la stessa cosa:

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(); 
     }); 
    }); 
    }); 
}); 

, purtroppo, che non funziona neanche .. stesso risultato!

+3

Calling qualcosa di "stupido", perché non si capisce come funziona e/o non si può fare che funziona nel tuo caso è scortese. –

+2

Inoltre, vi è https://github.com/sheebz/phantom-proxy che è più consigliato di altri bridge Node.js. Le persone hanno utilizzato il bridging di PhantomJS con Ruby, PHP, Node.js con un successo variabile. –

+3

Mi scuso per la mia forte formulazione, lo porterò fuori dalla domanda .. Daremo anche un'occhiata a 'phantom-proxy' .. alla fine della giornata il mio obiettivo è far funzionare le cose, è non sminuire lo sforzo degli altri. – abbood

risposta

38

phantomjs-node non è un pacchetto NPM supportato ufficialmente per phantomjs. Invece, implementa un "ponte nauseamente intelligente" tra nodo e fantasma creando un server web che utilizza websocket per fungere da canale IPC tra nodo e fantasma.I'm not making this up:

Così abbiamo comunicare con PhantomJS facendo girare un'istanza di ExpressJS, aprendo Phantom in un sottoprocesso, e che punta a una pagina web speciale che trasforma i messaggi socket.io in alert() chiama. Quelle chiamate di avviso() vengono rilevate da Phantom e eccoti!

Quindi io non sarei sorpreso se lavori phantomjs-nodo, non funziona, non riesce in silenzio, o fallisce in modo spettacolare. Né mi aspetterei che qualcuno oltre all'autore di phantomjs-node sia in grado di risolvere il problema del nodo fantasma.

La risposta alla domanda originale è la risposta dal faq phantomjs: No. Fantasma e nodo hanno differenze inconciliabili. Entrambi si aspettano di avere il controllo completo su funzionalità basilari di basso livello come il ciclo degli eventi, lo stack di rete e l'esecuzione di JS in modo che non possano cooperare all'interno dello stesso processo.

+5

wow è brutto! quindi la prossima domanda è: qual è il modo migliore per grattare una pagina dinamica usando jquery? – abbood

+0

@abbood Non credo sia possibile.Qual è il tuo obiettivo qui? –

+1

perché non sarebbe possibile? penso di aver trovato la mia [risposta] (https://github.com/tmpvar/jsdom/) anche se .. come sempre .. comincio prendendo il percorso incredibilmente difficile, solo per trovare una soluzione molto più semplice lol .. i ' Vi forniremo il premio per la risposta corretta .. – abbood

0

Ho riscontrato gli stessi problemi e, apparentemente, c'è un known issue con phantomjs-node e versioni più recenti di nodejs. Sembra che abbia smesso di funzionare da qualche parte attorno al nodo 0.9.3, secondo i commenti nel problema. Quindi, finché non è stato risolto, è necessario eseguire il downgrade di nodejs o provare un modulo diverso, ad esempio node-phantom o utilizzare semplicemente exec/spawn.

1

modificare il codice per questo, e lavoreranno:

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(); 
     }); 
    }); 
    }); 
}); 
9

Si potrebbe anche dare phridge una prova. Il vostro esempio sarebbe stato scritto in questo modo:

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(); 
    }); 
1

Si potrebbe semplicemente fosso PhantomJS come ho fatto perché era davvero troppo di un dolore con questi involucri non funziona bene, e andare con Zombie.js che è abbastanza popolare anche.

9

Ora sono il nuovo manutentore del pacchetto phantom-node. Non usa più il coffeescript. Puoi fare qualcosa come

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 nuova versione è molto più veloce e resiliente. Inoltre non usa più websocket.

1

sembra che questo sta lavorando ..

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(); 
     }); 
    }); 
    }); 
}); 

ma sto cercando di generare una pagina html con alcuni file di script esterno. Non è in grado di iniettare un file di script. Ho provato a seguire. La richiamata non sta tornando dalla linea 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(); 
      }); 
     }); 
     }); 
    }); 
Problemi correlati