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]); }); }); }); };


2 回复

根据你提供的错误信息和代码,问题可能出在 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]);
            });
        });
    });
};

解释

  1. 错误处理:在提取标题时,我们添加了一个检查条件 if ($th.length > 0),以确保只有存在 <th> 元素的情况下才将其文本内容添加到 titles 数组中。
  2. 调试信息:通过打印 topics 数组中的第一个元素,我们可以更好地理解 Cheerio 解析的结果。
  3. 性能优化:使用 .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”的错误。

回到顶部