Nodejs中expressjs与phantom联合使用报错,求解

Nodejs中expressjs与phantom联合使用报错,求解

首先在此强调一下,我不想用phantomjs-node 这种node包,这种包我也试了,也有很多问题。我是按照如下方式实现的

我想用nodejs实现一个抓取网页的功能,抓取网页我用phantomjs,然后我用node去执行phantomjs的代码,

现在phantomjs抓取网页的代码如下。 #

    var page = require('webpage').create(),
    system = require('system'),
    t, address;
if (system.args.length === 1) {
     phantom.exit(1);
} 
else {
    t = Date.now();
    address = system.args[1];
    page.open(address, function (status) {
    if (status !== 'success') {
         /*console.log('FAIL to load the address');*/
    } else {
        t = Date.now() - t;
        console.log(/*'Page title is ' +*/ page.evaluate(function () {
        var head = document.getElementsByTagName("head")[0]
        var basee = document.createElement("base")
        basee.href = document.location.origin

        head.insertBefore(basee, head.firstChild);
        return document.head.innerHTML + document.body.innerHTML;
    }));
    /*console.log('Loading time ' + t + ' msec');*/
}
phantom.exit();

}); }

在nodejs中,我用child_process去执行,代码如下

     var child_process = require('child_process');
     var events = require('events');
 exports.GetPageVisual = function (url, callback) {

var emitter = new events.EventEmitter();

setTimeout(function () { child = child_process.spawn(‘phantomjs’, [‘getPage.js’, url]); child.stdout.setEncoding(‘utf8’); child.stdout.on(“data”, function (data) { emitter.emit(“success”, data); }); child.stderr.on(‘data’, function (data) { emitter.emit(“error”, data); });

child.on('exit', function (code, signal) {
    emitter.emit("exit", code);
});

}, 100)

return emitter;

}

我用如下测试代码,去抓取网页,可以正常使用

        var _util=require("./util");

_util.GetPageVisual(“http://blog.miaozhuang.net”).on(“success”,function(d){ console.log(d); }) .on(“error”, function (err) { console.log(err);

})
.on("exit",function(d){
    console.log('子进程已退出,代码:' + d);
})

但是我把这段代码放到expressjs的请求中时候,却会报错,代码执行了error中的函数

err返回值为:<Buffer 43 61 6e 27 74 20 6f 70 65 6e 20 27 67 65 74 50 61 67 65 2e 6a 73        27 0d 0a>

子进程已退出,代码:-1

求解!!!!!!!!!!!!!!!!!!!!!!!!

 exports.getPage = function (req, res) {
 params.page=req.params.url

_util.GetPageVisual(params.page) .on(“success”, function (d) { res.send(d);

})
.on("error", function (err) {
    console.log("error":err);

})
.on("exit",function(d){
    console.log('子进程已退出,代码:' + d);
})

/*getPage(params.page).on(“success”, function (d) { res.send(d); }) */

};


3 回复

根据你的描述,问题可能出在 ExpressJS 和 PhantomJS 的异步处理上。具体来说,在 ExpressJS 中,请求处理函数需要尽快完成,否则可能会导致超时或其他错误。你提到的错误信息表明 PhantomJS 子进程无法正常启动或执行。

为了帮助你解决问题,我们可以做一些调整来确保子进程能够正确启动并处理请求。

示例代码

getPage.js (PhantomJS 脚本)

var page = require('webpage').create(),
    system = require('system'),
    t, address;

if (system.args.length === 1) {
    phantom.exit(1);
} else {
    t = Date.now();
    address = system.args[1];
    page.open(address, function (status) {
        if (status !== 'success') {
            console.error('FAIL to load the address');
        } else {
            t = Date.now() - t;
            console.log(page.evaluate(function () {
                var head = document.getElementsByTagName("head")[0]
                var basee = document.createElement("base")
                basee.href = document.location.origin
                head.insertBefore(basee, head.firstChild);
                return document.head.innerHTML + document.body.innerHTML;
            }));
        }
        phantom.exit();
    });
}

util.js (NodeJS 模块)

var child_process = require('child_process');
var events = require('events');

exports.GetPageVisual = function (url, callback) {
    var emitter = new events.EventEmitter();

    setTimeout(function () {
        var child = child_process.spawn('phantomjs', ['getPage.js', url]);
        child.stdout.setEncoding('utf8');
        child.stdout.on("data", function (data) {
            emitter.emit("success", data);
        });
        child.stderr.on('data', function (data) {
            emitter.emit("error", data);
        });

        child.on('exit', function (code, signal) {
            emitter.emit("exit", code);
        });
    }, 100);

    return emitter;
};

app.js (ExpressJS 应用)

const express = require('express');
const app = express();
const _util = require('./util');

app.get('/get-page', (req, res) => {
    const url = req.query.url; // 使用 query 参数获取 URL
    if (!url) {
        return res.status(400).send('URL 参数缺失');
    }

    _util.GetPageVisual(url)
        .on("success", function (d) {
            res.send(d);
        })
        .on("error", function (err) {
            console.error('Error:', err);
            res.status(500).send('请求失败');
        })
        .on("exit", function (d) {
            console.log('子进程已退出,代码:' + d);
        });
});

app.listen(3000, () => {
    console.log('服务器运行在 http://localhost:3000');
});

解释

  1. PhantomJS 脚本 (getPage.js):

    • 确保脚本能够正确处理页面加载状态,并输出页面内容。
  2. NodeJS 模块 (util.js):

    • 使用 child_process.spawn 来启动 PhantomJS 子进程,并捕获其标准输出和标准错误流。
    • 使用事件发射器 (EventEmitter) 来处理成功、错误和退出事件。
  3. ExpressJS 应用 (app.js):

    • 定义一个 GET 请求处理函数 /get-page,从查询参数中获取 URL。
    • 使用 GetPageVisual 方法来启动 PhantomJS 子进程,并处理其输出。
    • 如果发生错误,则返回 500 错误状态码。

通过这种方式,你可以确保 ExpressJS 请求处理函数能够正确处理异步操作,并且不会因为超时等问题而失败。希望这能解决你的问题!


phantomjs 工程下有 rasterize.js 这个文件, 直接使用这里面的代码吧 还有就是child.stdout.setEncoding(‘utf8’); 不知道有没有什么问题

根据你的描述,错误信息表明子进程无法打开 getPage.js 文件。这可能是因为文件路径不正确或文件权限问题。

你可以尝试以下几个步骤来解决这个问题:

  1. 确保文件路径正确: 确保 getPage.js 文件位于 Node.js 应用程序的根目录或相对于当前工作目录的正确路径。

  2. 检查文件权限: 确保 getPage.js 文件具有可执行权限。你可以在命令行中运行以下命令来设置权限:

    chmod +x getPage.js
    
  3. 使用绝对路径: 使用绝对路径来指定 getPage.js 文件的位置,以避免路径解析问题。

    child_process.spawn('/absolute/path/to/phantomjs', ['/absolute/path/to/getPage.js', url]);
    

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

exports.getPage = function (req, res) {
    const params = req.params;
    const url = params.url;

    _util.GetPageVisual(url)
        .on("success", function (d) {
            res.send(d);
        })
        .on("error", function (err) {
            console.error("Error:", err.toString());
            res.status(500).send("An error occurred while fetching the page.");
        })
        .on("exit", function (code) {
            console.log('子进程已退出,代码:' + code);
        });
};

通过这些步骤,你应该能够解决报错问题,并成功抓取网页。如果问题仍然存在,请检查日志输出以获取更多详细信息。

回到顶部