Search code examples
pythonpython-3.xflaskgithubheroku

Address already in use, but run normally on Python Shell


So I was making a bot, a Reddit bot, that is going to live on Heroku, but as of deployment, problem arise. The build went smoothly, until I was going to view the app, Application Error shows up. As it turns out, I got OSError: [Errno 98] Address already in use, but everything was running smoothly on my Python shell. Here is my code + structure: Folder structure

app.py:

import praw
import Levenshtein
import os
from bs4 import BeautifulSoup as bs
import requests
def g(url):
    r = requests.get(url)
    if r.status_code == 404:
        raise Exception
    page = r.text
    
    soup=bs(page,'html.parser')
    
    soup = soup.find('ul',{'class':'music_list clearfix'})
    
    soup = soup.find_all('li')
    
    return [[i.find('a')['href'],i.find('p').contents[0],i.find('h3').contents[0]] for i in soup]
def k():
    h = 1
    l = []
    while 1:
        try:
            l+=g('https://hololive.hololivepro.com/en/music?paged=%d' % h)
            h+=1
        except:
            break
    return l
from flask import Flask
from threading import Thread

app = Flask('')

@app.route('/')
def home():
    return "Server Alive!"

def run():
  app.run(host='localhost',port=8080)

def keep_alive():
    t = Thread(target=run)
    t.start()
reddit = praw.Reddit(
    client_id="******",
    client_secret="*******",
    user_agent="web:mv_bot:v0.1 (by u/khang1411)",
    username="khang1411_bot",
    password='*******',
)
def comp(w1,w2):
  w2 = w2.lower()
  w1 = w1.lower()
  if w1 in w2:
    return 1
  w2 = ''.join(ch for ch in w2 if ch.isalnum() or ch == ' ')
  w1 = ''.join(ch for ch in w1 if ch.isalnum() or ch == ' ')
  l = 0
  for i in w2.split():
    j = Levenshtein.ratio(w1,i)
    if j>l:
      l=j
  j = Levenshtein.ratio(w1,w2)
  if j > l:
    l = j
  return l
def form(l,mode,other):
  if mode == 'author':
    return ('These are the songs that matched the author %s: \n\n' % other) +  '\n\n'.join(l) + '\n\n' + '^(This comment is made by a bot, if you have improvements/complaints please contact u/khang1411)'
  elif mode == 'title':
    return ('These are the songs that matched the title %s: \n\n' % other) +  '\n\n'.join(l) + '\n\n' + '^(This comment is made by a bot, if you have improvements/complaints please contact u/khang1411)'
def fromauthor(author):
  
  w = ['%s by %s at link %s' % (l[2],l[1],l[0]) for l in k() if comp(author,l[1]) > 0.85]
  return w
def fromtitle(title):
  w=  ['%s by %s at link %s' % (l[2],l[1],l[0]) for l in k() if comp(title,l[2]) > 0.85]
  return w
if __name__ == '__main__':
    keep_alive()
    subreddit = reddit.subreddit("test")
    for comment in subreddit.stream.comments(skip_existing=True):
      print(comment.body)
      if '!mv' in comment.body:
        try:
          if comment.body.split()[1] == 'author':
            comment.reply(form(fromauthor(' '.join(comment.body.split()[2:])),'author',' '.join(comment.body.split()[2:])))
              #comment.reply()
          elif comment.body.split()[1]=='title':
            comment.reply(form(fromtitle(' '.join(comment.body.split()[2:])),'title',' '.join(comment.body.split()[2:])))
        except:
          pass

The pip file + pipfile.lock was from pipenv,

Procfile:

web: gunicorn app:app 

Requirements.txt:

beautifulsoup4==4.9.3
certifi==2021.5.30
charset-normalizer==2.0.4
click==8.0.1
colorama==0.4.4
Flask==2.0.1
gunicorn==20.1.0
idna==3.2
itsdangerous==2.0.1
Jinja2==3.0.1
Levenshtein==0.13.0
MarkupSafe==2.0.1
praw==7.4.0
prawcore==2.3.0
requests==2.26.0
soupsieve==2.2.1
update-checker==0.18.0
urllib3==1.26.6
websocket-client==1.2.1
Werkzeug==2.0.1

Runtime.txt:

python-3.9.4

Running it on Repl.it and the Python shell works, but not on Heroku.

P/S: I deployed the Heroku app through GitHub, this is the image: enter image description here

I tried to change the host and the port, but not working. How can I fix this? Thanks,

P/S 2: Log: https://pastebin.com/CmhpWXTW


Solution

  • You don't get to decide what port to run on Heroku. Heroku will tell you the correct port to use via an ENV variable. You can get this and then run:

    port = int(os.environ.get("PORT", 5000))
    app.run(host='0.0.0.0', port=port)
    

    See the docs for more.