我正在从许多来源(有数百万条记录)对爬虫进行一些api但是我的问题涉及内存不足。我用Google搜索并找到了一些资源,但它并没有解决我的问题。
similar question没有解决我的问题
这是我的示例代码:
function getContent() {
let d = q.defer();
let urls = [];
array.forEach(function(mang, index) {
for (let i = 1; i <= 600000; i++) {
urls.push(function (callback) {
setTimeout(function () {
let link = 'http://something.com/' + i;
let x = link;
let options = {
url: link,
headers: {
'User-Agent': 'something'
}
};
function callback1(error, response, html) {
if (!error) {
let $ = cheerio.load(html);
let tag_name = $('h1').text();
tag_name = tag_name.trim();
let tag_content = $('#content-holder').find('div').text();
let tagObject = new Object();
tagObject.tag_name = tag_name;
tagObject.tag_content = tag_content;
tagObject.tag_number = i;
tagArray.push(tagObject);
for (let v = 0; v < tagArray.length; v++) {
//console.log("INSERT INTO `tags` (tag_name, content, story_id, tag_number) SELECT * FROM (SELECT " + "'" + tagArray[v].tag_name + "'" + "," + "'" + tagArray[v].tag_content + "','" + array[c].story_id + "','" + tagArray[v].tag_number + "' as ChapName) AS tmp WHERE NOT EXISTS (SELECT `tag_name` FROM `tags` WHERE `tag_name`=" + "'" + tagArray[v].tag_name + "'" + ") LIMIT 1");
db.query("INSERT INTO `tags` (tag_name, content) " +
"SELECT * FROM (SELECT " + "'" + tagArray[v].tag_name + "'" + "," + "'" + tagArray[v].tag_content + "','" + "' as TagName) AS tmp " +
"WHERE NOT EXISTS (SELECT `tag_name` FROM `tags` WHERE `tag_name`=" + "'" + tagArray[v].tag_name + "'" + ") " +
"LIMIT 1", (err) => {
if (err) {
console.log(err);
}
});
}
urls = null;
global.gc();
console.log("Program is using " + heapUsed + " bytes of Heap.")
}
}
request(options, callback1);
callback(null, x);
}, 15000);
});
}
});
d.resolve(urls);
return d.promise;
}
getContent()
.then(function (data) {
let tasks = data;
console.log("start data");
async.parallelLimit(tasks, 10, () => {
console.log("DONE ");
});
})
我尝试使用global.gc()函数,但似乎没有效果
答案 0 :(得分:1)
期待有一份小批量的工作。我之前曾经使用像Kue这样的任务管理器,但坦率地说,你需要做的就是首先用10或25之类的合理数字填充你的URL数组。一种方法是在其中包含一个包含所有URL的表并且要么是他们已成功抓取的旗帜,要么是你计划再次执行它们的最后抓取日期我是时候了。
然后查询尚未抓取的所有网址(或者比一周前的某个日期更早抓取的网址),并将结果限制为10或25或其他任何内容。首先抓取并存储这些,我可能会使用像async.js #map或Promise.all这样的东西,而不是你当前正在使用的循环。
如果所有URL都在同一个域中,您可能希望每个请求之间都有一个短暂的超时,以尊重这些资源。
批处理完成后,查询您的数据库以获取下一批并重复。
根据您的体系结构,最好让这个程序更简单,除了获取一个批处理并解决一个批处理的爬网之外什么也不做。然后,您可以在cron作业或Windows服务上运行它,每5分钟或每15分钟或其他任何时间运行一次。
现在在手机上,但是如果你需要的话,我会在以后尝试使用笔记本电脑给你一个代码示例。