这是我第一次提问,所以请耐心等待。我试图在node.js中编写内容剪贴簿。我的程序将转到该站点的登录页面,获取下一页的链接并获取下一批页面的链接。我的问题是当我必须遍历一系列链接,转到那个页面,并在那里获取废品信息。我正在尝试async.forEach迭代,但它在我的链式承诺中的最后一个then()之后完成。这里的许多概念对我来说都是新的,所以我确信这段代码很棘手。任何帮助将不胜感激。
var sX = require('scrapper-x');
var request = require('request');
var async = require('async');
var Promise = require('bluebird');
var request = (require('request'));
var colors = require('colors');
var baseURL = 'http://shirts4mike.com';
var arrShirts = [
{
link: 'shirt.php?id=101',
img: 'some img'
},
{
link: 'shirt.php?id=102',
img: 'some img'
},
{
link: 'shirt.php?id=103',
img: 'some img'
}
];
var page = '';
var configMain = {
repeatItemGroup: '.nav > li',
dataFormat: {
link: {
selector: 'li > a',
type: 'attr:href'
}
}
};
var configShirts = {
repeatItemGroup: '.products > li',
dataFormat: {
link: {
selector: 'li > a',
type: 'attr:href'
},
img: {
selector: 'li > a > img',
type: 'attr:src'
}
}
};
var configDetails = {
repeatItemGroup: '.shirt-details',
dataFormat: {
price: {
selector: '.price',
type: 'text'
},
title: {
selector: '.shirt-details > h1',
type: 'text'
}
}
};
function getPage(url, config) {
return new Promise(function(resolve, reject) {
request(url, function(error, response, body, shirt) {
if (error) {
console.log('error');
reject();
}
if (!error && response.statusCode == 200) {
detail = sX.scrape(body, config);
resolve(detail);
}
});
});
}
function getDetailPage(arr, config) {
return new Promise(function(resolve, reject) {
async.forEach( arr, function( item, callback) {
request('http://www.shirts4mike.com' + '/' + item.link, function(error, response, body, item) {
if (!error && response.statusCode == 200) {
detail = sX.scrape(body, configDetails);
console.log('Item: ', detail);
}
});
callback();
});
resolve(detail);
});
}
getPage(baseURL, configMain).then( function(data) {
for (var i = 0; i < data.length; i++) {
//console.log('getMainPage: ', scrappedResult[i].link);
if (data[i].link.search('shirt') !== -1) {
page = '/' + data[i].link;
console.log(page.yellow);
baseURL += page;
return baseURL;
}
}
}).then( function(baseURL) {
return getPage(baseURL, configShirts);
}).then( function(data) {
for (var i = 0; i < data.length; i++) {
//console.log(data[i].link);
if (data[i].link.search('shirt') !== -1) {
arrShirts.push(data[i]);
console.log("arrShirts[" + i + "]: " + arrShirts[i].link);
}
}
return arrShirts;
}).then( function(arr) {
return getDetailPage(arrShirts, configDetails);
}).then(function (data) {
console.log("end: ", data);
}).catch( function(err) {
console.log(err);
});
&#13;
答案 0 :(得分:1)
我建议做一些改变。
停止使用全局变量或更高范围的变量或未声明的变量。声明使用/需要它们的局部变量,不要与其他函数共享变量。
不要将异步库与promises混合使用。由于您已经在宣传异步函数,因此使用promise函数来管理多个异步操作。您可以完全从该项目中删除异步库。
在最低级别实现Promisify,因此所有更高级别的用户都可以直接使用promises。因此,您应该宣传getPage()
,然后在request()
中使用它,而不是宣传getPage()
。
由于您拥有Bluebird promise库,您可以使用它的更高级迭代函数(例如Promise.map()
)来迭代您的集合,收集所有结果并返回单个承诺,告诉您何时完成所有操作
使用这些概念,您可以使用以下代码:
// promisified request()
function getRequest(url) {
return new Promise(function(resolve, reject) {
request(url, function(err, response, body) {
if (err) {
reject(err);
} else {
resolve(body);
}
});
});
}
// resolves to scraped contents for one page
function getPage(url, config) {
return getRequest(url).then(function(body) {
return sX.scrape(body, config);
});
}
// resolves to an array of scraped contents for an array of objects
// that each have a link in them
function getDetailPage(arr, config) {
return Promise.map(arr, function(item) {
return getPage('http://www.shirts4mike.com' + '/' + item.link);
});
}