2016-04-19 56 views
1

我试图抓取一个使用梦魇的网页,但只有在实际存在时才想要等待#someelem存在。否则,我想让梦魇继续前进。这怎么可以用.wait()来完成?梦魇有条件的等待()

我不能使用.wait(ms)。使用.wait(selector)意味着梦魇将持续等待,直到元素出现,但如果页面永远不会有这个元素,梦魇将永远等待。

最后一个选项是使用.wait(fn)。我已经试过这样的事情

.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) 

所以,等待并再次尝试(高达阈值),如果未找到该元素,然后继续前进。该代码似乎错误setTimeout,因为.wait在浏览器范围内完成。

提前致谢!

+0

梦魇医生说:等到'arn1,arg2,...'返回'true'页面的'fn'评估。所以,'wait'会一直等到'true'返回。是的,你是对的,它并不是真的。 – user

回答

4

我不认为通过cheerio库,因为它会很好地工作。参数被序列化(或多或少)以传递给子电子进程,因此传递整个库可能不起作用。

在了一面,.wait(fn)fn部分在页面上下文中执行 - 这意味着你可以完全访问document它具有方法(例如,querySelector)。如果存在,你也可以访问该页面的jQuery上下文,或者如果不存在,你甚至可以使用.inject()注入它。

设置一边,你就对.wait()(和.evaluate(),就此而言)是正确的,期望一个同步方法,至少直到像promises could be used directly in .evaluate()之类的东西。

直到那是可用的,你可以使用.action()模仿你想要的行为:

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

甜!这很好。谢谢罗斯! – user

+2

我想现在不需要这个了,因为我们可以使用'.wait('#elem')',对吧? –

0

在这里,我创建一个函数来获取HTML源不同的条件,我是爬行TimeWarnerCable页面以获取信息关于电视,互联网和捆绑计划,所以我的功能获取一些参数,并在不同的调用中对每个参数做出反应。您可以使用.exists()检查选择,然后用噩梦

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. 作为nightmarejs的文件中提到,

.wait(选择)继续 等到元素选择器存在,例如。等待(“#付费按钮”)

在这种情况下,等待观望的作品只是直到元件首先变得可见,如果它不那么它会一直工作到30多岁的默认超时

  • 等待与功能

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

  • 其中选择器是EL基于在我们等待的DOM中存在谁的意见。

    +1

    此外,您可以通过添加未记录的超时参数来为wait(“selector”)设置软超时。所以请求应该看起来像wait(“selector”,1000)或任何你想要的软超时。尽管缺少文档,它在NightmareJS单元测试中使用:https://github.com/segmentio/nightmare/blob/master/test/index.js#L341 –