前提・実現したいこと
Python・flaskで作ったwebアプリをherokuでデプロイし成功したものの、URLに飛ぶとApplication errorとなってしまう。
プログラミング初心者です。分かりづらい点があるかと思います、ご容赦ください。
発生している問題・エラーメッセージ
エラーコードはH10。問題箇所と思われるメッセージはこちらです。
Failed to find attribute 'application' in 'app'.
該当のソースコード
該当ファイルの構成は以下です。
アプリのファイル
|ーーapp.py
|ーーProcfile
|ーーrequirements.txt
|ーーruntime.txt
|ーー__pycache__
|ーーtemplates
|ーーvenv
|ーー.env
|ーー.env.sample
□「heroku logs --tail --app 自分のアプリ名」の実行結果
2022-01-11T11:06:47.556703+00:00 heroku[web.1]: State changed from crashed to starting 2022-01-11T11:06:52.498156+00:00 heroku[web.1]: Starting process with command `gunicorn app : app --log-file -` 2022-01-11T11:06:53.838531+00:00 app[web.1]: [2022-01-11 11:06:53 +0000] [4] [INFO] Starting gunicorn 20.1.0 2022-01-11T11:06:53.838940+00:00 app[web.1]: [2022-01-11 11:06:53 +0000] [4] [INFO] Listening at: http://0.0.0.0:24665 (4) 2022-01-11T11:06:53.838980+00:00 app[web.1]: [2022-01-11 11:06:53 +0000] [4] [INFO] Using worker: sync 2022-01-11T11:06:53.842165+00:00 app[web.1]: [2022-01-11 11:06:53 +0000] [9] [INFO] Booting worker with pid: 9 2022-01-11T11:06:53.853462+00:00 app[web.1]: [2022-01-11 11:06:53 +0000] [10] [INFO] Booting worker with pid: 10 2022-01-11T11:06:54.366422+00:00 heroku[web.1]: State changed from starting to up 2022-01-11T11:06:55.711302+00:00 app[web.1]: Failed to find attribute 'application' in 'app'. 2022-01-11T11:06:55.711529+00:00 app[web.1]: [2022-01-11 11:06:55 +0000] [9] [INFO] Worker exiting (pid: 9) 2022-01-11T11:06:55.711605+00:00 app[web.1]: Failed to find attribute 'application' in 'app'. 2022-01-11T11:06:55.711847+00:00 app[web.1]: [2022-01-11 11:06:55 +0000] [10] [INFO] Worker exiting (pid: 10) 2022-01-11T11:06:56.299718+00:00 app[web.1]: [2022-01-11 11:06:56 +0000] [4] [WARNING] Worker with pid 10 was terminated due to signal 15 2022-01-11T11:06:56.395344+00:00 app[web.1]: [2022-01-11 11:06:56 +0000] [4] [INFO] Shutting down: Master 2022-01-11T11:06:56.395413+00:00 app[web.1]: [2022-01-11 11:06:56 +0000] [4] [INFO] Reason: App failed to load. 2022-01-11T11:06:56.557625+00:00 heroku[web.1]: Process exited with status 4 2022-01-11T11:06:56.610039+00:00 heroku[web.1]: State changed from up to crashed 2022-01-11T11:06:58.000000+00:00 app[api]: Build succeeded 2022-01-11T11:07:02.198343+00:00 heroku[router]: at=error code=H10 desc="App crashed" method=GET path="/" host=foodbook135.herokuapp.com request_id=fc34bf91-5ec2-44a0-ac3d-fc6e828ba59c fwd="106.154.137.195" dyno= connect= service= status=503 bytes= protocol=https 2022-01-11T11:07:02.822734+00:00 heroku[router]: at=error code=H10 desc="App crashed" method=GET path="/favicon.ico" host=foodbook135.herokuapp.com request_id=fe1c5296-7855-4f26-b958-f03f77e4fc6d fwd="106.154.137.195" dyno= connect= service= status=503 bytes= protocol=https
Procfile
web: gunicorn app : app --log-file -
requirements
beautifulsoup4==4.10.0 cachetools==4.2.4 certifi==2021.10.8 charset-normalizer==2.0.9 click==8.0.3 Flask==2.0.2 google-api-core==2.3.2 google-api-python-client==2.33.0 google-auth==2.3.3 google-auth-httplib2==0.1.0 googleapis-common-protos==1.54.0 gunicorn==20.1.0 httplib2==0.20.2 idna==3.3 itsdangerous==2.0.1 Jinja2==3.0.3 MarkupSafe==2.0.1 protobuf==3.19.1 pyasn1==0.4.8 pyasn1-modules==0.2.8 pyparsing==3.0.6 requests==2.26.0 rsa==4.8 six==1.16.0 soupsieve==2.3.1 uritemplate==4.1.1 urllib3==1.26.7 Werkzeug==2.0.2
app.py
# -*- coding: utf-8 -*- from bs4 import BeautifulSoup import re from flask import Flask, render_template, request, session import requests import settings from requests.exceptions import Timeout # 返却された検索結果の読み取りにつかう from googleapiclient.discovery import build # ================================= app = Flask(__name__) # カスタム検索エンジンID CUSTOM_SEARCH_ENGINE_ID = "87dabc623cf5e8624" # API キー API_KEY = settings.AP # APIにアクセスして結果をもらってくるメソッド def get_search_results(query): # APIでやりとりするためのリソースを構築 search = build( "customsearch", "v1", developerKey = API_KEY ) # Google Custom Search から結果を取得 result = search.cse().list( q = query, cx = CUSTOM_SEARCH_ENGINE_ID, lr = 'lang_ja', num = 5, start = 1 ).execute() # 受け取ったjsonをそのまま返却 return result # 検索結果の情報をSearchResultに格納してリストで返す def summarize_search_results(result): # 結果のjsonから検索結果の部分を取り出しておく result_items_part = result['items'] # 抽出した検索結果の情報はこのリストにまとめる result_items = [] # 今回は (start =) 1 個目の結果から (num =) 10 個の結果を取得した for i in range(0, 5): # i番目の検索結果の部分 result_item = result_items_part[i] # i番目の検索結果からそれぞれの属性の情報をResultクラスに格納して # result_items リストに追加する s_r = SearchResult( title = result_item['title'], url = result_item['link'], snippet = result_item['snippet'] ) result_items.append(s_r.Making_d()) # 結果を格納したリストを返却 return result_items # 検索結果の情報を格納するクラス class SearchResult: def __init__(self, title, url, snippet): self.title = title self.url = url self.snippet = snippet def __str__(self): # コマンドライン上での表示形式はご自由にどうぞ return "[title] " + self.title + "\n\t[detail] " + self.snippet + "\n\t[url]" + self.url def Making_d(self): d_info = dict(title=self.title, url=self.url, detail=self.snippet) return d_info # htmlとやり取りするパート app = Flask(__name__) app.secret_key = 'abcdefghijklmn' @app.route('/', methods=['GET']) def get(): return render_template('index.html') # フォームを読み込んで検索結果を出す =page2 @app.route('/templates/page2', methods=['POST']) def post(): name = request.form.get('name') prefecture = request.form.get('prefectures') query = name query2 = prefecture query3 = '"食べログ"' the_word = query + " " + query2 + " " + query3 # APIから検索結果を取得 result = get_search_results(the_word) # result には 返却されたjsonが入る # 検索結果情報からタイトル, URL, スニペット, 検索結果の順位を抽出してまとめる result_items_list = summarize_search_results(result) # result_items_list には SearchResult のリストが入る # 他のページへ渡せるようにsessionを使う session['result_items_list'] = result_items_list # コマンドラインに検索結果の情報を1個分だけ表示 print(result_items_list[0]) # print(query2) # 第2引数で、htmlファイル上の変数にここで用いたリストを代入している return render_template('page2.html', rst_info=result_items_list) # 1つ目の情報が誤っていたときに2つ目の検索結果を表示する=page3 @app.route('/templates/page3', methods=["get"]) def page3(): # indexからpage2への移動時に作成された検索結果のリストをsessionを使って呼び出す searched_list = session.get('result_items_list', None) print(searched_list[1]) return render_template('page3.html', rst_info=searched_list) # page2での情報でOKだったときに、その店の詳細を表示させる=goal @app.route('/templates/goal', methods=["get"]) def goal(): searched_list = session.get('result_items_list', None) #↓OKが出た店の食べログURLでスクレイピング url_t = searched_list[0]['url'] r = requests.get(url_t) soup = BeautifulSoup(r.text, 'html.parser') name_rst = soup.find('div', class_='rstinfo-table__name-wrap').text station_rst = soup.find('span', class_='linktree__parent-target-text').text tel_rst = soup.find('p', class_='rstdtl-side-yoyaku__tel-number').text return render_template('goal.html', searched_list=searched_list, name_rst=name_rst, \ station_rst=station_rst, tel_rst=tel_rst) # 情報2件が両方とも不適切だった場合、はじめに戻る=fail @app.route('/templates/fail', methods=["get"]) def fail(): return render_template('fail.html') # xxxxxxxxxxxxxxxxxxxxxxxxxx if __name__ == '__main__': # app.run(debug=True) app.debug = True app.run() # xxxxxxxxxxxxxxxxxxxxxxxxxx
試したこと
調べる中でProcfileが特にあやしいと感じ、いろいろと英語のサイトなどにも当たりましたが原因がわかりませんでした。
特に参考にしたページ
https://toukei-lab.com/heroku-python
https://creepfablic.site/2019/06/15/heroku-procfile-matome/
よろしくお願いいたします。
まだ回答がついていません
会員登録して回答してみよう