Я играю с Cheerio в Node. У меня есть скребок, который идет в список статей, захватывает все URL-адреса статьи, а затем переходит к каждой статье и сбрасывает заголовок и URL-адрес. Все работает нормально, за исключением случаев, когда я пытаюсь повысить результаты до моего монгоба, я получаю неопределенное.
Я предполагаю, что он пытается взлететь до того, как будут определены значения... Но даже с помощью запроса-ответа я не могу заставить его работать. Любая помощь будет принята с благодарностью! Поскольку код не слишком длинный, я просто вставлю все это, чтобы было легче увидеть, что я пытаюсь сделать. Опять же, основной проблемой является получение upsertArticle
для фактического повышения переменных.
const request = require('request');
const cheerio = require('cheerio');
const rp = require('request-promise');
const mongoose = require('mongoose');
const Article = require('./models/article');
var urls = [];
//get the list of articles to scrape
rp('https://www.somesite.com/', function(error, response, html) {
if (!error && response.statusCode == 200) {
var $ = cheerio.load(html);
$('.c-entry-box--compact__title').each(function(i, element) {
var a = $(this);
urls.push(a.children().attr('href'));
}); } })
//scrape over each article individually
.then(function(getStuff) {
var arrayLength = urls.length;
//get the list of articles to scrape and upsert each one
for (var i = 0; i < arrayLength; i++) {
const result = rp(urls[i], function(error, response, html) {
if (!error && response.statusCode == 200) {
var $ = cheerio.load(html);
var parsedResults = [];
$('.l-main-content').each(function(n, element) {
var a = $(this);
var title = a.find('.c-page-title').text();
var url = response.request.uri.href;
//I also tried upserting the variables right here, that didn't work
return { title, url };
});
} else {console.log(error);}
}).then(function(upsertStuff) {
//also tried returning and upserting stuff here... but nothing gets upserted
upsertArticle({
title: result.title,
source: result.url,
dateCrawled: new Date()
});
console.log('Upserted ' + result.title);
}).catch(function(err) {console.log(err); }); }
}) .catch(function(err) {console.log(err); });
function upsertArticle(userObj) {
const DB_URL = 'mongodb://localhost/articles';
if (mongoose.connection.readyState == 0) {
mongoose.connect(DB_URL, {
useMongoClient: true
});
}
let conditions = {
title: userObj.title
};
let options = {
upsert: true,
new: true,
setDefaultsOnInsert: true
};
Article.findOneAndUpdate(conditions, userObj, options, (err, result) => {
if (err) throw err;
});
}
Я внес несколько изменений в предоставленный код. А именно, я использую обещания вместо обратных вызовов, чтобы ваша логика оставалась последовательной и чтобы все работало, когда это должно быть.
Для цикла for
я переместил upsertArticle({...})
обратно внутри each
функции, так что title
и url
определяются при запуске.
Наконец, я использую Bluebird Promise.all
(request-promise
имеет зависимость от Bluebird уже), чтобы сигнализировать, когда все ссылки были обновлены. Это изменение является необязательным, но я думаю, что будет полезно получить обратную связь, когда все будет завершено:
Попробуйте:
const request = require('request');
const cheerio = require('cheerio');
const rp = require('request-promise');
const mongoose = require('mongoose');
const Article = require('./models/article');
const Promise = require("bluebird");
var urls = [];
rp({uri: 'https://www.somesite.com', resolveWithFullResponse: true}).then(function(response) {
if(response.statusCode != 200) throw "Response: " + response.statusCode;
var html = response.body;
var $ = cheerio.load(html);
$('.c-entry-box--compact__title').each(function(i, element) {
var a = $(this);
urls.push(a.children().attr('href'));
});
}).then(function(getStuff) {
var arrayLength = urls.length;
var promiseArray = [];
for(var i = 0; i < arrayLength; i++) {
const p = rp({uri: urls[i], resolveWithFullResponse: true}).then(function(response) {
if(response.statusCode != 200) throw "Response: " + response.statusCode;
var html = response.body;
var $ = cheerio.load(html);
var parsedResults = [];
$('.l-main-content').each(function(n, element) {
var a = $(this);
var title = a.find('.c-page-title').text();
var url = response.request.uri.href;
upsertArticle({
title: title,
source: url,
dateCrawled: new Date()
});
console.log('Upserted ' + title);
});
});
promiseArray.push(p);
}
return Promise.all(promiseArray);
}).then(function() {
console.log("Done upserting!");
})
.catch(function(err) {
console.log(err);
});
function upsertArticle(userObj) {
const DB_URL = 'mongodb://localhost/articles';
if (mongoose.connection.readyState == 0) {
mongoose.connect(DB_URL, {
useMongoClient: true
});
}
let conditions = {
title: userObj.title
};
let options = {
upsert: true,
new: true,
setDefaultsOnInsert: true
};
Article.findOneAndUpdate(conditions, userObj, options, (err, result) => {
if (err) throw err;
});
}
Я не могу проверить код, не зная истинного значения https://www.somesite.com
, поэтому дайте мне знать, дает ли код новые ошибки.