Nodejs之node-lessons的问题请教
Nodejs之node-lessons的问题请教
最近在学习大牛alsotang的案例(https://github.com/alsotang/node-lessons/tree/master/lesson4) 运行第四课中的案例可以正常得到数据,另外我尝试了另外一个网站也没有问题。但是抓取网站kijiji(http://www.kijiji.ca/b-immobilier/ville-de-montreal/c34l1700281?ad=wanted) 信息时遇到了报错Cannot read property ‘parent’ of undefined 。关于这个页面抓取,我可以确定首页面链接抓取没问题,单独抓取每个子页面信息也没问题。请问有没有遇到过类似问题的同学可以指点一下。谢谢
报错信息: [ERROR] 18:07:23 TypeError TypeError: Cannot read property ‘parent’ of undefined at Function.exports.update (C:\Users\zhi_xie\nodejs\neomovie\node_modules\ch eerio\lib\parse.js:55:25) at module.exports (C:\Users\zhi_xie\nodejs\neomovie\node_modules\cheerio\lib \parse.js:17:11) at Function.exports.load (C:\Users\zhi_xie\nodejs\neomovie\node_modules\chee rio\lib\static.js:19:14) at C:\Users\zhi_xie\nodejs\neomovie\routes\crawlerusers.js:49:25 at Array.forEach (native) at C:\Users\zhi_xie\nodejs\neomovie\routes\crawlerusers.js:45:23 at all (C:\Users\zhi_xie\nodejs\neomovie\node_modules\eventproxy\lib\eventpr oxy.js:388:20) at EventProxy.trigger (C:\Users\zhi_xie\nodejs\neomovie\node_modules\eventpr oxy\lib\eventproxy.js:175:22) at C:\Users\zhi_xie\nodejs\neomovie\routes\crawlerusers.js:62:12 at Request.callback (C:\Users\zhi_xie\nodejs\neomovie\node_modules\superagen t\lib\node\index.js:746:30)
代码如下:
var User = require('../models/user');
exports.crawlerusers = function (req, res, next) {
var eventproxy = require('eventproxy');
var superagent = require('superagent');
var cheerio = require('cheerio');
// url 模块是 Node.js 标准库里面的
// http://nodejs.org/api/url.html
var url = require('url');
var kijijiUrl = 'http://www.kijiji.ca/b-immobilier/ville-de-montreal/c34l1700281?ad=wanted';
superagent.get(kijijiUrl).end(function (err, res) {
if (err) {
return console.error(err);
}
var topicUrls = [];
var $ = cheerio.load(res.text);
// 获取首页所有的链接-成功!
$('div.container-results').children('table').each(function (idx, element) {
var $element = $(element);
// $element.attr('href') 本来的样子是 /topic/542acd7d5d28233425538b04
// 我们用 url.resolve 来自动推断出完整 url,变成
// https://cnodejs.org/topic/542acd7d5d28233425538b04 的形式
// 具体请看 http://nodejs.org/api/url.html#url_url_resolve_from_to 的示例
var href = url.resolve(kijijiUrl, $element.attr('data-vip-url'));
topicUrls.push(href);
});
console.log(topicUrls);
// 得到一个 eventproxy 的实例
var ep = new eventproxy();
// 命令 ep 重复监听 topicUrls.length 次(在这里也就是 21 次) `topic_html` 事件再行动
ep.after('topic_html', topicUrls.length, function (topics) {
// topics 是个数组,包含了 21 次 ep.emit('topic_html', pair) 中的那 21 个 pair
// 开始行动
//如果用第三课的方法直接抓取每个子页面的titles,可以成功!
topics = topics.map(function (topicPair) {
var topicUrl = topicPair[0];
var topicHtml = topicPair[1];
var $ = cheerio.load(topicHtml);
return ({
titles: $(‘table.ad-attributes’).find(‘tr’).not(’.divider’).children(‘th’).text().trim(),
});
});
console.log(topics[0]);
});
console.log("--------------------------------------------");
console.log(“Totally fetched " + topicUrls.length + " Urls”);
console.log("--------------------------------------------");
topicUrls.forEach(function (topicUrl) {
superagent.get(topicUrl).end(function (err, res) {
//console.log(‘fetch ’ + topicUrl + ’ successful’);
ep.emit(‘topic_html’, [topicUrl, res.text]);
});
});
});
};
根据你提供的错误信息和代码,问题可能出在 Cheerio 解析过程中某些元素未被正确找到,导致 undefined
被传递给 Cheerio 的解析方法。具体来说,错误发生在 Cheerio 的 update
方法中,提示无法读取 parent
属性。
问题分析
在你的代码中,你使用 Cheerio 来解析 Kijiji 页面的内容,并从中提取所需的数据。错误发生的原因可能是某些 HTML 结构与预期不符,导致 Cheerio 在解析时找不到预期的元素或属性。
示例代码修正
为了解决这个问题,我们可以添加一些错误处理逻辑,确保在提取数据之前检查元素是否存在。此外,我们可以打印一些调试信息来更好地理解 Cheerio 解析的结果。
var User = require('../models/user');
exports.crawlerusers = function (req, res, next) {
var eventproxy = require('eventproxy');
var superagent = require('superagent');
var cheerio = require('cheerio');
var url = require('url');
var kijijiUrl = 'http://www.kijiji.ca/b-immobilier/ville-de-montreal/c34l1700281?ad=wanted';
superagent.get(kijijiUrl).end(function (err, res) {
if (err) {
return console.error(err);
}
var topicUrls = [];
var $ = cheerio.load(res.text);
// 获取首页所有的链接
$('div.container-results').children('table').each(function (idx, element) {
var $element = $(element);
var href = url.resolve(kijijiUrl, $element.attr('data-vip-url'));
topicUrls.push(href);
});
console.log(topicUrls);
var ep = new eventproxy();
ep.after('topic_html', topicUrls.length, function (topics) {
topics = topics.map(function (topicPair) {
var topicUrl = topicPair[0];
var topicHtml = topicPair[1];
var $ = cheerio.load(topicHtml);
// 添加错误处理逻辑
var titles = [];
$('table.ad-attributes').find('tr').not('.divider').each(function () {
var $th = $(this).children('th');
if ($th.length > 0) {
titles.push($th.text().trim());
}
});
return {
titles: titles
};
});
console.log(topics[0]);
});
console.log("--------------------------------------------");
console.log("Totally fetched " + topicUrls.length + " Urls");
console.log("--------------------------------------------");
topicUrls.forEach(function (topicUrl) {
superagent.get(topicUrl).end(function (err, res) {
ep.emit('topic_html', [topicUrl, res.text]);
});
});
});
};
解释
- 错误处理:在提取标题时,我们添加了一个检查条件
if ($th.length > 0)
,以确保只有存在<th>
元素的情况下才将其文本内容添加到titles
数组中。 - 调试信息:通过打印
topics
数组中的第一个元素,我们可以更好地理解 Cheerio 解析的结果。 - 性能优化:使用
.each()
方法来遍历所有符合条件的行,而不是使用.map()
,这样可以更灵活地处理各种情况。
通过这些修改,你应该能够避免由于 Cheerio 解析错误导致的 TypeError
。希望这能解决你的问题。
从错误信息来看,问题出现在 Cheerio 库中,具体是在处理某个元素时找不到其父节点。这可能是由于 Kijiji 网站的 HTML 结构与预期不符导致的。
以下是针对这个问题的解决方案,调整部分代码以确保在处理元素之前检查其存在性:
topicUrls.forEach(function (topicUrl) {
superagent.get(topicUrl).end(function (err, res) {
if (err) {
console.error('Failed to fetch ' + topicUrl);
return;
}
ep.emit('topic_html', [topicUrl, res.text]);
});
});
// 在处理子页面内容之前,增加一个检查
ep.after('topic_html', topicUrls.length, function (topics) {
topics = topics.map(function (topicPair) {
var topicUrl = topicPair[0];
var topicHtml = topicPair[1];
var $ = cheerio.load(topicHtml);
var titles = [];
$('table.ad-attributes tr:not(.divider)').each(function () {
var $th = $(this).children('th');
if ($th.length > 0) { // 确保 th 存在
titles.push($th.text().trim());
}
});
return {
titles: titles
};
});
console.log(topics[0]);
});
通过添加对 $th
的检查,确保只有当 th
元素存在时才处理它。这样可以避免 Cheerio 抛出“Cannot read property ‘parent’ of undefined”的错误。