見出し画像

Flask + Flask-SQLAlchemy + さくらレンタルサーバーでnoteと連携させたブログを作った方法


導入

お久しぶりです。4年の末広です。

引退したはずなのですが、今こうしてこの記事を書いています。
題名からもかなり趣向がいつもと違うことがわかるかと思いますが、今回は技術系の記事です。
というのも、ここ数週間ずっとwebサイトを作っていまして、色々と調べて、技術的なことで躓いたり成長したりしたので、ここにまとめておこうと思います。
運動会系の部活のブログの記事がテック系になることは珍しいと思いますが、これを機に今まで全く東大柔道部に関わりがなかった人も他のブログを見ていただけると嬉しいです。

完成品

ことの経緯

昔々、東大柔道部にはWordpressで作成されたブログが2008年ごろからあり、それを運営していました。しかしながら、全くもってメンテナンスされておらず、しまいにはwebの知識がほとんどないものをブログ係に据えるなど、杜撰の極みでした。(もちろんバックアップなど取っているはずがない。)
そんなある日、Wordpressの謎のプラグインの内部のプログラムで使われていたPerlのバージョンがレンタルサーバーでサポートされなくなったのをきっかけにブログが閲覧できない状態になり、しかもその後なぜか2008年ごろからのデータが闇に消えていったのです。ついでに東大柔道部の某サイトも500エラーを吐いて見れない状態になりました。
これが2022年3月のお話で、とりあえず一時的な措置としてnoteで仮にブログを復活させたのですが、この時既に私はブログの復活を企んでいたのです。

