2012-09-23 8 views
11

Ich kratze eine Facebook-Seite mit dem PhantomJS Knoten-Modul (https://github.com/sgentle/phantomjs-node), aber wenn ich versuche, die Seite auszuwerten, wird nicht ausgewertet, die Funktion, die ich an sie übergeben. Es wird in einem eigenständigen Skript ausgeführt und mit dem Node-Interpreter ausgeführt. Derselbe Code in einer Express.js-App funktioniert nicht.Phantomjs führt keine Funktion in page.evaluate Funktion

Das ist mein Code

facebookScraper.prototype.scrapeFeed = function (url, cb) { 
    f = ':scrapeFeed:'; 

    var evaluator = function (s) { 
     var posts = []; 

     for (var i = 0; i < FEED_ITEMS; i++) { 
      log.info(__filename+f+' iterating step ' + i); 
      log.info(__filename+f+util.inspect(document, false, null)); 
     } 

     return { 
      news: posts 
     }; 
    } 

    phantom.create(function (ph) { 
     ph.createPage(function (page) { 
      log.fine(__filename+f+' opening url ' + url); 
      page.open(url, function (status) { 
       log.fine(__filename+f+' opened site? ' + status); 
       setTimeout(function() { 
        page.evaluate(evaluator, function (result) { 
         log.info(__filename+f+'Scraped feed: ' + util.inspect(result, false, null)); 
         cb(result, ph); 
        }); 
       }, 5000); 
      }); 
     }); 
    }); 
}; 

Der Ausgang ich erhalte, ist: wie Sie also

{"level":"fine","message":"PATH/fb_regular.js:scrapeFeed: opening url <URL> ","timestamp":"2012-09-23T18:35:10.151Z"} 
{"level":"fine","message":"PATH/fb_regular.js:scrapeFeed: opened site? success","timestamp":"2012-09-23T18:35:12.682Z"} 
{"level":"info","message":"PATH/fb_regular.js:scrapeFeed: Scraped feed: null","timestamp":"2012-09-23T18:35:12.687Z"} 

finden, ruft es die Phantomcallback-Funktion (zweiter Parameter in der Funktion auswerten) mit einem Null Argument, aber es führt nicht den ersten Parameter (meine Evaluator-Funktion, die Iteration Schritt X druckt).

Wer weiß, was das Problem ist?

Antwort

23

Ich bin nicht sicher, welche Version von PhantomJS Sie verwenden, aber wie für die Dokumentation der Versionen 1.6+ Protokollierung in ausgewerteten Skript protokolliert das Ergebnis in der enthaltenen Seite. Es wird sich nicht in Ihrer Konsole anmelden. Zu erhalten, die Sie auf den Seiten onConsoleMessage Ereignisprotokollierung würde binden:

page.onConsoleMessage = function (msg) { console.log(msg); }; 

Was das Ergebnis nicht zur Verfügung stehen: Die page.evaluate Funktionsargumente nimmt wie so - erste ist eine Funktion ausgeführt werden und die Rest wird als Eingabe für diese Funktion übergeben. Das Ergebnis wird direkt zurückgegeben:

var title = page.evaluate(function (s) { 
    return document.querySelector(s).innerText; 
}, 'title'); 
console.log(title); 
9

evaluate im Sandbox-Modus ausgeführt werden, was bedeutet, dass keine der Variablen in der haltigen Umgebung definiert ist, einschließlich cb oder sogar das phantom Objekt oder alle Funktionen, die Sie definiert haben .

Sie können Informationen explizit in die Sandbox als zusätzliche Argumente zu evaluate tunneln.

page.evaluate(function(cb){...}, cb); 
4

PhantomJS‘page.evaluate() Funktion ist die Tür zum DOM-Kontext (Seite Kontext). Der Zugriff auf das DOM ist nur über diese Funktion möglich. Da die Funktion sandboxed ist, können Sie keine außerhalb davon definierten Variablen verwenden, die explizit übergeben werden müssen. Es gibt Einschränkungen, was in und out obwohl (docs) übergeben werden kann:

Hinweis: Die Argumente und der Rückgabewert die evaluate Funktion muss ein einfaches primitives Objekt sein. Die Faustregel: Wenn es über JSON serialisiert werden kann, ist es in Ordnung.

Verschlüsse, Funktionen, DOM-Knoten usw. nicht funktionieren!

phantomjs-node ist eine Brücke zwischen PhantomJS und Knoten.js und als solche hat eine etwas andere API als PhantomJS selbst. Funktionen, die in PhantomJS synchron sind, geben nichts in phantomjs-node zurück, sondern nehmen einen Callback zurück, bei dem das Ergebnis übergeben wird. Der Callback wird im äußeren Kontext ausgeführt und ist nicht sandboxed.

page.evaluate(function(arg1, arg2){ 
    // use arg1 and arg2 in the page 
    // return `result` 
}, function(result){ 
    // use `result` in the node context 
}, "some arg1", "another arg"); 
+1

Die neueste Version der PhantomJS-Knoten Brücke soll ein Versprechen zurückkehren statt sich auf eine Callback-Funktion verlassen. –

+0

Das hat mir wirklich geholfen, danke –

+0

Nun, ich verliere etwa 6 Stunden einige Dinge im 'evaluate' -Funktion zu testen ... Wenn es eine andere Funktion gibt, oder irgendetwas nicht-primitiver Typ, wird es nicht einmal die Ausführung der Funktion starten ... Eine wichtige Sache. ** Vergessen Sie nicht, die Dokumentation zu lesen ** –

2

Die für mich eine Seite zu bewerten arbeiten folgende:

Die Argumente können auf diese Weise weitergegeben werden

page.evaluate(function(s) { 
    return document.querySelector(s) 
}, 'body').then(res => { 
    console.log(res) 
})