我尝试使用梦魇抓取网页,但希望等待#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 :(得分:4)
我不认为传递cheerio
库会让你工作得很好。参数被序列化(或多或少)传递给子Electron进程,因此传递整个库可能不起作用。
从好的方面来说,fn
的{{1}}部分在页面上下文中执行 - 这意味着您可以完全访问.wait(fn)
及其拥有的方法(例如{{1} }})。您也可以访问页面的jQuery上下文(如果存在),或者如果没有,您甚至可以使用document
注入它。
除此之外,如果querySelector
(和.inject()
就此问题而言)是正确的,那么你是正确的,至少在promises could be used directly in .evaluate()
之前需要同步方法。
在此之前,您可以使用.wait()
来模仿您想要的行为:
.evaluate()
答案 1 :(得分:2)
.wait(选择器) 等到元素选择器出现,例如.wait( '#付费按钮')
在这种情况下等待等待只有在元素第一次变为可见时才会显示,否则它将工作到默认超时为30秒
.wait(function () { return (document.querySelector(selector) === null); })
其中selector是基于我们在DOM中存在的元素。
答案 2 :(得分:0)
这里我创建了一个函数来获取不同条件的html源代码,我正在抓取TimeWarnerCable页面以获取有关TV,Internet和Bundle计划的信息,因此我的函数获取了一些参数并对每个参数做出反应不同的电话。您可以使用.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;
}