(この時彼は自分は何もやっていないのに「完全復活はあまり期待できないかもしれません。」などと言っており、失礼な人間であることが伺える。 https://note.com/todaijudobu/n/n7faa7293d083 )

復活のためにまずは、過去のブログの投稿を抽出する必要があったのですが、これがかなり難航し、結局 web archive をスクレイピングすることで(ほとんど)全ての記事を取り出しました。
また、どのフレームワークでブログを作るかもかなり大事な選択で、僕は普段pythonを使うことが多いことから、Flask か Django にしようとは決めていたのですが、この2択を決断するまでに僕は引退していました。

このようにあまりにもブログ復活の進捗が遅かったので、note にかなりの数の投稿をみんなが上げていて、新しいブログもnoteとの連携を取る方がいいのではと思うようになりました。
ただ、noteは、例えばタグの機能がなかったり、誰がその記事を書いたのかの情報を付与できなかったり、あとノイズ(広告や他のユーザーのおすすめ記事)が多いのなど欠点が多いので(私はnoteのエディタも嫌いであるが、他の柔道部員的には使いやすいらしい)、新しいブログは過去の先人たちによる未来に遺すべき投稿の数々を復活させ、さらに最近の記事についてはnoteと連携し、タグや投稿者の情報を付与することでnoteの良さを最大限活かした運用することに決定したのです。

Flask + Flask-SQLAlchemy でブログ風のサイトを作る方法

webサイトを作るとなると、とりあえず、ローカルで開発を進めていきます。

Step 0 - Flaskの練習

今回はFlaskを用いるのが初めてだったので、ステップ0としては、まず簡単な掲示板の作成を行いました。

参考にしたサイト

Step 1 - FlaskのチュートリアルのFlask-SQLAlchemy化

次に練習として、Flask のドキュメントにあるチュートリアル: https://msiz07-flask-docs-ja.readthedocs.io/ja/latest/tutorial/index.html (データベースの操作はsqlite3でSQLを書いて行っている) をFlask-SQLAlchemy を用いたデータベース管理に書き換えをしました。
(Flask-SQLAlchemy とは、Object Relational Mapper (ORM)で、SQLを書かずにデータベースの操作をできるほか、pythonのオブジェクトとしてデータベースを扱えるようになります。)

参考にしたサイト

Step 2 - 設計通りにサイトを作っていく

ここからが本番で、まず、サイトを設計していきます。ここでいう設計は、

  • データベース (データの保存先)

  • ルーティング (どのリンクに来たらどの処理をするのか)

  • フロント (webページとして見えている部分)

  • その他機能の実装方法 (例えばnoteの記事のリンクから本文などの抽出する方法など)

などを考えます。そのため設計段階で組み入れたい機能全てを列挙し、それをどのように実装するのかを一旦決めます。

加えて、どの順番で何の実装していくかもこのタイミングで考え、僕の場合は、各実装を行うためのgitのブランチ名もその時に全て決めました。

今回は作りべきもののベース(Flask + Flask-SQLAlchemy になっているblog)がStep 1 でできているので、それに修正や機能追加をすることで作りました。

参考にしたサイト

note API を利用してnoteの記事のリンクから本文などの抽出するコード

#Python
from datetime import datetime
import requests


def get_note_article_from_url(url_string):
    error = None

    try:
        url_string.index("https://note.com/todaijudobu/n/")
    except ValueError:
        error = "正しいURL(https://note.com/todaijudobu/n/n...)を入力してください。"    

    if error is not None:
        return {}, error
    else:
        article_key = url_string[31:]

        if len(article_key) < 13:
            error = "正しいURL(https://note.com/todaijudobu/n/n...)を入力してください。"
            return {}, error

        api_url = "https://note.com/api/v3/notes/"

        response = requests.get(api_url+article_key)

        note_api_status_code = response.status_code

        if note_api_status_code // 100 >= 4: # Client Error or Server Error
            error = "note の API が使えなくなっている場合があります。ブログの管理者に相談してください。"
            return {}, error

        response_dict = response.json()

        try:
            created_at = datetime.strptime(response_dict['data']['created_at'], "%Y-%m-%dT%H:%M:%S.000+09:00")
        except ValueError:
            error = "note の API が仕様が変更され使えなくなっている場合があります。ブログの管理者に相談してください。"
            return {}, error

        note_article_data = {
            'key': response_dict['data']['key'],
            'title': response_dict['data']['name'],
            'body': response_dict['data']['body'],
            'created_at': created_at,
            'permanent_link': url_string,
        }

        return note_article_data, error

さくらレンタルサーバーにデプロイ

Step 3 - デプロイ

ここまでローカルで開発してきたが、それが完成したら、本番サーバにデプロイする必要があります。
サーバはVPSと悩んだが、ケチってこっちにしました。VPSとの差で非常に大きいのは、sudoが使えないことです。

Flask的にはWSGIを使えってうるさいが、レンタルサーバではほぼ全てで使えないので、index.cgiで

python
wsgiref.handlers.CGIHandler().run(app)

を用います。

加えて、ProxyFixの設定では、以下でコメントアウトした部分の設定を行ってしまうと動作しなくなるので注意が必要。

# python
class ProxyFix(object):
    def __init__(self, app):
        self.app = app
    def __call__(self, environ, start_response):
        environ['SERVER_NAME'] = (サーバー名)
        environ['SERVER_PORT'] = "80"
        # environ['REQUEST_METHOD'] = "GET"
        environ['SCRIPT_NAME'] = ""
        # environ['PATH_INFO'] = "/"
        # environ['QUERY_STRING'] = ""
        environ['SERVER_PROTOCOL'] = "HTTP/1.1"
        return self.app(environ, start_response)

参考にしたサイト


まとめ

ブログ完成した。大変だった。
pythonってすごい。javascriptってもっとすごい。


(noteっていうプラットフォームを1から作った人なら尊敬できるけど、noteに登録しただけで尊敬してもらえるって思ってんの、やっぱコイツどうかしてるぜ。
 https://note.com/todaijudobu/n/n387b8842d85e )

以上、無給でサイトを作った末広でした。


いいなと思ったら応援しよう!