3

我正在尝试使用 Nightmare 抓取网页,但希望等待#someelem出现,前提是它确实存在。否则,我希望 Nightmare 继续前进。如何做到这一点.wait()

我不能用.wait(ms)。Using.wait(selector)意味着 Nightmare 会一直等待直到元素出现,但是如果页面永远不会有这个元素,Nightmare 会一直等待。

最后一个选项是使用.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是在浏览器范围内完成的。

提前致谢!

4

3 回答 3

5

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

从好的方面来说,fn部分.wait(fn)是在页面上下文中执行的——这意味着您可以完全访问document它拥有的方法(例如,querySelector)。如果它存在,您还可以访问页面的 jQuery 上下文,或者如果不存在,您甚至可以使用.inject()它来注入它。

撇开这一点不谈,就.wait()(并且.evaluate(),就此而言)期望同步方法而言,您是对的,至少在可以直接在.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);
  });
于 2016-04-20T05:21:22.243 回答
3
  1. 正如 nightmarejs 的文档中提到的,

.wait(selector) 等到元素选择器出现,例如 .wait('#pay-button')

在这种情况下,等待等待仅在元素第一次变得可见时才起作用,如果它不可见,那么它将一直工作到默认超时 30 秒

  1. 等待函数

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

其中 selector 是我们等待在 DOM 中存在的元素。

于 2017-01-31T11:46:16.150 回答
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;
}
于 2016-07-21T19:51:36.517 回答