使用 nightmare.js 提出各种要求
Make various requests using nightmare.js
我正在使用 nightmarejs 抓取网站。首先,我请求获取一些链接,这些链接指向另一个页面,其中包含我也想要的更多信息。我把它分成两个功能:
const { csvFormat } = require('d3-dsv');
const Nightmare = require('nightmare');
const { writeFileSync } = require('fs');
const url = 'https://lojaonline.claro.com.br/celular';
function getUrls (){
console.log('Extraindo Links...');
const nightmare = new Nightmare({show: true});
var p1 = '51030';
var p2 = '560';
try{
nightmare.goto(url).wait('input[id="edit-cep-part1"]')
.type('input[id="edit-cep-part1"]', p1)
.wait('input[id="edit-cep-part2"]')
.type('input[id="edit-cep-part2"]', p2)
.click('input[value="Confirmar"]')
.wait('#products-container .products-list').evaluate(function(){
return Array.from(document.querySelectorAll('.offer')).map(element => element.href);
}).end()
.then(function(result){
var listaUrls = Object.values(result);
return listaUrls;
})
.then(function(listaUrls){
listaUrls.forEach(function(link){
console.log('Pegando preços de ' + link);
getPrecos(link);
});
});
}catch(e){
console.error(e);
}
};
function getPrecos(endereco) {
console.log('Extraindo preços...');
const nightmare = new Nightmare({gotoTimeout: 999999999});
var p1 = '51030';
var p2 = '560';
try{
nightmare.goto(endereco).wait('input[id="edit-cep-part1"]')
.type('input[id="edit-cep-part1"]', p1)
.wait('input[id="edit-cep-part2"]')
.type('input[id="edit-cep-part2"]', p2)
.click('input[value="Confirmar"]')
.wait('#plans-tab').evaluate(function(){
return Array.from(document.querySelectorAll('tr.body')).map(element => element.innerText);
}).end()
.then(function(result){
var listaPrecos = Object.values(result);
console.log(listaPrecos);
});
}catch(e){
console.error(e);
}
};
getUrls();
大部分情况下都有效。有些请求成功,我能够获取信息,但有些请求在 30 秒后超时:
UnhandledPromiseRejectionWarning: Error: .wait() for #plans-tab timed out after 30000msec.
我必须等待、输入并点击,因为这个特定的网站在显示数据之前要求输入邮政编码。如果我确实在 getPrecos 函数中显示 : true ,则会弹出 20 个 electron 实例。我在这里做错了什么?
有没有办法只在前一个请求完成后才触发一个请求?
你正在使用 forEach 循环遍历列表,如果你想让它们一个一个地抓取数据,那么你应该使用 for...of
和 async await
或一些支持并发的承诺库。
listaUrls.forEach(function(link) {
console.log("Pegando preços de " + link);
getPrecos(link);
});
上面的代码片段可以像下面这样使用 async await 和 for 循环来转换。
// other part of code
.then(async function(listaUrls) { // <-- async function
for(const link of listaUrls){
console.log("Pegando preços de " + link);
await getPrecos(link); // <-- go thru the link one by one
}
});
我正在使用 nightmarejs 抓取网站。首先,我请求获取一些链接,这些链接指向另一个页面,其中包含我也想要的更多信息。我把它分成两个功能:
const { csvFormat } = require('d3-dsv');
const Nightmare = require('nightmare');
const { writeFileSync } = require('fs');
const url = 'https://lojaonline.claro.com.br/celular';
function getUrls (){
console.log('Extraindo Links...');
const nightmare = new Nightmare({show: true});
var p1 = '51030';
var p2 = '560';
try{
nightmare.goto(url).wait('input[id="edit-cep-part1"]')
.type('input[id="edit-cep-part1"]', p1)
.wait('input[id="edit-cep-part2"]')
.type('input[id="edit-cep-part2"]', p2)
.click('input[value="Confirmar"]')
.wait('#products-container .products-list').evaluate(function(){
return Array.from(document.querySelectorAll('.offer')).map(element => element.href);
}).end()
.then(function(result){
var listaUrls = Object.values(result);
return listaUrls;
})
.then(function(listaUrls){
listaUrls.forEach(function(link){
console.log('Pegando preços de ' + link);
getPrecos(link);
});
});
}catch(e){
console.error(e);
}
};
function getPrecos(endereco) {
console.log('Extraindo preços...');
const nightmare = new Nightmare({gotoTimeout: 999999999});
var p1 = '51030';
var p2 = '560';
try{
nightmare.goto(endereco).wait('input[id="edit-cep-part1"]')
.type('input[id="edit-cep-part1"]', p1)
.wait('input[id="edit-cep-part2"]')
.type('input[id="edit-cep-part2"]', p2)
.click('input[value="Confirmar"]')
.wait('#plans-tab').evaluate(function(){
return Array.from(document.querySelectorAll('tr.body')).map(element => element.innerText);
}).end()
.then(function(result){
var listaPrecos = Object.values(result);
console.log(listaPrecos);
});
}catch(e){
console.error(e);
}
};
getUrls();
大部分情况下都有效。有些请求成功,我能够获取信息,但有些请求在 30 秒后超时:
UnhandledPromiseRejectionWarning: Error: .wait() for #plans-tab timed out after 30000msec.
我必须等待、输入并点击,因为这个特定的网站在显示数据之前要求输入邮政编码。如果我确实在 getPrecos 函数中显示 : true ,则会弹出 20 个 electron 实例。我在这里做错了什么?
有没有办法只在前一个请求完成后才触发一个请求?
你正在使用 forEach 循环遍历列表,如果你想让它们一个一个地抓取数据,那么你应该使用 for...of
和 async await
或一些支持并发的承诺库。
listaUrls.forEach(function(link) {
console.log("Pegando preços de " + link);
getPrecos(link);
});
上面的代码片段可以像下面这样使用 async await 和 for 循环来转换。
// other part of code
.then(async function(listaUrls) { // <-- async function
for(const link of listaUrls){
console.log("Pegando preços de " + link);
await getPrecos(link); // <-- go thru the link one by one
}
});