我编写了一个抓取工具,可以遍历网站上的每个页面并提取信息。页面很多;如果这个程序不间断地运行,大约需要一周的时间才能完成。然而,每隔两三个小时,当它尝试从页面中提取信息时,它就会挂起,并且永远不会继续。这很令人沮丧,因为我一直不得不重新启动脚本。这是它的框架,使用 NodeJS 运行:
index = 0;
finalIndex = 50000;
function scrape(){
if(index < finalIndex){
//hit the website using nightmare, navigate to page, extract info, store as JSON
console.log("finished scraping page number: ", index);
index++;
scrape();
}
}
scrape();
我想在这个文件或另一个文件中拥有一个运行抓取功能的函数,然后每 2 小时终止该函数并从它尝试抓取的最后一个索引重新启动它。我尝试过使用 setTimeout 来思考公式,但我不确定如何中途终止函数堆栈。如果抓取功能已经开始挂起,我也不希望重新启动功能失败。
对我来说最好的方法是什么?欢迎针对此问题提供其他解决方案,但即使从 JavaScript 知识的 Angular 来看,我也想知道将来如何做到这一点。
这是我的函数的更详细信息:
function scrape() {
console.log("initializing scrape from index: " + index);
var nightmare = Nightmare();
if (index < indexEnd) {
nightmare
.goto(hidTestURL) //connect to the main site
.wait('input[name="propertySearchOptions:advanced"]')
.wait(4000)
.goto(pageURL) //navigate to the specific entry's info page
.wait('a[id="propertyHeading_searchResults"]')
.wait(2500)
.evaluate(function(){
return document.querySelector('body').innerHTML;
})
.then(function(html){
return xP([html, {data: css.data}])() //scrape the data from the page
})
.then(cleanDetails)
.then(writeResult)
.then(_ => {
nightmare.end();
nightmare.proc.disconnect();
nightmare.proc.kill();
nightmare.ended = true;
nightmare = null;
})
.then(function(){
console.log("successful scrape for ", ids[index]);
++index;
setTimeout(scrape(), interval); //start scraping the next entry after a specified delay (default 4 seconds)
})
.catch(function(e){
if (e.message === 'EmptyProperty'){
console.log('EmptyProperty');
++index;
setTimeout (scrape, interval / 2);
}
else {
return appendFileP(logFile, new Date().toString() + " unhandled error at " + street + index + ' ' + e + '\r\n', 'utf8')
.then(function(){
if (numOfTries < 2){
console.log("Looks like some other error, I'll retry: %j", e.message);
++numOfTries;
setTimeout (scrape, interval * 5);
return nightmare.end();
}
else {
console.log("Tried 3 times, moving on");
++index;
numOfTries = 0;
setTimeout (scrape, interval * 5);
return nightmare.end();
}
});
}
})
}
有些辅助函数的代码我没有包含在内,但它们的名称应该很明显,而且我不认为它们的函数是问题的重要部分。我还想澄清一下,我正在使用 Node 运行它,它从未在浏览器中运行。
最佳答案
我之前必须解决类似的问题,我选择的解决方案是确保每个页面在一定时间内完成,否则继续下一页。您可以将噩梦代码包装在 Promise 中,并使用 Promise.race 来确保它在设定的时间内完成。然后,如果超时,请使用 v2.8.0 中引入的 .halt
api以防止内存泄漏和废弃的进程。
它看起来像这样:
Promise.race([
doNightmareCodeAndReturnPromise(nightmareInstance),
new Promise((resolve, reject) => setTimeout(() => reject('timed out'), 5000))
])
.then(result => /* save result */)
.catch(error => {
if (error === 'timed out') nightmareInstance.halt()
})
关于javascript - 如何从另一个 JavaScript 函数定期终止并重新启动一个 JavaScript 函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40007105/