javascript - 如何从另一个 JavaScript 函数定期终止并重新启动一个 JavaScript 函数

标签 javascript node.js

我编写了一个抓取工具,可以遍历网站上的每个页面并提取信息。页面很多;如果这个程序不间断地运行,大约需要一周的时间才能完成。然而,每隔两三个小时,当它尝试从页面中提取信息时,它就会挂起,并且永远不会继续。这很令人沮丧,因为我一直不得不重新启动脚本。这是它的框架,使用 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/

相关文章:

javascript - 使用 Jquery 的 onClick 事件

node.js - Node ffmpeg模块卡住了多个文件

javascript - Nodejs - 使用属性读取器包时出错

javascript - 动态宽度测量 : ReactJS/NodeJS & HTML/CSS

javascript - 显式调用与父函数查找的效率

javascript - jQuery 平滑滚动问题,页面 'blinks' 一秒钟

javascript - 如何使文本字段适合 Dynamics CRM 2011

javascript - 可变属性作为​​ jQuery 插件中的参数

node.js - 如何配置 __dirname 指向 Node 中的项目目录?

node.js - 我的 Meteor 应用程序出现服务器错误?