我正试图为所有教授刮取http://www.ratemyprofessors.com/。我的代码似乎得到以下错误:
FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed - JavaScript heap out of memory
1: node::Abort() [node]
2: 0x10d3f9c [node]
3: v8::Utils::ReportApiFailure(char const*, char const*) [node]
4: v8::internal::V8::FatalProcessOutOfMemory(char const*, bool) [node]
5: v8::internal::Factory::NewFillerObject(int, bool, v8::internal::AllocationSpace) [node]
6: v8::internal::Runtime_AllocateInTargetSpace(int, v8::internal::Object**, v8::internal::Isolate*) [node]
7: 0x292aec062bf
Aborted
我不知道我做了什么导致这个错误,但可能是因为我的循环?我需要循环超过1000万页但我不知道为什么它甚至只用10个循环给我这个错误。这是代码:
var express = require('express');
var path = require('path');
var request = require('request');
var cheerio = require('cheerio');
var fs = require('fs');
var app = express();
var count = 1;
var url;
while(count != 10){
url = "http://www.ratemyprofessors.com/ShowRatings.jsp?tid=" + count;
request(url, function(err, resp, body){
var $ = cheerio.load(body);
if($('.error').text().substring(0, 14) == "Page Not Found"){
console.log("hello");
count++;
return;
}else{
console.log($('.error').text().substring(0, 14) );
var pfname = $('.pfname');
var plname = $('.plname');
var professorName = pfname.text().replace(/\s/g, '') + " " +plname.text().replace(/\s/g, '');
console.log(professorName);
console.log(url);
count++;
}
return;
})
}
app.listen(3000, function(){
console.log("server is now listening");
})
答案 0 :(得分:0)
你可能正在做超过10个循环。您只在请求的回调中递增计数,这可能在发送请求后的几百毫秒内发生。在那段时间,while循环正在尽可能快地发送请求。
如果您只使用普通的for循环而不是while循环,这可能会更好。
答案 1 :(得分:0)
您应该创建一个URL数组,然后使用Cheerio迭代该数组。这段代码应该让你开始,虽然它可以使用很多改进。最后的超时是网址可以完成填充。
var request = require('request');
var cheerio = require('cheerio');
var url;
var urls = [];
for (i = 1; i < 10; i++) {
url = 'http://www.ratemyprofessors.com/ShowRatings.jsp?tid=' + i;
urls.push(url);
}
function done() {
var arrayLength = urls.length;
var promiseArray = [];
for (var i = 0; i < arrayLength; i++) {
request(urls[i], function(err, resp, body) {
var $ = cheerio.load(body);
if (
$('.error')
.text()
.substring(0, 14) == 'Page Not Found'
) {
console.log('hello');
return;
} else {
console.log(
$('.error')
.text()
.substring(0, 14)
);
var pfname = $('.pfname');
var plname = $('.plname');
var professorName =
pfname.text().replace(/\s/g, '') +
' ' +
plname.text().replace(/\s/g, '');
console.log(professorName);
console.log(url);
}
return;
});
}
}
setTimeout(function() {
done();
}, 3000);
console.log(urls);
答案 2 :(得分:0)
我认为Raphael是正确的,因为你正在进行10个以上的循环,因为在请求的回调之前,计数不会增加。您可以使用async.whilst
之类的东西来解决这个问题,它允许您在while循环中串行运行异步代码:
const request = require('request')
const async = require('async')
let count = 1
const test = () => count < 10
const iteratee = callback => {
const url = 'http://www.ratemyprofessors.com/ShowRatings.jsp?tid=' + count
request(url, (error, response, body) => {
if (error) return callback(error)
// do other stuff here
count++
callback()
})
}
const done = error => {
// all done
}
async.whilst(test, iteratee, done)
这可能更安全,更负责任,因为你阻止向他们的服务器发出并发请求(想象一下,如果你只是同时向同一个地方发射了1000万个HTTP请求 - 不好)。如果您确实想要发出并发请求,可以考虑使用async.map
或async.each
等“并行”方法以及bottleneck等速率限制器。