나는 전자 상거래 사이트에서 데이터를 긁어 내기 위해 Node.js를 사용하고있다. 나는 Request
을 사용하여 페이지의 DOM을 검색하고 Cheerio
을 사용하여 서버 측 DOM 선택을 수행합니다.Javascript for 루프에 서버 측 지연을 추가하는 방법은 무엇입니까?
const cheerio = require('cheerio');
const request = require('request');
// takes a URL, scrapes the page, and returns an object with the data
let scrapePage = (url) => {
return new Promise((resolve, reject) => {
request(url, (error, resp, body) => {
if(error){
reject(error);
};
let $ = cheerio.load(body);
let $url = url;
let $price = $('#rt-mainbody > div > div.details > div.Data > div:nth-child(4) > div.description').text();
let obj = {
url: $url,
price: $price
}
resolve(obj);
});
});
};
// Runs scrapePage in a loop
// There is a variable called arrayOfURLs defined elsewhere that contains 100s of URLs
for(let i = 0; i < arrayOfURLs.length; i++){
scrapePage(arrayOfURLs[i])
.then((obj) => {
//write to a file
})
.catch((error) => {
})
};
문제는 그 요청을 보내 서버가 가끔 정지의 어떤 종류없이 너무 많은 요청을 보내는 거니까, 내가 믿고있어 빈 데이터를 다시 보내는 것입니다. JS의 비동기 특성으로 인해 루프의 각 반복 사이에 효과적인 지연을 추가하는 방법을 찾는 데 어려움을 겪고 있습니다. setTimeOut
자체가 비동기이기 때문에 동기식으로 setTimeOut
을 추가하는 것만으로는 충분하지 않으며 서버에서 실행 중이므로 Window
개체가 없습니다.
편집
위의 코드는 내가 일하고 있어요 무엇의 단순화 된 버전입니다. 전체 코드는 이것이다 : 서버 응답을 보내기 전에 약속 해결하기 위해 당신이 기다리고되지 않습니다처럼
app.js
const fs = require('fs');
const path = 'urls.txt';
const path2 = 'results.txt';
const scraper = require('./scraper');
let scrapePage = (url) => {
scraper.scrapePage(url)
.then((obj) => {
// console.log('obj from the scraper with Promises was received');
// console.log(obj);
// console.log('writing obj to a file');
fs.appendFile(path2, JSON.stringify(obj) + ', ', (error) => {
if(error){
console.log(error);
} else {
// console.log('Successfully wrote to ' + path2);
}
})
})
.catch((error) => {
console.log('There was an error scraping obj: ');
console.log(error);
})
}
fs.readFile(path, 'utf8', (err, data) => {
if (err){
throw err;
};
var urlArray = JSON.parse(data);
// this returns an Unexpected Identifier error
// const results = await Promise.all(urlArray.map(scrapePage));
// this returns an Unexpected Token Function error
// async function scrapePages(){
// const results = await Promise.all(urlArray.map(scrapePage));
// };
});
scraper.js
const request = require('request');
const cheerio = require('cheerio');
exports.scrapePage = (url) => {
return new Promise((resolve, reject) => {
request(url, (error, resp, body) => {
if(error){
reject(error);
};
let $ = cheerio.load(body);
let $url = url;
let $price = $('#rt-mainbody > div > div.details > div.itemData > div:nth-child(4) > div.description').text();
let obj = {
url: $url,
price: $price
}
resolve(obj);
})
})
}
[sleep()의 JavaScript 버전은 무엇입니까?] (https://stackoverflow.com/questions/951021/what-is-the-javascript-version-of-sleep) –
당신이 의지 할 수없는 복제본 주어진 시간 후에 데이터가있을 것이라고 가정합니다. 대신 콜백 함수를 사용하여 접근을 시도하십시오. – Ctznkane525
이 빈 데이터 문제를 조사해보고 최소한 헤더와 응답 코드를 기록하여 오류의 위치를 파악할 수 있습니다. 추측하고있는 것처럼 보이며 오류가 무엇인지 알기도 전에 변경해야하는 이유는 무엇입니까? –