问题描述
是这样,由于业务需要,在一个国外网站上爬取数据,服务器CentOS,数据库MySQL
由于擅长js所以选择的是谷歌的puppeteer无头浏览器爬取数据.业务要求爬取数据的即时性在两分钟左右,所以爬取频率较高(循环按序爬取4-5个页面检查更新存入数据库,30秒一个页面)
我的处理是心跳每隔30秒抓取一个页面数据进行处理,国外网站较慢所以常常超时故增加了超时处理(30秒自动取消本次访问但仍然能抓取到目标数据,当然这些不重要)
_getHtmls方法是心跳循环执行的
相关代码
const fs = require("fs");
const puppeteer = require('puppeteer');
const {TimeoutError} = require('puppeteer/Errors');
async function _getHtmls(url,callback){
if( !url ){
console.log("url有问题",url);
return false;
}
console.log("_getHtmls url", url);
let htmlsName = url.match( /[^/]+(?!.*\/)/ )[0];
console.log("htmls文件名:" , htmlsName );//作为htmls文件名
//拉取url的htmls 写入log文件
const browser = await puppeteer.launch({
args: ['--no-sandbox', '--disable-setuid-sandbox'],
headless: false,
timeout: 30000
});
const page = await browser.newPage();
try {
await page.goto(url, {});
await page.waitForSelector("[dir='ltr']");//#leaderboard+script
await page.waitForSelector("#leaderboard+script");
domInnerHTML = await page.$eval("html", dom => dom.innerHTML);
// await console.log(domInnerHTML);
console.log("未超时");
} catch (e) {
if (e instanceof TimeoutError) {
await page.waitForSelector("[dir='ltr']");
await page.waitForSelector("#leaderboard+script");
domInnerHTML = await page.$eval("html", dom => dom.innerHTML);
// await console.log(domInnerHTML);
console.log("超时了");
}
}
}
问题描述
在服务器top观察,大概几分钟,cpu飙升99%导致服务器无响应假死,此bug100%稳定重现,吃内存的进程就是chrome(即puppeteer)
最终的解决办法是用npm-request+cherrio进行数据爬取和分析,但是这不是我想规避问题的初衷,问题一直困扰着我.
希望大神帮忙指导一下我问题出在哪里?别的代码不重要如有需要我再贴出来,我只想指导puppeteer为什么内存飙升那么严重,是不是我不断puppeteer.launch导致?正确的处理方式是不是puppeteer.launch一次然后循环browser.newPage()?
希望写一个小小的实例,我真的是查了好些好些资料也找不到关于多个newPage详细的操作,几乎都是操作一个页面而且也不循环抓取数据.
望不吝赐教,感激不尽!
如果没有特殊需求, 可以尝试只 puppeteer.launch() 一次, 打开一个 browser 实例, 然后循环 browser.newPage() 抓取数据.
另外,也可以检查一下代码是否有正确 browser.close() 退出不需要的 browser 实例, 看你代码没贴出来, 不知道你有没有写.