Puppeteer:内存泄漏错误和超时处理



我正试图从这个网站上抓取数据。下面是代码,它适用于单一地区和医院类型,但当我把它放在循环中时会中断。我尝试将getData函数中的语句设置为异步等待,但它仍然打开了数百个浏览器实例,导致内存泄漏问题。我该如何修复它,使它一次运行一个,而不是一次运行所有。

const puppeteer = require('puppeteer');
const districtList = ["020", "001", "003", "008", "016", "017", "004", "006", "005", "007", "022", "021", "019", "009",
"012", "013", "023", "010", "002", "011", "014", "015", "018"];
outputJsonArray = [];
const url = "https://excise.wb.gov.in/CHMS/Public/Page/CHMS_Public_Hospital_Bed_Availability.aspx";
async function scrape(did, hospType) {
// const browser = await puppeteer.launch({headless: false, args: ['--auto-open-devtools-for-tabs']});
const browser = await puppeteer.launch({headless: false});
const page = await browser.newPage();
page.setDefaultNavigationTimeout(0);
await page.goto(url, {waitUntil: 'networkidle0', timeout: 0});
await page.waitForSelector('#ctl00_ContentPlaceHolder1_ddl_District');
await page.click(hospType);
await page.select('#ctl00_ContentPlaceHolder1_ddl_District', did);
await page.waitForSelector('tbody tr');
// extracting information from code
let outputData = await page.evaluate(() => {
let output = [];
let dataRows = document.body.querySelectorAll("tbody tr");
let cityName = document.querySelector("#ctl00_ContentPlaceHolder1_ddl_District").selectedOptions[0].textContent.trim();
console.log(cityName)
// return dataRows.length;
console.log("Num entries == " + dataRows.length);
dataRows.forEach((dataRow) => {
let rowJson = {};
// debugger;
rowJson["Name"] = dataRow.querySelector('h5').textContent.trim().replace(/s+/g, ' ');
// let h3 = dataRow.querySelectorAll('li h3.text-success')[3].textContent;
rowJson["Contact"] = dataRow.querySelector('.rounded-pill.bg-success').textContent.trim().replace(/s+/g, ' ');      
output.push(rowJson);
})
return output;
});
outputJsonArray = outputJsonArray.concat(outputData);
console.log("data == ");
console.log(outputData);
await browser.close();
};
districtList.forEach(getData);
async function getData(districtId) {
await scrape(districtId, "[for=ctl00_ContentPlaceHolder1_rdo_Govt_Flag_0]")
await scrape(districtId, "[for=ctl00_ContentPlaceHolder1_rdo_Govt_Flag_1]")
await scrape(districtId, "[for=ctl00_ContentPlaceHolder1_rdo_Govt_Flag_2]")
console.log("+++++++++++++++++Full JSON below+++++++++++++++++");
console.log(outputJsonArray);
}

此外,在第17行,waitForSelector超时并完全停止执行。这是因为有些情况没有结果。例如,选择";ALIPURDUAR";在地区和第二医院类型没有返回任何结果,因此它一直在等待,应该超时。我该如何处理这两个问题?

(节点:50036(MaxListenersExcededWarning:可能的EventEmitter内存检测到泄漏。向[进程]添加了11个出口侦听器。使用emitter.setMaxListeners((以增加限制(使用node --trace-warnings ...显示创建警告的位置((节点:50036(MaxListenersExceedWarning:Possible EventEmitter内存检测到泄漏。向[进程]添加了11个SIGINT侦听器。使用emitter.setMaxListeners((以增加限制(节点:50036(MaxListenersExceeddWarning:可能存在EventEmitter内存泄漏检测到。向[进程]添加了11个SIGTERM侦听器。使用emitter.setMaxListeners((以增加限制(节点:50036(MaxListenersExceeddWarning:可能存在EventEmitter内存泄漏检测到。向[进程]添加了11个SIGHUP侦听器。使用emitter.setMaxListeners((以增加限制

我推荐更可靠的解决方案:为每个地区和医院运行一个导入木偶师的儿童流程。这样,主进程就永远不会泄漏,每个子进程都可能泄漏,但你们不在乎,因为你们会尽快杀死它,它会释放所有资源。我知道它没有文档,但它很好地解决了这个问题。

另一个链接:

  • puppeteer中的原始内存泄漏GitHub问题,并建议子进程解决该问题
  • scriptimate工具的源代码,它为动画的每一帧生成一个新的过程

您可能在浏览器上下文中遇到错误。尝试可选的链接,看看这是否有帮助:

let data = await page.$$eval('tbody tr', trs => trs.map(tr => {
return {
name: tr.querySelector('h5')?.textContent?.trim()?.replace(/s+/g, ' '),
contact: tr.querySelector('.rounded-pill.bg-uccess')?.textContent?.trim().replace(/s+/g, ' ')
}
}))

编辑

因此,要一次运行这些程序,您可以执行以下操作:

async function run(districtList){
for(let districtId of districtList){
await getData(districtId)
}
}
run(districtList)

问题出在forEach上,它看起来像一个for循环,但实际上不是。

最新更新