BeautifulSoupでリンクを取得してこれをFlaskで表示させる
beautiful-soup-flask
ASP.NET Coreで作成したアプリを公開したら他のアプリが動かなくなってしまった件の続きです。
表示されなくなったコード
以前、PythonのライブラリBeautifulSoupを用い、以下のようなコードをかいてYahoo!Japanのトップページから貼られているリンクを表示させるページを公開していました。ところがASP.NET Coreで作成したアプリを公開したらページが表示されなくなってしまいました。プログラマを悩ませるあの「500 Internal Server Error」です。
.htaccess
1 2 |
DirectoryIndex index.py indexhtml AddHandler cgi-script .py |
index.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
#!/home/(鳩のアカウント名)/miniconda3/bin/python3 # -*- coding: utf-8 -*- import urllib.request from bs4 import BeautifulSoup # 日本語を扱うために必要な設定 import sys sys.stdin = open(sys.stdin.fileno(), 'r', encoding='UTF-8') sys.stdout = open(sys.stdout.fileno(), 'w', encoding='UTF-8') sys.stderr = open(sys.stderr.fileno(), 'w', encoding='UTF-8') # HTMLヘッダ出力 print("Content-type: text/html; charset=utf-8\r\n\r\n") # Yahoo Japanのトップページにアクセス url = "https://www.yahoo.co.jp/" data = urllib.request.urlopen(url) # HTMLを解析して取得 soup = BeautifulSoup(data, 'html.parser') # リンクの部分のみ取り出す items = soup.find_all('a') # HTMLタグ出力 print("<!DOCTYPE html>") print("<html>") print("<head>") print("<meta charset='utf-8'>") print("<meta name='viewport' content='width=device-width,user-scalable=yes'>") print("<link rel='stylesheet' href='style.css'>") print("<title>Yahoo Japanのリンク部分だけ取得してみる</title>") print("</head>") print("<body>") print("<h1>Yahoo Japanのリンク部分を取得してみる</h1>") print("<ul>") for a in items: print('<li>') print(a.text) print("</li>") print("</ul>") print("</body>") print("</html>") |
Flaskをつかって結果を表示させる
ただFlaskを実行してこれを.htaccessで表示させるという方法は使えるみたいです。そこでこの方法で表示させます。
サーバーでも必要になるのでpipでFlaskをインストールしておきます。
1 |
pip install Flask |
そして
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
from flask import Flask import urllib.request from bs4 import BeautifulSoup app = Flask(__name__) @app.route("/") def show_yahoo_links(): url = "https://www.yahoo.co.jp/" data = urllib.request.urlopen(url) soup = BeautifulSoup(data, 'html.parser') items = soup.find_all('a') # HTMLタグ出力 html_text = '<!DOCTYPE html>' html_text += '<html>' html_text += '<head>' html_text += '<meta charset="utf-8">' html_text += '<meta name="viewport" content="width=device-width,user-scalable=yes">' html_text += '<link rel="stylesheet" href="style.css">' html_text += '<title>Yahoo Japanのリンク部分だけ取得してみる</title>' html_text += '</head>' html_text += '<body>' html_text += '<h1>Yahoo Japanのリンク部分を取得してみる</h1>' html_text += '<ul>' for a in items: html_text += '<li><a target="_blank" rel="noopener">' + a.text + '</a></li>' html_text += '</ul>' html_text += '</body>' html_text += '</html>' return html_text if __name__ == '__main__': app.run(port=8500) |
まあ、これでも実行してみるとリンクはただしく表示されるのでいいのかもしれませんが、あまり筋がいいやりかたではないです。そこでテンプレートを使います。
テンプレートを使う
テンプレートを使うにはapp.pyと同じフォルダにtemplatesというフォルダを作成します。そしてそこにindex.htmlというファイル(名前はなんでもOK。abc.xyzみたいな名前でもよい)を作成します。
templates/index.html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <title>{{ title }}</title> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> </head> <body> {{body|safe}} </body> </html> |
app.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 |
from flask import Flask, render_template # render_templateが追加されている import urllib.request from bs4 import BeautifulSoup app = Flask(__name__) @app.route("/") def show_index_page(): return get_yahoo_links() # サーバー上では以下がないと / にアクセスしたときページが存在しないと表示される @app.route("/index.html") def show_index_page2(): return get_yahoo_links() @app.route("/test.py") def show_testpy_page(): return get_yahoo_links() # 一部変更すればGoogleでも同じことができる @app.route("/google.py") def show_google_page(): return get_google_links() def get_yahoo_links(): url = 'https://www.yahoo.co.jp/' data = urllib.request.urlopen(url) soup = BeautifulSoup(data, 'html.parser') items = soup.find_all('a') html_text = '<h1>Yahoo Japanのリンク部分を取得してみる</h1>' html_text += '<ul>' for a in items: html_text += '<li><a target="_blank" rel="noopener">' + a.text + '</a></li>' html_text += '</ul>' return render_template('index.html', title = 'Yahoo Japanのリンク部分を取得してみる', body = html_text ) def get_google_links(): url = 'https://www.google.com/' data = urllib.request.urlopen(url) soup = BeautifulSoup(data, 'html.parser') items = soup.find_all('a') html_text = '<h1>Googleのリンク部分を取得してみる</h1>' html_text += '<ul>' for a in items: html_text += '<li><a target="_blank" rel="noopener">' + a.text + '</a></li>' html_text += '</ul>' return render_template('index.html', title = 'Googleのリンク部分を取得してみる', body = html_text ) if __name__ == '__main__': app.run(port=8500) |
公開する
あとは適当なディレクトリにアップロードして以下を実行。
1 2 3 4 5 |
$ python app.py & # そのあとCtrl + C を押した後に disown |
表示させたいurlに相当するディレクトリに.htaccessを設置
1 2 3 4 |
<IfModule mod_rewrite.c> RewriteEngine On RewriteRule ^(.*)$ http://localhost:8500/$1 [P,L] </IfModule> |
これで見た目はもとどおりになりました。
https://lets-csharp.com/samples/2108/python-test/
https://lets-csharp.com/samples/2108/python-test/test.py
https://lets-csharp.com/samples/2108/python-test/google.py