2016-11-03 4 views
8

Ich versuche Casperjs zu verwenden, um eine Liste der Links von einer Seite zu erhalten, öffnen Sie dann jeden dieser Links, und fügen Sie zu einem Array-Objekt einen bestimmten Datentyp von diesen Seiten.Casperjs Iterieren über eine Liste von Links mit casper.each

Das Problem, das ich habe, ist mit der Schleife, die über jedes der Listenelemente ausgeführt wird.

Zuerst bekomme ich eine listOfLinks von der ursprünglichen Seite. Dieser Teil funktioniert und mit Länge kann ich überprüfen, dass diese Liste aufgefüllt ist.

Mit der loop-Anweisung this.each (siehe unten) wird jedoch keine der Konsolenanweisungen angezeigt und casperjs scheint diesen Block zu überspringen.

Ersetzen this.each durch einen Standard für die Schleife, die Ausführung wird nur teilweise durch den ersten Link, wie die Anweisung "Creating new Array in Objekt für X.html" erscheint einmal und dann der Code beendet die Ausführung. Die Verwendung eines IIFE ändert dies nicht.

Edit: im ausführlichen Debug-Modus geschieht Folgendes:

Creating new array object for https://example.com 
[debug] [phantom] Navigation requested: url=about:blank, type=Other, willNavigate=true, isMainFrame=true 

Also aus irgendeinem Grund die URL, die in die thenOpen Funktion geändert wird, um leer übergeben wird ...

Ich fühle mich wie Es gibt etwas an Casperjs asynchronem Wesen, das ich hier nicht verstehe, und wäre dankbar, auf ein funktionierendes Beispiel hingewiesen zu werden.

casper.then(function() { 

    var date = Date.now(); 
    console.log(date); 

    var object = {}; 
    object[date] = {}; // new object for date 

    var listOfLinks = this.evaluate(function(){ 
    console.log("getting links"); 
    return document.getElementsByClassName('importantLink'); 
    }); 

    console.log(listOfLinks.length); 

    this.each(listOfLinks, function(self, link) { 

    var eachPageHref = link.href; 

    console.log("Creating new array in object for " + eachPageHref); 

    object[date][eachPageHref] = []; // array for page to store names 

    self.thenOpen(eachPageHref, function() { 

     var listOfItems = this.evaluate(function() { 
     var items = []; 
     // Perform DOM manipulation to get items 
     return items; 
     }); 
    }); 

    object[date][eachPageHref] = items; 

    }); 
    console.log(JSON.stringify(object)); 

}); 
+1

Added eine andere Antwort, die alle Probleme mit Ihrem Skript eigentlich lösen sollte. – Vaviloff

Antwort

3

Ich habe beschlossen, unsere eigene Stackoverflow.com als Demo-Website zu verwenden, um Ihr Skript gegen zu betreiben. Es gab ein paar kleinere Dinge, die ich in Ihrem Code korrigiert habe, und das Ergebnis ist diese Übung, um Kommentare von PhantomJS Bounty-Fragen zu erhalten.

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

casper 
.start() 
.open('http://stackoverflow.com/questions/tagged/phantomjs?sort=featured&pageSize=30') 
.then(function() { 

    var date = Date.now(), object = {}; 
    object[date] = {}; 

    var listOfLinks = this.evaluate(function(){ 

     // Getting links to other pages to scrape, this will be 
     // a primitive array that will be easily returned from page.evaluate 
     var links = [].map.call(document.querySelectorAll("#questions .question-hyperlink"), function(link) { 
      return link.href; 
     });  
     return links; 
    }); 

    // Now to iterate over that array of links 
    this.each(listOfLinks, function(self, eachPageHref) { 

     object[date][eachPageHref] = []; // array for page to store names 

     self.thenOpen(eachPageHref, function() { 

      // Getting comments from each page, also as an array 
      var listOfItems = this.evaluate(function() { 
       var items = [].map.call(document.getElementsByClassName("comment-text"), function(comment) { 
        return comment.innerText; 
       });  
       return items; 
      }); 
      object[date][eachPageHref] = listOfItems; 
     }); 
    }); 

    // After each links has been scraped, output the resulting object 
    this.then(function(){ 
     console.log(JSON.stringify(object)); 
    }); 
}) 

casper.run(); 

Was geändert wird: page.evaluate kehrt nun einfachen Arrays, die für casper.each benötigt werden() iterieren richtig. href Attribute werden sofort in page.evaluate extrahiert.Auch diese Korrektur:

object[date][eachPageHref] = listOfItems; // previously assigned items which were undefined in this scope 

Das Ergebnis der Skriptausführung ist

{"1478596579898":{"http://stackoverflow.com/questions/40410927/phantomjs-from-node-on-windows":["en.wikipedia.org/wiki/File_URI_scheme – Igor 2 days ago\n","@Igor is there something in particular you see wrong, or are you suggesting the phantom module has an incorrect URI? – Danny Buonocore 2 days ago\n","Probably windows security issue not allowing to run an unsigned program. – Vaviloff yesterday\n"],"http://stackoverflow.com/questions/40412726/casperjs-iterating-over-a-list-of-links-using-casper-each":["Thanks, this looked really promising. I made the changes but it didn't solve the problem. And I just realised that in debug mode the following happens: Creating new array object for https://example.com [debug] [phantom] Navigation requested: url=about:blank, type=Other, willNavigate=true, isMainFrame=true and then Casperjs silently fails. It seems that the correct link that gets passed into thenOpen gets changed to about:blank... – cyc665 yesterday\n"]}} 
+1

Danke, ich habe dein Skript gut auf Stackoverflow und einigen anderen Websites funktioniert. Allerdings funktioniert es immer noch nicht auf der Website, für die ich es vorgesehen habe, was vielleicht daran liegt, dass es mit vielen AJAX und anderen Skripten besonders komplex ist. Ich denke, das Problem war website-spezifisch. Vielen Dank für Ihre Hilfe, dies ist ein sehr nützliches Skript. – Laurence

3

Sie kehren DOM-Knoten in der evaluate() Funktion, was nicht erlaubt ist. Sie können stattdessen die tatsächlichen URLs zurückgeben.

Hinweis: Die Argumente und der Rückgabewert der Funktion auswerten 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. funktionieren nicht!

Referenz: PhantomJS#evaluate

+0

Danke, das sah wirklich vielversprechend aus. Ich habe die Änderungen vorgenommen, aber es hat das Problem nicht gelöst. Und ich habe gerade festgestellt, dass im Debug-Modus Folgendes passiert: 'Erstellen eines neuen Array-Objekts für https://example.com [debug] [Phantom] Navigation angefordert: url = about: leer, type = Other, willNavigate = true, isMainFrame = wahr 'und dann versagt Casperjs stillschweigend. Es scheint, dass der korrekte Link, der in thenOpen übergeben wird, zu ungefähr geändert wird: leer ... – Laurence

1

Wenn ich Ihr Problem richtig verstanden hat, zu lösen, gibt Artikeln [] einen globalen Rahmen. In Ihrem Code hätte ich Folgendes getan:

var items = []; 
this.each(listOfLinks, function(self, link) { 

    var eachPageHref = link.href; 

    console.log("Creating new array in object for " + eachPageHref); 

    object[date][eachPageHref] = []; // array for page to store names 

    self.thenOpen(eachPageHref, function() { 

     this.evaluate(function() { 
     // Perform DOM manipulation to get items 
     items.push(whateverThisItemIs); 
     }); 
    }); 

Ich hoffe, dies hilft.

Verwandte Themen