#node.js #web-scraping #promise #request #cheerio
#node.js #очистка веб-страниц #обещание #запрос #приветствую
Вопрос:
Я создал скрипт, node
использующий promise
в сочетании с request
и cheerio
для анализа столбца links
under Province
с этой веб-страницы, затем повторно использую эти ссылки, чтобы очистить все URL-адреса under Office
column со всех таких страниц и, наконец, использовать их links
для сбора title
со всех таких целевых страниц, как Cairos main Post Office
на этой странице.
Мой текущий скрипт в большинстве случаев застревает. Однако иногда он выдает эту ошибку UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'parent' of undefined
. Я проверил каждую из функций и обнаружил, что все они работают правильно по отдельности.
Хотя скрипт выглядит немного больше, он построен на очень простой логике, которая заключается в использовании каждой links
целевой страницы, пока она не достигнет title
целевой страницы.
Это моя попытка до сих пор:
const request = require('request');
const cheerio = require('cheerio');
const link = 'https://www.egyptcodebase.com/en/p/all';
const base_link = 'https://www.egyptcodebase.com/en/';
const items = [];
const nitems = [];
let getLinks = () => {
return new Promise((resolve, reject) => {
request(link, function(error, response, html) {
let $ = cheerio.load(html);
if (error) return reject(error);
try {
$('.table tbody tr').each(function() {
items.push(base_link $(this).find("a").attr("href"));
});
resolve(items);
} catch (e) {
reject(e);
}
});
});
};
let getData = (links) => {
const promises = links
.map(nurl => new Promise((resolve, reject) => {
request(nurl, function(error, response, html) {
let $ = cheerio.load(html);
if (error) return reject(error);
try {
$('.table tbody tr').each(function() {
nitems.push(base_link $(this).find("a").attr("href"));
});
resolve(nitems);
} catch (e) {
reject(e);
}
})
}))
return Promise.all(promises)
}
let FetchData = (links) => {
const promises = links
.map(nurl => new Promise((resolve, reject) => {
request(nurl, function(error, response, html) {
let $ = cheerio.load(html);
if (error) return reject(error);
try {
resolve($(".home-title > h2").eq(0).text());
} catch (e) {
reject(e);
}
})
}))
return Promise.all(promises)
}
getLinks().then(resultList => {
getData(resultList).then(resultSet => {
FetchData(resultSet).then(title =>{
console.log(title);
})
})
})
Как я могу удалить заголовки с целевых страниц, используя все ссылки с целевых страниц?
Комментарии:
1. Пожалуйста, будьте осторожны с сервером, с которого вы удаляете, он не может обрабатывать сотни запросов одновременно, вот почему ваш скрипт застрял. Сначала
Cannot read property 'parent' of undefined
вы должны проверитьif(error)
, а затем выполнитьcheerio.load
.2. Брохер, я понял, в чем проблема
Ответ №1:
Было бы намного проще спросить владельца веб-сайта о данных, которые вам нужны.
Он может понять ваш запрос и предоставить его вам бесплатно, вместо того, чтобы очищать свой сайт.
P.S: Я был удивлен, обнаружив вопрос о том, как очистить мой собственный веб-сайт.
P.S2: Если вам просто нужны все заголовки почтовых отделений, я мог бы предоставить их вам бесплатно: D
P.S3: возможно, ваша ошибка возникает из-за того, что в течение некоторого времени на странице нет элемента, которыйвы пытаетесь выполнить синтаксический анализ с помощью cheerio.
Комментарии:
1. Мне вообще не нужны данные. Я использовал ссылку в качестве примера сайта. Все, что я хотел бы знать, это способ добиться того, что я пытался @Samy Massoud.
2. @robots.txt Затем проверьте P.S3 и распечатайте содержимое, которое у вас есть, чтобы убедиться, что элемент, который вы ищете, действительно существует в html
3. Мир тесен! Ха-ха: D
Ответ №2:
Итак, проблема в 2D
массиве. Если вы внимательно изучите свою getData
функцию, вы вернете 2D-массив.
map
верните массив, и внутри этой карты вы разрешаете другой массив nitems
.
Вот рабочий код:
const base_link = 'https://www.egyptcodebase.com/en/';
// helper wrapper DRY
const getHtmls = (url) => {
return new Promise((resolve, reject) => {
request({ uri: url, method: 'GET', followAllRedirects: true } , function(error, response, html) {
if (error) reject(error);
else resolve(html);
});
})
}
let getLinks = async () => {
const link = 'https://www.egyptcodebase.com/en/p/all';
const items = [];
try {
const html = await getHtmls(link);
let $ = cheerio.load(html);
$('.table tbody tr').each(function() {
items.push(base_link $(this).find("a").attr("href"));
});
} catch (e) {
// handling error here so execution can continue for good eggs
console.error(e.message)
}
return items;
};
let getData = async (links) => {
const out = [];
try {
const promises = links.map(nurl => getHtmls(nurl));
const htmls = await Promise.all(promises);
htmls.forEach(html => {
let $ = cheerio.load(html);
$('.table tbody tr').each(function() {
out.push(base_link $(this).find("a").attr("href"));
});
})
} catch (e) {
// handling error here so execution can continue for good eggs
console.error(e.message)
}
return out;
}
let FetchData = async (links) => {
const out = [];
try {
const promises = links.map(nurl => getHtmls(nurl));
const htmls = await Promise.all(promises)
htmls.forEach(html => {
try {
let $ = cheerio.load(html);
out.push($(".home-title > h2").eq(0).text());
} catch (e){
// handling error here so execution can continue for good eggs
console.error(e.message)
}
})
} catch (e) {
// handling error here so execution can continue for good eggs
console.error(e.message)
}
return out;
}
getLinks().then(resultList => {
getData(resultList).then(resultSet => {
FetchData(resultSet).then(title =>{
console.log(title);
})
})
})
Примечание: вместо написания собственной Promise
оболочки вы можете использовать request-promise
package
Комментарии:
1. Я исправил свой скрипт так, как вы предложили, и запустил его. Тем не менее, он все равно застревает. После выполнения я часами ждал какого-либо результата, но он ничего не напечатал @1556089774. Можете ли вы подсказать, где я ошибаюсь? Это исправленный скрипт . Спасибо.
2. @robots.txt обновленный ответ, проверьте (я не смог протестировать все ~ 540 ссылок, проблема с сетью), дайте мне знать, работает ли это
3. Я ждал полчаса после выполнения предложенного вами скрипта, но он все еще зависает. Должен ли я ждать больше? Я собираюсь наградить эту награду за ваш ответ, и я надеюсь, что вы посмотрите, что происходит. Спасибо.
4.@robots.txt некоторый рефакторинг и некоторые изменения, протестированные и работающие (похоже, что некоторые htmlsне
".home-title > h2"
' Exhibits Island Post Office', ' Kafr Moyes Post Office', '',
замечают, что третья запись является пустой строкой в одинарных кавычках). Проверено на всех ~ 540 URL-адресах. Также похоже, что сервер не справляется с нагрузкой. (частый сброс соединения) @SamyMassoud извините за бомбардировку вашего сайта, пришлось сделать это для тестирования 🙂
Ответ №3:
Проблема с вашим кодом заключается в функции fetchData, так как в этой функции вы передаете ссылки, а затем используете map поверх нее. Но если вы заглянете внутрь этой функции map и проверите значение переменной ‘nurl’, это будет массив ссылок, а его тип данных будет object. Согласно семантике функции запроса, ее первым параметром должна быть строка, поэтому, если вы выполните итерацию по переменной ‘nurl’, чтобы получить значения, тогда это сработает.