This is a simplified code that runs on Node.js crawler and it gets all data. But how do I insert inside the "callback": function value of var "i" from cycle for(var i=0... When I'm adding name: datas[i].name it returns an error:
TypeError: Cannot read property 'undefined' of undefined
var Crawler = require("crawler").Crawler;
var crawler = new Crawler;
var datas = [
{name: 'John', url: 'john025'},
{name: 'Jim', url: 'jim04567'}
];
function crauler(done) {
for (var i = 0; i < datas.length; i++) {
var link = 'http://somesite.com/' + datas[i].url;
crawler.queue([{
"uri": link,
// inside this func
"callback": function (error, result, $, datas, i) {
var arr = $('.blogpost').map(function (index) {
var str = $(this).attr('href');
var object = {
numb: str,
name: datas[i].name
};
return obj;
}).get().join(',');
done(arr);
} }]) }; };
crauler (function (arr) {
console.log(arr);
});
You can't pass datas and i into callback functions like this. What arguments that the callback functions will be called with are up to the caller, you don't have the control of it.
You're seeing "TypeError: Cannot read property 'undefined' of undefined" because you want your callback function to have datas and i as parameters; but the caller will call the callback with the first 3 arguments only [crawler callback reference], so the datas and i are undefined.
Therefore, you should remove the datas and i from in line:
"callback": function (error, result, $, datas, i) {
Because datas is defined in the outer scope of the callback function, the callback can access datas without any special treatment. For the variable i, it's a little bit tricky as mentioned in other answers, so you need to create a closure for it.
So, your callback function definition should be something looks like the following:
"callback": (function(i) { // create closure for i
return function (error, result, $) { // no more datas and i here
var arr = $('.blogpost').map(function (index) {
var str = $(this).attr('href');
var object = {
numb: str,
name: datas[i].name // access datas as it
};
return obj;
}).get().join(',');
done(arr);
}
})(i)
You're trying to create a closure around i inside of a loop which is causing you problems. This answer should help you:
You need a closure to capture the values, this is one way to solve the problem. Read up on closures.
Javascript
var Crawler = require("crawler").Crawler;
var crawler = new Crawler;
var datas = [{
name: 'John',
url: 'john025'
}, {
name: 'Jim',
url: 'jim04567'
}];
function queue(link, i) {
crawler.queue([{
"uri": link,
// inside this func
"callback": function (error, result, $, datas, i) {
var arr = $('.blogpost').map(function (index) {
var str = $(this).attr('href');
var object = {
numb: str,
name: datas[i].name
};
return obj;
}).get().join(',');
done(arr);
}
}]);
}
function crauler(done) {
for (var i = 0; i < datas.length; i++) {
var link = 'http://somesite.com/' + datas[i].url;
queue(link, i);
};
crauler(function (arr) {
console.log(arr);
});