2016-08-04 10 views
0

Es gibt eine Website, die eine Seite mit einer Liste von 25 Einträgen enthält, wobei jeder Eintrag ein Link zu einer Seite ist, die einige Informationen enthält, die ich brauche. Ich möchte auf die Liste Seite und dann: 1) klicken Sie auf den Link zum ersten Eintrag 2) rufen Sie alle HTML 3) klicken Sie zurück auf die Liste Seite (es gibt eine Schaltfläche dafür) 4) für jeden anderen wiederholen NotierungWechsel zwischen Seiten und Scraping wie ich mit Nightmare gehe

Ich würde auch gerne so effizient wie möglich tun, was mir gesagt wurde, Hebelwirkung verspricht. Hier ist mein Code Skizze, die nicht funktioniert:

var Nightmare = require('nightmare'); 
var nightmare = Nightmare({ openDevTools: true, show: true }) 
var Xray = require('x-ray'); 
var x = Xray(); 
var resultArr = []; 

nightmare 
.goto(hidTestURL) 
.wait(2500) 
.click('input[name="propertySearchOptions:advanced"]') //start navigating to listing page 
.wait(2500) 
.type('input[name="propertySearchOptions:streetName"]', 'Main') 
.wait(2500) 
.select('select[name="propertySearchOptions:recordsPerPage"]', '25') 
.wait(2500) 
.click('input[name="propertySearchOptions:search"]') //at listing page 
.wait(2500) 
.then(function(){ 
    nightmare 
    .click('a[href^="Property.aspx?prop_id=228645"]') //first entry 
    .evaluate(function(){ //retrieve info 
    var resultArr = []; 
    resultArr.push(document.querySelector('html').innerHTML); 
    }) 
}) 

nightmare 
.click('a[id="propertyHeading_searchResults"]') //return to listing page 
.evaluate(function(){ 
    return resultArr.push(document.querySelector('html').innerHTML); retrieve listing page info to show that it returned. 
}) 
.then(function (resultArr) { 
    console.log('resultArr', resultArr); 
    x(resultArr[1], '[email protected]') //output listing page html 
    .write('results.json'); 
}) 

Dies wird bis zur Eintragsseite, und dann nicht weiter gehen wird. Ich habe auch den gleichen Code versucht, aber mit return nightmare für jede Verwendung von nightmare mit Ausnahme der ersten. Ich habe einige Beispiele gesehen, die return verwendet haben, aber als ich das getan habe, hat der Code einen Fehler verursacht.

Ich habe auch versucht, nicht die dritte nightmare (die nach dem Leerzeichen), und stattdessen versuchen, die alte Albtraum-Instanz fortzusetzen, indem Sie direkt auf die .click() gehen, aber das warf auch einen Fehler.

Ich brauche eindeutig Hilfe bei der Syntax und Semantik von Albtraum, aber es gibt nicht viel Dokumentation online neben einer API-Liste. Weiß jemand wie ich das machen kann?

Antwort

5

Zuerst ruft Nightmare wie Sie es haben - in zwei Ketten gebrochen - ist wahrscheinlich nicht zu tun, was Sie wollen. (This comment thread ist eine gute - wenn auch lange - Primer.) Memory Serving, Aktionen aus der zweiten Kette wird direkt nach der ersten in die Warteschlange gestellt, was zu (wahrscheinlich) unerwünschtes Verhalten. Du hast gesagt, du hättest es etwas anders geschrieben - ich wäre neugierig, es zu sehen, es klingt, als wäre es ein bisschen näher gekommen.

Zweitens versuchen Sie, resultArr in .evaluate() zu heben, was nicht möglich ist. Die Funktion, die an .evaluate() übergeben wurde, wird innerhalb von Electron beschriftet und wiederhergestellt - was bedeutet, dass Sie den Umgebungskontext um die Funktion verlieren. This example in nightmare-examples geht in ein wenig mehr Tiefe, wenn Sie neugierig sind.

Drittens, und vielleicht ist dies ein Tippfehler oder mich Missverständnis Absicht: href Selektor verwendet die Starts-mit (^=) -Operator, ist das absichtlich? Sollte das ein Ende sein mit ($=)?

Vierte, looping over asynchronous operations is tricky. Ich habe den Eindruck, dass das auch ein Stolperstein sein könnte?

Mit all dem im Hinterkopf, werfen wir einen Blick auf das Ändern Ihres ursprünglichen Skripts. Zwar nicht getestet, da ich, keinen Zugriff auf Ihre Tests URL haben, so ist dies ein bisschen aus der Hüfte:

var Nightmare = require('nightmare'); 
var nightmare = Nightmare({ openDevTools: true, show: true }) 
var Xray = require('x-ray'); 
var x = Xray(); 

nightmare 
.goto(hidTestURL) 
.wait(2500) 
.click('input[name="propertySearchOptions:advanced"]') //start navigating to listing page 
.wait(2500) 
.type('input[name="propertySearchOptions:streetName"]', 'Main') 
.wait(2500) 
.select('select[name="propertySearchOptions:recordsPerPage"]', '25') 
.wait(2500) 
.click('input[name="propertySearchOptions:search"]') //at listing page 
.wait(2500) 
.evaluate(function(){ 
    //using `Array.from` as the DOMList is not an array, but an array-like, sort of like `arguments` 
    //planning on using `Array.map()` in a moment 
    return Array.from(
    //give me all of the elements where the href contains 'Property.aspx' 
    document.querySelectorAll('a[href*="Property.aspx"]')) 
    //pull the target hrefs for those anchors 
    .map(a => a.href); 
}) 
.then(function(hrefs){ 
    //here, there are two options: 
    // 1. you could navigate to each link, get the information you need, then navigate back, or 
    // 2. you could navigate straight to each link and get the information you need. 
    //I'm going to go with #1 as that's how it was in your original script. 

    //here, we're going to use the vanilla JS way of executing a series of promises in a sequence. 
    //for every href in hrefs, 
    return hrefs.reduce(function(accumulator, href){ 
    //return the accumulated promise results, followed by... 
    return accumulator.then(function(results){ 
     return nightmare 
     //click on the href 
     .click('a[href="'+href+'"]') 
     //get the html 
     .evaluate(function(){ 
      return document.querySelector('html').innerHTML; 
     }) 
     //add the result to the results 
     .then(function(html){ 
      results.push(html); 
      return results; 
     }) 
     .then(function(results){ 
      //click on the search result link to go back to the search result page 
      return nightmare 
      .click('a[id="propertyHeading_searchResults"]') 
      .then(function() { 
       //make sure the results are returned 
       return results; 
      }); 
     }) 
    }); 
    }, Promise.resolve([])) //kick off the reduce with a promise that resolves an empty array 
}) 
.then(function (resultArr) { 
    //if I haven't made a mistake above with the `Array.reduce`, `resultArr` should now contain all of your links' results 
    console.log('resultArr', resultArr); 
    x(resultArr[1], '[email protected]') //output listing page html 
    .write('results.json'); 
}); 

Hoffentlich ist das genug, um Sie zu erhalten begonnen.