2016-11-03 20 views
8

Próbuję użyć Caspers by uzyskać listę linków ze strony, następnie otworzyć każdy z tych linków i dodać do obiektu tablicy konkretny typ danych z tych strony.Casperjs iteruje listę linków za pomocą casper.each

Problem, który mam, dotyczy pętli wykonywanej na każdym z elementów listy.

Najpierw otrzymuję listOfLinks z oryginalnej strony. Ta część działa i używając długości mogę sprawdzić, czy ta lista jest wypełniona.

Jednakże, używając poniższej instrukcji pętli this.each, żadna z instrukcji konsoli nigdy się nie wyświetla i wydaje się, że casperjs pomija ten blok.

Zastępując this.each standardową pętlą, wykonanie przechodzi tylko przez pierwsze łącze, ponieważ instrukcja "Tworzenie nowej tablicy w obiekcie dla x.html" pojawia się raz, a następnie kod przestaje działać. Używanie IIFE nie zmienia tego.

Edit: w trybie debugowania gadatliwym dodaje się dzieje:

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

więc z jakiegoś powodu URL, który jest przekazywany do funkcji thenOpen zostanie zmieniony na puste ...

czuję się jak jest coś takiego w asynchronicznej naturze Casperjsa, którego tu nie rozumiem i byłbym wdzięczny za wskazanie przykładu.

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

Dodany inna odpowiedź, że należy właściwie rozwiązać wszystkie problemy z skryptu. – Vaviloff

Odpowiedz

3

Zdecydowałem się użyć naszego własnego Stackoverflow.com jako witryny demonstracyjnej do uruchomienia skryptu. W kodzie poprawiłem kilka drobnych rzeczy, a wynikiem jest to ćwiczenie w uzyskiwaniu komentarzy z pytań o nagrodę PhantomJS.

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

Co się zmieniło: page.evaluate teraz powraca prostych tablic, które są potrzebne do casper.each(), aby prawidłowo iteracyjne. Atrybuty href są pobierane natychmiast w page.evaluate.Również w tym korekta:

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

Wynik biegu skryptu jest

{"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

Dzięki, Twój skrypt działa sprawnie na Stackoverflow i kilku innych stronach internetowych. Jednak nadal nie działa na stronie internetowej, dla której ją zaplanowałem, co może być spowodowane tym, że jest szczególnie skomplikowana w przypadku dużej ilości AJAX i innych skryptów. W końcu myślę, że problem był związany z konkretną witryną. Bardzo dziękuję za pomoc, ale jest to bardzo przydatny skrypt. – Laurence

3

Wracasz węzły DOM w funkcji evaluate(), co jest niedozwolone. Zamiast tego możesz zwrócić rzeczywiste adresy URL.

Uwaga: Argumenty i wartość zwracana z funkcją oceny musi być prosty prymitywny przedmiot. Zasada: jeśli może być serializowana przez JSON, to jest w porządku.

Zamknięcia, funkcje, węzły DOM itp. Nie będą działać!

referencyjny: PhantomJS#evaluate

+0

Dzięki, wyglądało to naprawdę obiecująco. Wprowadziłem zmiany, ale to nie rozwiązało problemu. I właśnie uświadomiłem sobie, że w trybie debugowania następują: 'Tworzenie nowego obiektu tablicy dla https://example.com [debug] [phantom] Żądanie nawigacji: url = about: blank, type = Other, willNavigate = true, isMainFrame = true', a następnie Casperjs po cichu zawiedzie. Wygląda na to, że poprawny link, który zostanie przekazany do thenOpen, zostanie zmieniony na: blank ... – Laurence

1

Jeśli rozumiem Twojego problemu poprawnie rozwiązać, dać przedmioty [] zasięg globalny. W twoim kodzie zrobiłbym to:

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

Mam nadzieję, że to pomoże.

Powiązane problemy