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
相关产品推荐
相关产品推荐

