2016-04-19 15 views
1

Ich versuche, eine Webseite mit Nightmare zu crawlen, aber warten möchte, bis #someelem vorhanden ist, nur wenn es tatsächlich existiert. Ansonsten möchte ich, dass Nightmare weitergeht. Wie kann dies unter Verwendung .wait() getan werden?Nightmare Conditional Wait()

Ich kann .wait(ms) nicht verwenden. Die Verwendung von .wait(selector) bedeutet, dass Nightmare warten wird, bis das Element vorhanden ist, aber wenn die Seite dieses Element nie haben wird, wird Nightmare ewig warten.

Die letzte Option ist .wait(fn) zu verwenden. Und ich habe so etwas wie dies versuchte

.wait(function(cheerio) { 
      var $ = cheerio.load(document.body.outerHTML); 
      var attempt = 0; 

      function doEval() { 
       if ($('#elem').length > 0) { 
        return true; 
       } 
       else { 
        attempt++; 

        if (attempt < 10) { 
         setTimeout(doEval,2000); //This seems iffy. 
        } 
        else { 
         return true; 
        } 
       } 
      } 

      return doEval(); 
     },cheerio) 

Also, warten und erneut versuchen (bis zu einer Schwelle), und wenn das Element nicht gefunden wird, dann einfach weiter. Der Code scheint um setTimeout falsch zu sein, weil .wait im Browser-Bereich erfolgt.

Vielen Dank im Voraus!

+0

Nightmare doc sagt: Warte, bis das 'fn' auf der Seite ausgewertet wird mit' arg1, arg2, ... 'gibt 'true' zurück. Warten bedeutet also, bis "wahr" zurückgegeben wird. Ja, du hast recht, es ist nicht wahr. – user

Antwort

4

Ich glaube nicht, die cheerio Bibliothek übergeben, wie Sie es haben, wird sehr gut funktionieren. Die Argumente werden serialisiert (mehr oder weniger), um sie an den Child-Electron-Prozess zu übergeben, also wird das Übergeben einer ganzen Bibliothek wahrscheinlich nicht funktionieren.

Auf der Seite oben, der fn Teil .wait(fn) im Seitenkontext ausgeführt wird - Sie haben bedeutet vollen Zugang zum document und die Methoden, sie hat (zB querySelector). Sie können auch Zugriff auf den jQuery-Kontext der Seite haben, falls vorhanden, oder Sie könnten sogar .inject() verwenden, um sie zu injizieren, wenn nicht.

Einstellung, zur Seite, du hast Recht, soweit .wait() (und .evaluate(), was das betrifft) erwarten eine synchrone Methode, zumindest bis so etwas wie promises could be used directly in .evaluate().

Bis das verfügbar ist, könnten Sie .action() verwenden, das Verhalten zu imitieren Sie wollen:

var Nightmare = require('nightmare'); 

Nightmare.action('deferredWait', function(done) { 
    var attempt = 0; 
    var self = this; 

    function doEval() { 
    self.evaluate_now(function(selector) { 
     return (document.querySelector(selector) !== null); 
    }, function(result) { 
     if (result) { 
     done(null, true); 
     } else { 
     attempt++; 
     if (attempt < 10) { 
      setTimeout(doEval, 2000); //This seems iffy. 
     } else { 
      done(null, false); 
     } 
     } 
    }, '#elem'); 
    }; 
    doEval(); 
    return this; 
}); 

var nightmare = Nightmare(); 
nightmare.goto('http://example.com') 
    .deferredWait() 
    .then(function(result) { 
    console.log(result); 
    }); 
+0

Süß! Das funktioniert gut. Danke Ross! – user

+2

Ich denke, jetzt gibt es keine Notwendigkeit dafür, weil wir '.wait ('# elem')' verwenden können, richtig? –

0

Hier erstelle ich eine Funktion html Quellen für verschiedene Bedingungen zu bekommen, ich bin kriechen die TimeWarnerCable Seite Informationen zu erhalten über TV-, Internet- und Bundle-Pläne, damit meine Funktion einige Parameter bekommt und für jeden in verschiedenen Anrufen reagiert. Sie können die .exists() verwenden, Wähler zu überprüfen und dann mit Alptraum weiter

