You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PhantomJS includeJs报错:TypeError: page.includeJs is not a function

解决PhantomJS爬取时的两个常见问题

我来帮你搞定这两个问题,其实都是因为你用的Node.js版PhantomJS封装(phantom-node)的API和传统PhantomJS有差异导致的,咱们一步步来解决:

问题1:TypeError: page.includeJs is not a function 报错

传统PhantomJS的page.includeJs是回调式的,但你用的phantom-node库已经改成了Promise风格的API,这个方法要么被移除了,要么用法完全变了。更推荐的做法是用page.addScriptTag来加载外部脚本(比如jQuery),这个方法返回Promise,完美适配你现在的链式写法。

问题2:exit() was called before waiting for commands to finish 警告

这个警告是因为你过早调用了exit()——不管是在catch里直接调用,还是正常流程里没等所有异步操作做完就退出,都会触发这个问题。正确的做法是用Promise的finally块来统一处理资源清理,确保所有爬取操作完成后,再关闭页面并退出PhantomJS。

修正后的完整代码

app.get('/scrape', function(req, res) {
    let _ph, _page;
    phantom.create()
        .then(function(ph) {
            _ph = ph;
            return ph.createPage();
        })
        .then(function(page) {
            _page = page;
            const url = "https://banc.nl/";
            return page.open(url);
        })
        .then(function(status) {
            // 先确认页面是否成功打开
            if (status !== 'success') {
                throw new Error('页面打开失败');
            }
            // 用addScriptTag加载jQuery,返回Promise
            return _page.addScriptTag({ url: 'http://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js' });
        })
        .then(function() {
            // 在浏览器环境里执行DOM解析
            return _page.evaluate(function() {
                // 注意你的选择器写错了!两个class要连在一起写
                const targetElements = $('.sc-dnqmqq.kaMmif');
                const prices = [];
                targetElements.each(function() {
                    const priceText = $(this).children().first().text();
                    console.log("Price: " + priceText);
                    prices.push(priceText);
                });
                // 把爬取到的数据传回Node.js环境
                return prices;
            });
        })
        .then(function(scrapedPrices) {
            // 这里拿到爬取结果,可以返回给前端
            console.log('爬取到的价格:', scrapedPrices);
            res.json({ success: true, data: scrapedPrices });
        })
        .catch(function(err) {
            console.log("出错了: ", err);
            res.status(500).json({ success: false, error: err.message });
        })
        .finally(function() {
            // 不管成功失败,都要清理资源
            if (_page) {
                _page.close().catch(err => console.log('关闭页面出错:', err));
            }
            if (_ph) {
                _ph.exit().catch(err => console.log('退出PhantomJS出错:', err));
            }
        });
});

额外注意点

  • 选择器修正:你原来的$('.sc-dnqmqq kaMmif')是错误的写法,两个类选择器之间不能有空格,应该写成$('.sc-dnqmqq.kaMmif'),否则会被解析为找.sc-dnqmqq下的kaMmif标签,这肯定不是你要的。
  • 数据传递:page.evaluate里的代码是在浏览器沙箱里运行的,不能直接访问Node.js的变量,所以要把爬取到的数据return出来,在后面的then块里接收。
  • 资源清理:用finally块处理页面关闭和PhantomJS退出,能确保所有异步操作完成后再执行清理,彻底解决exit过早调用的警告。

内容的提问来源于stack exchange,提问作者Fogarasi Norbert

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 06:27:15