繁体   English   中英

Node.js 应用程序在本地运行,但在部署到 heroku 时出现应用程序错误

[英]Node.js app works locally but when deploy to heroku I get application error

我为现场体育比分构建了一个网络爬虫。 我有 2 个文件,一个用作服务器的 index.js 和一个执行抓取的 scraper.js 文件。 这是我的 index.js 文件代码:

const express = require('express');

const scraper = require('./util/scraper');

const app = express();

app.get('/scores', (req, res) => {
    const scores = new Promise((resolve, reject) => {
        scraper
         .scrapeLiveScores()
         .then(data => {
             resolve(data)
        }).catch(err => reject('scores scrape failed'))
    });

    // res.send(JSON.stringify(scores));
    // Use promise.all([]) if more than one scraper is used and list each of them
    Promise.resolve(scores)
     .then(data => {
         res.send(JSON.stringify(data));
     }).catch(function() {
         console.log("promise rejected");
     });
});

app.set( 'port', ( process.env.PORT || 5000 ));

// Start node server
app.listen( app.get( 'port' ), function() {
  console.log( 'Node server is running on port ' + app.get( 'port' ));
  });
module.exports = app;

当我在本地运行 heroku 时,它会返回我需要的数据的 json。 但是当我将它部署到 heroku 时,我收到一个应用程序错误,控制台日志为“承诺被拒绝”。

const puppeteer = require('puppeteer');


const scrapeLiveScores = async () => {
    try{
        //Open the browser
        var browser = await puppeteer.launch({ headless: true });

        //Open a new page
        var page = await browser.newPage();

        //Enter url in the page
        await page.goto('https://www.flashscore.com.au/basketball/usa/nba/');

        //wait for selector to load in
        await page.waitForSelector('div.event__score.event__score--home');

        var scores = await page.evaluate(() => {
            var basePath = 'div.leagues--live > div > div.event__match';
            var homeScore = document.querySelectorAll('div.leagues--live > div > div.event__match > div.event__score--home');
            var awayScore = document.querySelectorAll('div.leagues--live > div > div.event__match > div.event__score--away');
            var homeTeam = document.querySelectorAll('div.leagues--live > div > div.event__match > div.event__participant.event__participant--home');
            var awayTeam = document.querySelectorAll('div.leagues--live > div > div.event__match > div.event__participant.event__participant--away');
            var stages = document.querySelectorAll('div.leagues--live > div > div.event__match > div.event__stage > div');


            //#g_3_6LLArB7N > div.event__stage > div
            var scoresArray = [];

            for(var i = 0; i < homeScore.length; i++){

                if(stages[i] != null){
                    scoresArray[i] = {
                        homeTeam: homeTeam[i].innerText.trim(),
                        homeScore: homeScore[i].innerText.trim(),
                        awayTeam: awayTeam[i].innerText.trim(),
                        awayScore: awayScore[i].innerText.trim(),
                        stage: stages[i].innerText.trim()
                    };
                }else{
                    scoresArray[i] = {
                        homeTeam: homeTeam[i].innerText.trim(),
                        homeScore: homeScore[i].innerText.trim(),
                        awayTeam: awayTeam[i].innerText.trim(),
                        awayScore: awayScore[i].innerText.trim(),
                        stage: "-"
                    };
                }

            }

            return scoresArray;
        });

        console.log(scores);
        await browser.close();
        return scores;
    }catch(err){

        await browser.close();
    }
}

module.exports.scrapeLiveScores = scrapeLiveScores;

我已经坚持了几个小时。 这是日志:

2019-12-30T08:06:23.178178+00:00 app[web.1]: scraper error TypeError: Cannot read property 'close' of undefined
2019-12-30T08:06:23.178216+00:00 app[web.1]:     at Object.scrapeLiveScores (/app/util/scraper.js:60:23)
2019-12-30T08:06:23.178218+00:00 app[web.1]:     at processTicksAndRejections (internal/process/task_queues.js:93:5)
2019-12-30T08:06:23.182971+00:00 heroku[router]: at=info method=GET path="/scores" host=nbalive-api.herokuapp.com request_id=7f5b79cc-dd2e-433b-a4db-56052f8a5cdd fwd="99.247.208.27" dyno=web.1 connect=1ms service=23ms status=500 bytes=231 protocol=https

第 60 行是 catch(err){await browswer.close()}

要调试这个问题,你需要记录你得到的实际错误。 而且,当你在做的时候,简化代码并删除将现有承诺包装在另一个不必要的承诺中的承诺反模式。

把代码改成这样:

app.get('/scores', (req, res) => {
    scraper.scrapeLiveScores().then(data => {
         res.send(data);
    }).catch(function(e) {
         console.log("scraper error", e);
         res.status(500).send("scraper error");
     });
});

然后.catch()中的console.log()语句将显示您得到的确切错误。

除了删除承诺反模式,简化代码并记录您获得的实际错误并消除由res.send()自动完成的JSON.stringify() res.send() ,这还会在出现错误时向请求发送响应而不是让浏览器挂起。

我没有使用过刮刀,但我已经在 Heroku 上成功使用了 Cheerio 和 Puppeteer:

const puppeteer = require('puppeteer');

const $ = require('cheerio');

exports.scraper = (req, res) => {
  const url = 'https://www.my-target-url.com';
  puppeteer
    .launch()
    .then(function(browser) {
      return browser.newPage();
    })
    .then(function(page) {
      return page.goto(url).then(function() {
        return page.content();
      });
    })
    .then(function(html) {
      // target a css selector
      $('#my_selector', html).each(function() {

        console.log($(this).text());
        res.send($(this).text());
      });
    })
    .catch(function(err) {
      //handle error
    });
};

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM