所以基本的想法是编写一个方法来废弃网页以获取包含产品评级的JSON数据。然后在几个域(.de,.uk,.fr,.nl等)上多次调用此方法以收集所有评级。
所以我最终用scrapWebPage
方法废弃单页:
const scrapWebPage = async (countryAppData, productNumber) => {
const shopUrl = `https://www.shopExample.${countryAppData.countryCode}/?q=${productNumber}`
const avoidCORSUrl = 'https://allorigins.me/get?url=' + shopUrl + '&callback=?'
return await axios
.get(avoidCORSUrl, {xmlMode: false, normalizeWhitespace: true})
.then(response => {
const $ = cheerio.load(response.data)
let scrapedWebPageJson
contentForParsing = $("script").get().children[0].data
scrapedWebPageJson = JSON.parse(contentForParsing)
return scrapedWebPageJson
})
}
scrapWebPage
还包含一些解析来返回我想要的一些JSON数据 - 它正确解析(测试了这个)并返回Promise。
但后来我想在多个域上调用这个方法,所以我创建了getProductDataFromManyDomains
:
const getProductDataFromManyDomains = (productNum) => {
let prodData = {
reviews: []
}
const appCountries = [
{countryCode: 'nl'},
{countryCode: 'pl'},
{countryCode: 'de'}
]
appCountries.forEach(async countryApp => {
let countryData = {}
let parsedWebPage = await scrapWebPage(countryApp, productNum)
countryData.countryCode = countryApp.countryCode
countryData.ratingCount = parsedWebPage.aggregateRating.ratingCount
countryData.ratingValue = parsedWebPage.aggregateRating.ratingValue
countryData.reviews = parsedWebPage.reviews
prodData.reviews.push(countryData)
})
return prodData
}
现在我在填充之前收到prodData
...而我想收到实际数据(填充prodData
)。
我不确定如何在填充之前构建这个getProductDataFromManyDomains
方法来实际返回数据而不是prodData
。那可能吗?或者这里处理类似的东西有什么好的模式?
使用for
循环而不是.forEach()
。 for
循环将暂停等待,.forEach()
循环不会。这是因为你传递给async
的.forEach()
回调将返回一个承诺,但是.forEach()
并不是为了做任何事情而设计的,所以它不会在继续循环之前等待它解决,而是使用for
的await
循环。
然后,getProductDataFromManyDomains()
将需要是async
并将返回您最终结果的承诺。
async function getProductDataFromManyDomains(productNum) {
let prodData = {
reviews: []
}
const appCountries = [
{countryCode: 'nl'},
{countryCode: 'pl'},
{countryCode: 'de'}
]
for (let countryApp of appCountries) {
let countryData = {}
let parsedWebPage = await scrapWebPage(countryApp, productNum)
countryData.countryCode = countryApp.countryCode
countryData.ratingCount = parsedWebPage.aggregateRating.ratingCount
countryData.ratingValue = parsedWebPage.aggregateRating.ratingValue
countryData.reviews = parsedWebPage.reviews
prodData.reviews.push(countryData)
})
// this will be the resolved value of the promise that
// getProductDataFromManyDomains() returns
return prodData;
}
// usage
getProductDataFromManyDomains(productNum).then(result => {
console.log(result);
});
您也可以并行运行多个请求,而不是一次运行多个请求,但由于您最初尝试让代码一次执行一个,我向您展示了如何执行此操作。
如果你想并行执行它们,你只需在数组中累积promises并使用Promise.all()
知道它们何时完成,你就不会await
请求。
这是使用.map()
和Promise.all()
并行运行请求的代码版本:
function getProductDataFromManyDomains(productNum) {
let prodData = {
reviews: []
}
const appCountries = [
{countryCode: 'nl'},
{countryCode: 'pl'},
{countryCode: 'de'}
]
return Promise.all(appCounteries.map(countryApp => {
return scrapWebPage(countryApp, productNum).then(parsedWebPage => {
let countryData = {}
countryData.countryCode = countryApp.countryCode
countryData.ratingCount = parsedWebPage.aggregateRating.ratingCount
countryData.ratingValue = parsedWebPage.aggregateRating.ratingValue
countryData.reviews = parsedWebPage.reviews
return countryData;
});
})).then(results => {
// put results into prodData and make that the resolved value
prodData.reviews = results;
return prodData;
});
}
getProductDataFromManyDomains(productNum).then(result => {
console.log(result);
});