function getSource(url,serviceQuantity,zip){ 
    var defer=Q.defer(); 
    var Nightmare = require('nightmare'); 
    var nightmare = Nightmare({openDevTools:browserDev ,show: browserVisible,'webPreferences':{partition: 'nopersist'}}); 

    nightmare 
    .goto(url) 
    .cookies.clear() 
    .wait(2000) 
    .exists('div.messagebox-wrapper.twc-container[style="display: block;"]') 
    .then(function(noZipSet){ 
    if (noZipSet){ 
     debug('No zipcode settled down'); 
     nightmare 
     .insert('fieldset > div > input[placeholder="Enter Your ZIP Code"]',zip) 
     .type('fieldset > div > input[placeholder="Enter Your ZIP Code"]', '\u000d');//I do "Enter" because nightmare can't find the submit button 
    }else{ 
     debug('Zipcode settled down'); 
     nightmare 
     .click('div.section.newHeaderIcons > div > ul > li:nth-child(4) > div > a') 
     .wait(2000) 
     .insert('form.geoLoc > fieldset > div > input[placeholder="Update Your ZIP Code"]',zip) 
     .type('form.geoLoc > fieldset > div > input[placeholder="Update Your ZIP Code"]', '\u000d');//I do "Enter" because nightmare can't find the submit button 
    } 
    nightmare 
    .wait(8500) 
    .exists('div[style="display: block;"] > div > div > div > div > div > div > div.parsys.oof-error-content > div > div > div > div > div > div > p[style="color: #333333;"]') 
    .then(function(zipNotAvailable){ 
     if (zipNotAvailable){ 
     debug('Service not available in '+zip+' for '+serviceQuantity+' services'); 
     nightmare 
      .end() 
      .then(function(){ 
      defer.resolve(''); 
      }); 
     }else{ 
     debug('Service available on the zipcode'); 
     switch (serviceQuantity) { 
      case 1: 
       nightmare 
        .evaluate(function(){ 
        return document.querySelector('html').innerHTML; 
        }) 
        .end() 
        .then(function (result) { 
        defer.resolve(result); 
        }) 
        .catch(function (error) { 
        debug('ERROR >> Search failed:', error); 
        }); 
       break; 
      case 2: 
       nightmare 
       .click('#tv-filter') 
       .wait(500) 
       .click('#internet-filter') 
       .wait(500) 
       .evaluate(function(){ 
        return document.querySelector('html').innerHTML; 
       }) 
       .end() 
       .then(function (result) { 
        defer.resolve(result); 
       }) 
       .catch(function (error) { 
        debug('ERROR >> Search failed:', error); 
       }); 
       break; 
      case 3: 
       nightmare 
        .click('#tv-filter') 
        .wait(500) 
        .click('#internet-filter') 
        .wait(500) 
        .click('#phone-filter') 
        .wait(500) 
        .evaluate(function(){ 
        return document.querySelector('html').innerHTML; 
        }) 
        .end() 
        .then(function (result) { 
        defer.resolve(result); 
        }) 
        .catch(function (error) { 
        debug('ERROR >> Search failed:', error); 
        }); 
        break; 
     } 
     } 
    }); 
    }); 
    return defer.promise; 
} 
2
  1. Wie in der Dokumentation von nightmarejs erwähnt,

.wait (Selektor) Warten Sie, bis das Element Selektor ist vorhanden z .warten (‚# Pay-Button‘)

die Wartezeit Warte Arbeiten in diesem Fall nur bis das Element wird erst sichtbar, wenn es nicht dann ist es bis Standard-Timeout von 30s

  1. Warte mit Funktion

    .wait(function() { return (document.querySelector(selector) === null); })

wo Selektor ist der el auf deren Existenz im DOM wir warten.

+1

Zusätzlich können Sie eine weiche Zeitüberschreitung für warten ("Selektor") setzen, indem Sie einen nicht dokumentierten Timeout-Parameter hinzufügen. So sollte die Anfrage wie warten ("Selektor", 1000) oder was auch immer Soft-Timeout Sie möchten. Trotz fehlender Dokumentation wird es in den NightmareJS Unit Tests verwendet: https://github.com/segmentio/nightmare/blob/master/test/index.js#L341 –