刚学Nodejs不久,写了个抓页面的,但是返回不了结果。求大神指正

刚学Nodejs不久,写了个抓页面的,但是返回不了结果。求大神指正

这个是Server,客户端会用Ajax请求这个地方 // Nodejs部分,主要作用是接收前端关键词,抓取百度知道页面。返回页面给前端 var http = require(‘http’); var cheerio = require(‘cheerio’); var iconv = require(‘iconv-lite’); http.createServer(function (req, res) { res.writeHead(200, { ‘Content-Type’: ‘text/html’, ‘Access-Control-Allow-Origin’ : ‘*’ }); var postData = “”; var ret = 0; req.setEncoding(‘utf-8’); req.addListener(‘data’, function(chunk){ postData += chunk; }); req.addListener(‘end’, function(){ var value = postData.replace(/kw=/, ‘’), result = 0; doRequest(value, 0); }); res.end(’{“rank”:’+result+’}’); }).listen(10088);

这个是当server端得到数据后,会请求这个doRequest方法,这里面会去抓百度的页面,计算出关键词排的在第几返回出来。 var doRequest = function(kw, page){ page = page * 10; var options = { host: ‘zhidao.baidu.com’, port: 80, path: ‘/search?word=’+kw+’&pn=’+page }; http.get(options, function(res) { var buffers = [], size = 0; res.on(‘data’, function(buffer) { buffers.push(buffer); size += buffer.length; }); res.on(‘end’, function() { var buffer = new Buffer(size), pos = 0; for(var i = 0, l = buffers.length; i < l; i++) { buffers[i].copy(buffer, pos); pos += buffers[i].length; } var gbk_buffer = iconv.decode(buffer,‘GBK’); $ = cheerio.load(gbk_buffer.toString()); // 获取页面前三个的优质回答 var target = “DARRY RING”; var isBreak = false; var htmlTop = $("#cluster-items").find(".con-all").slice(0, 3); htmlTop.each(function(){ var tContent = $(this).text().replace(/\s+/g, “”); tContent = tContent.toLowerCase(); if (tContent.indexOf(“darryring”) > 0 ){ // 当找到DY的时候,退出循环 isBreak = true; return false; } }); if (isBreak == true){ return {keyword : kw, score : 1}; } var html = $("#wgt-list").find(“dd.answer”); var n = 0; html.each(function(i, elem){ var content = $(this).text().replace(/\s+/g, “”); content = content.toLowerCase(); if (content.indexOf(“darryring”) > 0 && n <= html.length ){ n = i + 1; return false; } }); if(n == 0){ page++; if (page < 5){ doRequest(kw, page); }else{ return {keyword : kw, score : 9999}; } }else{ var num = page + n; return {keyword : kw, score : num}; } }); res.on(‘error’, function(e){ console.log("Got error: " + e.message); }) }) }

现在就是调试的时候,doRequest里面都成功了,但是不返回到客户端。求指正啊,我要怎么改?以前没写过异步


2 回复

根据你描述的情况,问题可能出在异步操作上。在Node.js中,处理异步操作需要特别注意回调函数和异步流程控制。你的doRequest方法中的逻辑是异步执行的,而你试图立即返回结果。你需要确保在所有异步操作完成后才返回结果。

以下是一个改进后的示例代码,使用回调函数来处理异步操作,并确保返回结果:

var http = require('http');
var cheerio = require('cheerio');
var iconv = require('iconv-lite');

http.createServer(function (req, res) {
    res.writeHead(200, {'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*'});
    var postData = "";
    req.setEncoding('utf-8');
    req.on('data', function(chunk) {
        postData += chunk;
    });
    req.on('end', function() {
        var value = postData.replace(/kw=/, '');
        doRequest(value, 0, function(result) {
            res.end(JSON.stringify({rank: result}));
        });
    });
}).listen(10088);

var doRequest = function(kw, page, callback) {
    page = page * 10;
    var options = {
        host: 'zhidao.baidu.com',
        port: 80,
        path: '/search?word=' + encodeURIComponent(kw) + '&pn=' + page
    };
    http.get(options, function(res) {
        var buffers = [], size = 0;
        res.on('data', function(buffer) {
            buffers.push(buffer);
            size += buffer.length;
        });
        res.on('end', function() {
            var buffer = Buffer.concat(buffers, size);
            var gbk_buffer = iconv.decode(buffer, 'GBK');
            var $ = cheerio.load(gbk_buffer.toString());
            
            var target = "DARRY RING";
            var isBreak = false;
            var htmlTop = $("#cluster-items").find(".con-all").slice(0, 3);
            htmlTop.each(function() {
                var tContent = $(this).text().replace(/\s+/g, "");
                tContent = tContent.toLowerCase();
                if (tContent.indexOf(target.toLowerCase()) > -1) {
                    isBreak = true;
                    return false;
                }
            });

            if (isBreak) {
                callback({keyword: kw, score: 1});
                return;
            }

            var html = $("#wgt-list").find("dd.answer");
            var n = 0;
            html.each(function(i, elem) {
                var content = $(this).text().replace(/\s+/g, "");
                content = content.toLowerCase();
                if (content.indexOf(target.toLowerCase()) > -1 && n <= html.length) {
                    n = i + 1;
                    return false;
                }
            });

            if (n == 0) {
                page++;
                if (page < 5) {
                    doRequest(kw, page, callback);
                } else {
                    callback({keyword: kw, score: 9999});
                }
            } else {
                var num = page + n;
                callback({keyword: kw, score: num});
            }
        });
    }).on('error', function(e) {
        console.log("Got error: " + e.message);
    });
};

解释

  1. HTTP Server:

    • req.on('end')回调中调用doRequest方法,并传递一个回调函数callback
    • doRequest的回调函数中,使用res.end发送最终结果。
  2. doRequest:

    • 使用http.get进行异步请求。
    • res.on('end')回调中处理响应数据。
    • 使用Buffer.concat合并缓冲区。
    • 使用iconv.decode解码GBK编码的数据。
    • 使用cheerio解析HTML。
    • 在完成所有处理后,调用callback函数返回结果。

通过这种方式,你可以确保在所有异步操作完成后才返回结果。


根据你的描述,问题出在 doRequest 方法的异步调用上。由于 http.get 是一个异步操作,所以在 doRequest 方法中没有直接返回结果。你需要使用回调函数来处理异步操作的结果,并将其传递回客户端。

以下是修改后的代码示例:

var http = require('http');
var cheerio = require('cheerio');
var iconv = require('iconv-lite');

http.createServer(function (req, res) {
    res.writeHead(200, {'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*'});

    var postData = "";
    req.setEncoding('utf-8');
    req.on('data', function(chunk) {
        postData += chunk;
    });

    req.on('end', function() {
        var value = postData.replace(/kw=/, '');
        doRequest(value, 0, function(result) {
            res.end(JSON.stringify({rank: result}));
        });
    });
}).listen(10088);

var doRequest = function(kw, page, callback) {
    page = page * 10;
    var options = {
        host: 'zhidao.baidu.com',
        port: 80,
        path: '/search?word=' + encodeURIComponent(kw) + '&amp;pn=' + page
    };

    http.get(options, function(res) {
        var buffers = [], size = 0;
        res.on('data', function(buffer) {
            buffers.push(buffer);
            size += buffer.length;
        });

        res.on('end', function() {
            var buffer = Buffer.concat(buffers, size);
            var gbk_buffer = iconv.decode(buffer, 'GBK');
            var $ = cheerio.load(gbk_buffer.toString());

            var isBreak = false;
            var htmlTop = $("#cluster-items").find(".con-all").slice(0, 3);
            htmlTop.each(function() {
                var tContent = $(this).text().replace(/\s+/g, "");
                tContent = tContent.toLowerCase();
                if (tContent.indexOf("darryring") > -1) {
                    isBreak = true;
                    return false;
                }
            });

            if (isBreak) {
                callback({keyword: kw, score: 1});
                return;
            }

            var html = $("#wgt-list").find("dd.answer");
            var n = 0;
            html.each(function(i, elem) {
                var content = $(this).text().replace(/\s+/g, "");
                content = content.toLowerCase();
                if (content.indexOf("darryring") > -1 && n <= html.length) {
                    n = i + 1;
                    return false;
                }
            });

            if (n == 0) {
                var nextPage = page + 10;
                if (nextPage < 50) {
                    doRequest(kw, nextPage, callback);
                } else {
                    callback({keyword: kw, score: 9999});
                }
            } else {
                var num = page + n;
                callback({keyword: kw, score: num});
            }
        });

        res.on('error', function(e) {
            console.log("Got error: " + e.message);
            callback({keyword: kw, score: 9999});
        });
    });
};

解释

  1. 回调函数:在 doRequest 中添加了一个回调函数 callback,用于处理异步操作的结果,并将其传递回客户端。
  2. 异步操作:在 http.get 的回调中处理异步操作的结果,并调用 callback 函数将结果传递回去。
  3. 编码处理:使用 Buffer.concat 替换原有的手动拼接 Buffer 的方式,使代码更简洁。

通过这种方式,你可以确保异步操作的结果能够正确地返回到客户端。

回到顶部