アサトの実験blog

Pythonでの自動化とか、IT関連で興味のあるテーマについて色々実験する場所です

Python-Flask-bootstrapでホームページを作ってherokuにデプロイする方法

0.はじめに

ブログはハテナブログで始めていますが、自動投稿などを herokuで行っているうちに、heroku上にホームページも作ってみたくなりました。

記事は色々転がっているようなのでそれらを見ると基本手順はわかりそうでしたが、どれもなぜか hello, world と文字列を出すだけで終わっている記事が多かったのが気になりました。実際、ホームページを作ってみよう!という人は

「ある程度見た目のよいホームページをインターネット上に立ち上げたい」

と思っているはずで、

「自分のPC環境にウェブサーバを立ち上げて Hello, Worldという文字列を出す」

わけではないはずですので。まあとにかく初めて見ます。

1 概要

1-1 heroku

基本知識として、Herokuというサービスは、Salesform.comが提供している PaaS (Platform as a Service)に分類されるもので、ある程度までは無料で使えることができます。  実際にアプリをデプロイすると、アプリ名.herokuapp.com という名前でアクセスができますので、ドメイン名を別途取得したりも一応は不要です。(自分の好きな名前で今後サービスを行いたいのであれば取得した方がいいのはもちろんですが)

herokuへのデプロイ手順については、

qiita.com

を参考にさせていただきました。ありがとうございます。

1-2 Flask

Flask というのは、pythonで動かすことのできる小型のウェブフレームワークです。Pythonには何種類かのウェブフレームワークがありますが、ここでは軽量でとっつきやすいということで Flaskを選択します。

1-3 Bootstrap

Bootstrap というのは、Twitter社で開発された、CSSフレームワークと呼ばれているもので、デザイン等の知識がなくても比較的簡単に Webサイトのデザインを進めることができます。

インターネット上に色々な Bootstrapのひな形がありますが、ここでは、日本語が使えるBootstrapのひな形として結構な人気がある、

honokak.osaka

を使ってみたいと思います。

2 手順

さて、概要はこれくらいで。

まずは、ローカルの環境に Flask Webサーバを立ち上げます。一応 Python & pip が動くサーバはある前提として、そこは飛ばさせてもらいます。まあわからない人はこのあたり↓を参照で。 www.python.jp

(私の環境の場合は、Unix環境なのでpython実行の時に python3.6 と記載しますが、Windows等の場合は pythonでよい筈です。まあ pythonの実行の仕方は各環境毎に読み替えてください)

2-1 pipenv のインストール

後々 herokuへインストールする際も、pipenv が便利なので pipenvをインストールします。

# pip install pipenv 

でインストールを行ってください。

2-2 アプリ用ディレクトリの作成 & pipenv shell の実行。

ここでは、flask-bs というディレクトリ名で作成します。

# mkdir flask-bs
# cd flask-bs
# pipenv shell
# pip freeze 

2-3 必要なパッケージのインストール

2-2 で、仮想環境が作成され、必要ナモジュールは何も出ていない状況になっていると思います。 ここで、必要なパッケージをインストールしていきます。 Flask, flask-bootstrap4 に加えて、あとで heroku にデプロイする時に必要な gunicornも入れちゃいましょう。

# pipenv install Flask
# pipenv install flask-bootstrap4
# pipenv install gunicorn

2-4 bootstrap のテンプレートのダウンロード

ここで、bootstrapのテンプレートをダウンロードしておきましょう。

最初に説明したHonokaのテンプレートがダウンロードできるのは、ここから。 github.com

2-5.フォルダの準備

現在、自分のいる flask-bsというディレクトリの下には、PipfileとPipfile.lockの2つのファイルがあるだけだと思います。

最初に、templates というディレクトリと、staticというディレクトリを作りましょう

# mkdir templates
# mkdir static

2-6. html等の作成。書き換え。

Flask-bootstrapでは templates の下に、htmlテンプレート、staticの下に javascriptcss等を入れる形になります。 そして、同じディレクトリ上に vi 等のエディタを使って、bootstrap.py というファイルを作成します。

# coding: utf-8
from flask import Flask, render_template
from flask_bootstrap import Bootstrap

app = Flask(__name__)
bootstrap = Bootstrap(app)

@app.route('/')
def index():
    return render_template('bootstrap1.html')

if __name__ == '__main__':
    app.run()

後は 2.4 でダウンロードしたテンプレートをダウンロード。書き換えるのですが、書き換え後の再集計のファイルをここに置いておきました。面倒な人はここからダウンロードして展開してください。

github.com

ポイントは、上のソースから呼ばれる templateの html と、あとは html等から呼ばれる css, js 等の資産です。 css,や javascriptの資産は、Flaskの標準では、 先ほど作成した static というディレクトリの下に置きます。そのあたりを書き換えます。

全部を載せるとすさまじく長くなってしまうので一部だけ。 bootstrap1.htmlのひな形で利用するhtmlはこんな形

{% extends "bootstrap/base.html" %}

{% block title %}Hello{% endblock %}

{% block content %}
<div class="container">

★ここに、表示したいhtmlを入れる。

</div>
{% endblock %}

具体的には、Honokaで用意されている、index.htmlをそのまま上の★部分に読み込んでしまいます。そして、cssjavascript等の呼び出し部分を、/static/css/xxx , /static/js/xxx という形に書き換えれば基本的な作業は終了です。

出来上がった bootstrap1.htmlだけ載せておきます。

# cat bootstrap1.html
{% extends "bootstrap/base.html" %}

{% block title %}Hello{% endblock %}

{% block content %}
<div class="container">

<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

  <title>Honoka - 日本語も美しく表示できるBootstrapテーマ</title>

  <link rel="shortcut icon" type="image/png" href="assets/img/brand.png">

  <meta property="og:title" content="Honoka - 日本語も美しく表示できるBootstrapテーマ">
  <meta property="og:type" content="website">
  <meta property="og:url" content="http://honokak.osaka/">
  <meta property="og:image" content="http://honokak.osaka/assets/img/sample.png">
  <meta property="og:description" content="Honokaは日本語表示に最適化されたオリジナルBootstrapテーマです。">

  <meta name="twitter:card" content="summary_large_image">
  <meta name="twitter:site" content="@MITLicense">
  <meta name="twitter:creator" content="@MITLicense">
  <meta name="twitter:title" content="Honoka - 日本語も美しく表示できるBootstrapテーマ">
  <meta name="twitter:image" content="http://honokak.osaka/assets/img/sample.png">
  <meta name="twitter:description" content="Honokaは日本語表示に最適化されたオリジナルBootstrapテーマです。">

  <link rel="stylesheet" type="text/css" href="/static/css/bootstrap.css">
  <link rel="stylesheet" type="text/css" href="/static/assets/css/example.css">

  <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.0.8/css/all.css" integrity="sha384-3AB7yXWz4OeoZcPbieVW64vVXEwADiYyAEhwilzWsLw+9FgqpyjjStpPnpBO8o8S" crossorigin="anonymous">
</head>
<body>

<header>
  <nav class="navbar navbar-expand-lg navbar-light bg-light">
    <div class="container">
      <a class="navbar-brand" href="./">
        <img src="/static/assets/img/brand.png" width="30" height="30" class="d-inline-block align-top mr-1" alt="Honoka">
        Honoka
      </a>
      <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbar" aria-controls="navbar" aria-expanded="false" aria-label="Toggle navigation">
        <span class="navbar-toggler-icon"></span>
      </button>

      <div class="collapse navbar-collapse" id="navbar">
        <ul class="navbar-nav mr-auto">
          <li class="nav-item active">
            <a class="nav-link" href="./">Top <span class="sr-only">(current)</span></a>
          </li>
          <li class="nav-item dropdown">
            <a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
              Live demo
            </a>
            <div class="dropdown-menu" aria-labelledby="navbarDropdown">
              <a class="dropdown-item" href="./bootstrap-ja.html">Japanese Page</a>
              <a class="dropdown-item" href="./bootstrap.html">English Page</a>
            </div>
          </li>
          <li class="nav-item">
            <a class="nav-link" href="http://github.com/windyakin/Honoka/releases">Download</a>
          </li>
          <li class="nav-item">
            <a class="nav-link" href="http://github.com/windyakin/Honoka/wiki">Wiki</a>
          </li>
        </ul>
        <div class="form-inline my-2 my-lg-0">
          <a href="https://twitter.com/intent/tweet?url=http://honokak.osaka/&text=Honoka%20%2d%20%e6%97%a5%e6%9c%ac%e8%aa%9e%e3%82%82%e7%be%8e%e3%81%97%e3%81%8f%e8%a1%a8%e7%a4%ba%e3%81%a7%e3%81%8d%e3%82%8bBootstrap%e3%83%86%e3%83%bc%e3%83%9e" class="btn btn-twitter mr-1"><i class="fab fa-twitter fa-lg fa-fw"></i> Tweet</a>
          <a href="http://www.facebook.com/sharer.php?u=http://honokak.osaka/" class="btn btn-facebook mr-1"><i class="fab fa-facebook-f fa-lg fa-fw"></i> Share</a>
          <a href="javascript:window.open('http://b.hatena.ne.jp/add?mode=confirm&is_bm=1&title='+escape(document.title)+'&url='+escape(location.href),%20'_blank',%20'width=520,height=600,resizable=1,scrollbars=1');undefined;" class="btn btn-hatena"><i class="icon icon-hatebu fa-lg"></i> Bookmark</a>
        </div>
      </div>
    </div>
  </nav>
</header>

<div class="jumbotron special">
  <div class="container">
    <div class="row">
      <div class="col-xl-4 d-xl-block d-none">
        <div class="honoka"></div>
      </div>
      <div class="col-xl-8 outline text-xl-left text-center">
        <div class="display-3 copy">
          <span class="d-inline-block">その Bootstrap は、</span><br>
          <span class="d-inline-block">日本語も</span><span class="d-inline-block"><u>美しく</u></span><br>
          <span class="d-inline-block">表示されて</span><span class="d-inline-block">ますか?</span>
        </div>
        <p class="lead mt-2">Honoka は日本語も美しく表示できる Bootstrap テーマです</p>
        <hr>
        <ul class="download list-inline">
          <li class="list-inline-item"><a href="//github.com/windyakin/Honoka/releases" class="btn btn-honoka btn-lg last-release-download-link"><i class="fab fa-github-alt"></i> Download from GitHub</a></li>
          <li class="list-inline-item"><a href="/bootstrap-ja.html" class="btn btn-primary btn-lg"><i class="fa fa-play-circle"></i> Live Demo</a></li>
        </ul>
        <div class="basedon small">
          Last version v<span class="last-version"></span> ・ Based on <a href="http://getbootstrap.com/">Bootstrap</a> v<span class="base-version"></span>
        </div>
      </div>
    </div>
  </div>
</div>

<aside class="social">
  <div class="social-button">
    <ul>
      <li><iframe src="https://ghbtns.com/github-btn.html?user=windyakin&repo=Honoka&type=star&count=true" frameborder="0" scrolling="0" width="90px" height="20px"></iframe></li>
      <li><a href="https://twitter.com/share" class="twitter-share-button" data-lang="ja" data-dnt="true">ツイート</a></li>
      <li><div class="fb-like" data-href="http://honokak.osaka/" data-layout="button_count" data-action="like" data-show-faces="false" data-share="false"></div></li>
      <li><a href="http://b.hatena.ne.jp/entry/" class="hatena-bookmark-button" data-hatena-bookmark-layout="standard-balloon" data-hatena-bookmark-lang="ja" title="このエントリーをはてなブックマークに追加"><img src="https://b.st-hatena.com/images/entry-button/button-only@2x.png" alt="このエントリーをはてなブックマークに追加" width="20" height="20" style="border: none;"></a></li>
    </ul>
  </div>
</aside>

<section class="section section-default point">
  <div class="container">
    <div class="row">
      <div class="col-12 subtitle">
        <h2>HonokaはオリジナルBootstrapテーマです</h2>
        <p class="lead">HonokaはBootstrapテーマの一つですが、以下の特徴を持っています。</p>
      </div>
    </div>
    <div class="row">
      <div class="col-md-3 col-sm-6 point-box">
        <div class="point-circle start">
          <i class="fa fa-check"></i>
        </div>
        <div class="point-description">
          <h4>Easy to Start</h4>
          <p>HonokaはBootstrapを元に製作されているため、非常に高い互換性を持っています。マークアップに関する規約はほとんど変わりません。</p>
        </div>
      </div>
      <div class="col-md-3 col-sm-6 point-box">
        <div class="point-circle replace">
          <i class="fa fa-sync-alt"></i>
        </div>
        <div class="point-description">
          <h4>Replace Bootstrap</h4>
          <p>既にBootstrapを使って作成したウェブサイトがある場合は、CSSを置き換えるだけで簡単にHonokaを利用できます。</p>
        </div>
      </div>
      <div class="col-md-3 col-sm-6 point-box">
        <div class="point-circle compass">
          <i class="fab fa-github-alt"></i>
        </div>
        <div class="point-description">
          <h4>Open Source</h4>
          <p>Honokaを構成するファイルは全て公開されています。変数の定義ファイルを変更することで自分好みの設定に変更することも可能です。</p>
        </div>
      </div>
      <div class="col-md-3 col-sm-6 point-box">
        <div class="point-circle japanese">
          <span class="icon-jp"></span>
        </div>
        <div class="point-description">
          <h4>Optimized Japanese</h4>
          <p>Bootstrapでは考慮されていない日本語のフォント指定やウェイトの変更を行っているので、美しく日本語を表示できます。</p>
        </div>
      </div>
    </div>
  </div>
</section>

<section class="section section-inverse getting-started">
  <div class="container">
    <div class="row">
      <div class="col-12 subtitle">
        <h2>さあ、はじめましょう。</h2>
        <p class="lead">導入はとっても簡単です</p>
      </div>
    </div>
    <div class="row my-3">
      <div class="col-12 text-center">
        <div class="form-group">
          <a href="//github.com/windyakin/Honoka/releases" class="btn btn-primary btn-lg last-release-download-link"><i class="fas fa-file-archive fa-lg mr-2"></i> Download from GitHub</a>
          <p class="form-text text-muted"><small>Last version v<span class="last-version"></span> ・ <a href="//github.com/windyakin/Honoka/blob/master/LICENSE">MIT License</a></small></p>
        </div>
      </div>
    </div>
    <div class="row">
      <div class="col-md-6 text-center my-3">
        <h3><a href="https://www.npmjs.com/package/bootstrap-honoka"><img src="/static/assets/img/npm-logo.png" alt="npm" class="img-fluid package-system-logo"></a></h3>
        <div class="input-group input-group-lg">
          <input type="text" class="form-control border-secondary" id="npm-install-command" value="npm install --save bootstrap-honoka" onclick="this.select();" readonly="readonly">
          <span class="input-group-append">
            <button type="button" class="btn btn-light border-secondary" data-clipboard-target="#npm-install-command"><i class="fa fa-clipboard"></i></button>
          </span>
        </div>
        <div><small class="form-text text-muted"><a href="https://www.npmjs.com/package/bootstrap-honoka">npmjs.com</a> / v3.3.7-a 以降から対応</small></div>
      </div>
      <div class="col-md-6 text-center my-3">
        <h3><img src="/static/assets/img/bower-logo.png" alt="Bower" class="img-fluid package-system-logo"> Bower</h3>
        <div class="input-group input-group-lg">
          <input type="text" class="form-control border-secondary" id="bower-install-command" value="bower install --save $(node -e &#34;$(curl -fsSL https://cdn.honokak.osaka/last.js)&#34; windyakin Honoka)"
           onclick="this.select();" readonly="readonly">
           <span class="input-group-append">
            <button type="button" class="btn btn-light border-secondary" data-clipboard-target="#bower-install-command"><i class="fa fa-clipboard"></i></button>
          </span>
        </div>
        <div><small class="form-text text-muted">v3.3.5-c 以降から対応</small></div>
      </div>
    </div>
    <div class="row mt-3">
      <div class="col-12 text-center">
        <p>使い方やファイルの説明など、詳しくは <a href="//github.com/windyakin/Honoka#readme">README</a> または <a href="//github.com/windyakin/Honoka/wiki">Wiki</a> をご確認ください</p>
      </div>
    </div>
  </div>
</section>

<section class="section section-inverse avaliable-webpack d-none">
  <div class="container">
    <div class="row">
      <div class="col-12 subtitle">
        <h2>Available on Framework!</h2>
        <p class="lead">Honokaは様々なパッケージマネージャからも利用することができます</p>
      </div>
    </div>
    <div class="row">
      <div class="col-md-6 text-center">
        <h3><a href="https://www.npmjs.com/package/bootstrap-honoka"><img src="/static/assets/img/npm-logo.png" alt="npm" class="img-fluid package-system-logo"></a></h3>
        <div class="input-group input-group-lg">
          <input type="text" class="form-control" id="npm-install-command" value="npm install --save bootstrap-honoka" onclick="this.select();" readonly="readonly">
          <span class="input-group-append">
            <button type="button" class="btn btn-secondary" data-clipboard-target="#npm-install-command"><i class="fa fa-clipboard"></i></button>
          </span>
        </div>
        <div><small class="form-text text-muted"><a href="https://www.npmjs.com/package/bootstrap-honoka">npmjs.com</a> / v3.3.7-a 以降から対応</small></div>
      </div>
      <div class="col-md-6 text-center">
        <h3><img src="/static/assets/img/bower-logo.png" alt="Bower" class="img-fluid package-system-logo"> Bower</h3>
        <div class="input-group input-group-lg">
          <input type="text" class="form-control" id="bower-install-command" value="bower install --save $(node -e &#34;$(curl -fsSL https://cdn.honokak.osaka/last.js)&#34; windyakin Honoka)"
           onclick="this.select();" readonly="readonly">
           <span class="input-group-append">
            <button type="button" class="btn btn-secondary" data-clipboard-target="#bower-install-command"><i class="fa fa-clipboard"></i></button>
          </span>
        </div>
        <div><small class="form-text text-muted">v3.3.5-c 以降から対応</small></div>
      </div>
    </div>
  </div>
</section>

<section class="section section-default used-by">
  <div class="container">
    <div class="row">
      <div class="col-12 subtitle">
        <h2>Honokaを使って作られたウェブサイト</h2>
        <p class="lead">HonokaやそのForkテーマで構築されたウェブサイトを紹介します</p>
      </div>
    </div>
    <div class="row">
      <div class="col-md-4">
        <div class="card my-3">
          <a href="https://proconist.net/"><img src="//cdn.honokak.osaka/assets/img/proconist.png" class="card-img-top"></a>
          <div class="card-body text-center">
            <h5 class="card-title m-0">Proconist.net</h5>
          </div>
        </div>
      </div>
      <div class="col-md-4">
        <div class="card my-3">
          <a href="http://sugoi.windyakin.net/"><img src="//cdn.honokak.osaka/assets/img/sugoi.png" class="card-img-top"></a>
          <div class="card-body text-center">
            <h5 class="card-title m-0">この高専がすごい!</h5>
          </div>
        </div>
      </div>
      <div class="col-md-4">
        <div class="card my-3">
          <a href="http://yashihei.net/"><img src="//cdn.honokak.osaka/assets/img/yashihei.png" class="card-img-top"></a>
          <div class="card-body text-center">
            <h5 class="card-title m-0">yashihei.net</h5>
          </div>
        </div>
      </div>
    </div>
    <div class="row">
      <div class="col-md-4">
        <div class="card my-3">
          <a href="http://sysken.org/advent2015/"><img src="//cdn.honokak.osaka/assets/img/sysken.png" class="card-img-top"></a>
          <div class="card-body text-center">
            <h5 class="card-title m-0">SYSKEN Advent Calendar</h5>
          </div>
        </div>
      </div>
      <div class="col-md-4">
        <div class="card my-3">
          <a href="http://timers-inc.com/"><img src="//cdn.honokak.osaka/assets/img/timers-inc.png" class="card-img-top"></a>
          <div class="card-body text-center">
            <h5 class="card-title m-0">TIMERS Inc</h5>
          </div>
        </div>
      </div>
      <div class="col-md-4">
        <div class="card my-3">
          <a href="http://ost.procon-online.net/"><img src="//cdn.honokak.osaka/assets/img/ost.png" class="card-img-top"></a>
          <div class="card-body text-center">
            <h5 class="card-title m-0">PROCON O.S.T. Project</h5>
          </div>
        </div>
      </div>
    </div>
  </div>
</section>

<section class="section section-inverse fork">
  <div class="container">
    <div class="row">
      <div class="col-12 subtitle">
        <h2>HonokaのForkテーマ</h2>
        <p>Honokaをベースにして作られた他のBootstrapテーマ</p>
      </div>
    </div>
    <div class="row">
      <div class="col-md-6">
        <div class="card my-3">
          <a href="//ysakasin.github.io/Umi/"><img src="//cdn.honokak.osaka/assets/img/umi.png" class="card-img-top"></a>
          <div class="card-body text-center">
            <h4 class="card-title">Umi</h4>
            <p>"Umi"は"Honoka"に<a href="https://bootswatch.com/flatly/">Bootswatch Flatly</a>の配色を適用したテーマです。</p>
            <div>
              <a href="//ysakasin.github.io/Umi/" class="btn btn-primary">Umiの特設ページ <i class="fa fa-external-link-alt"></i></a>
              <a href="//github.com/ysakasin/Umi" class="btn btn-outline-secondary">Umi on GitHub <i class="fab fa-github-alt"></i></a>
            </div>
          </div>
        </div>
      </div>
      <div class="col-md-6">
        <div class="card my-3">
          <a href="http://nico.kubosho.com/"><img src="//cdn.honokak.osaka/assets/img/nico.png" class="card-img-top"></a>
          <div class="card-body text-center">
            <h4 class="card-title">Nico</h4>
            <p>"Nico"は"Honoka"にピンク系の配色を適用したテーマです。</p>
            <div>
              <a href="http://nico.kubosho.com/" class="btn btn-primary">Nicoの特設ページ <i class="fa fa-external-link-alt"></i></a>
              <a href="//github.com/kubosho/Nico" class="btn btn-outline-secondary">Nico on GitHub <i class="fab fa-github-alt"></i></a>
            </div>
          </div>
        </div>
      </div>
    </div>
    <div class="row">
      <div class="offset-md-3 col-md-6">
        <div class="card my-3">
          <a href="//rinhoshizo.la/"><img src="//cdn.honokak.osaka/assets/img/rin.png" class="card-img-top"></a>
          <div class="card-body text-center">
            <h4 class="card-title">Rin</h4>
            <p>"Rin"は"Honoka"を元にしたMaterial Design風のテーマです。</p>
            <div>
              <a href="//rinhoshizo.la/" class="btn btn-primary">Rinの特設ページ <i class="fa fa-external-link-alt"></i></a>
              <a href="//github.com/raryosu/Rin" class="btn btn-outline-secondary">Rin on GitHub <i class="fab fa-github-alt"></i></a>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
</section>

<section class="section section-default featured">
  <div class="container">
    <div class="row">
      <div class="col-12 subtitle">
        <h2>Honoka has been featured on</h2>
      </div>
    </div>
    <div class="row">
      <div class="col-12 text-center">
        <ul class="list-inline featured-list">
          <li class="list-inline-item"><a href="http://www.moongift.jp/2015/06/honoka-%E6%97%A5%E6%9C%AC%E8%AA%9E%E3%82%82%E7%B6%BA%E9%BA%97%E3%81%AB%E8%A1%A8%E7%A4%BA%E3%81%A7%E3%81%8D%E3%82%8Bbootstrap%E3%83%86%E3%83%BC%E3%83%9E/"><img src="http://cdn.honokak.osaka/assets/img/moongift.png" alt="MOONGIFT"></a></li>
          <li class="list-inline-item"><a href="http://coliss.com/articles/build-websites/operation/work/bootstrap-theme-honoka.html"><img src="http://cdn.honokak.osaka/assets/img/coliss.png" alt="コリス"></a></li>
          <li class="list-inline-item"><a href="http://stocker.jp/diary/web-news-may2015/"><img src="http://cdn.honokak.osaka/assets/img/stockerjp.png" alt="Stocker.jp / diary"></a></li>
        </ul>
      </div>
    </div>
  </div>
</section>


<footer class="small">
  <div class="social-button">
    <ul>
      <li><iframe src="https://ghbtns.com/github-btn.html?user=windyakin&repo=Honoka&type=star&count=true" frameborder="0" scrolling="0" width="90px" height="20px"></iframe></li>
      <li><a href="https://twitter.com/share" class="twitter-share-button" data-lang="ja" data-dnt="true">ツイート</a></li>
      <li><div class="fb-like" data-href="http://honokak.osaka/" data-layout="button_count" data-action="like" data-show-faces="false" data-share="false"></div></li>
      <li><a href="http://b.hatena.ne.jp/entry/" class="hatena-bookmark-button" data-hatena-bookmark-layout="standard-balloon" data-hatena-bookmark-lang="ja" title="このエントリーをはてなブックマークに追加"><img src="https://b.st-hatena.com/images/entry-button/button-only@2x.png" alt="このエントリーをはてなブックマークに追加" width="20" height="20" style="border: none;"></a></li>
    </ul>
  </div>
  <div class="container">
    <div class="row">
      <div class="col-12 text-center copyright">
        &copy; 2015 Honoka
      </div>
    </div>
  </div>
</footer>

<script>
  (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
  (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
  m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
  })(window,document,'script','//www.google-analytics.com/analytics.js','ga');

  ga('create', 'UA-61413040-1', 'auto');
  ga('send', 'pageview');

</script>

<script src="//cdnjs.cloudflare.com/ajax/libs/clipboard.js/1.5.5/clipboard.min.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="/static/js/bootstrap.min.js"></script>
<script>
new Clipboard('.btn');
$(document).ready(function(e) {
  $.when(
    $.ajax({
      url: 'https://api.github.com/repos/windyakin/Honoka/releases/latest',
      type: 'get',
      dataType: 'json'
    }),
    $.ajax({
      url: 'https://cdn.rawgit.com/windyakin/Honoka/master/bower.json',
      type: 'get',
      dataType: 'json'
    })
  )
  .done(function(last, base) {
    $('.last-version').text(last[0].tag_name.split('v')[1]);
    $('.base-version').text(base[0].devDependencies.bootstrap);
    $('.last-release-download-link').attr({'href': '//github.com/windyakin/Honoka/releases/tag/' + last[0].tag_name })
  });
});
</script>
<script>!function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0],p=/^http:/.test(d.location)?'http':'https';if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src=p+'://platform.twitter.com/widgets.js';fjs.parentNode.insertBefore(js,fjs);}}(document, 'script', 'twitter-wjs');</script>
<div id="fb-root"></div>
<script>(function(d, s, id) {var js, fjs = d.getElementsByTagName(s)[0];if (d.getElementById(id)) return;js = d.createElement(s); js.id = id;js.src = "//connect.facebook.net/ja_JP/sdk.js#xfbml=1&appId=238369762859730&version=v2.3";fjs.parentNode.insertBefore(js, fjs);}(document, 'script', 'facebook-jssdk'));</script>
<script type="text/javascript" src="https://b.st-hatena.com/js/bookmark_button.js" charset="utf-8" async="async"></script>
</body>
</html>

</div>
{% endblock %}

(★注:Flaskで呼び出してエラーが出ないようにフォルダ構成とかだけを書き換えただけなので、中身を具体的に見たわけではありません。具体的には、上のリストの中の /static/で書かれているところが主な書き換え場所です。)

githubに登録している方のソースでは、Honokaに含まれる bootstrap.html, bootstrap-ja.htmlも同様に書き換えを行ってはいます。ただ、まだエラーがあるようなのでこのあたりはそのうち時間を見て自分用のホームページに書き換える時に調べたいと思います。

2-7 動作確認

さて、動作確認です。pythonなのでいつもの通り、# python3.6 bootstrap.py .... ではありませんのでご注意を。

確認用のアプリ実行には、以下の形でコマンドを入れてください。

FLASK_APP=bootstrap.py flask run --host=0.0.0.0

うまく動作すれば、次のようなメッセージが出てきます。

# FLASK_APP=bootstrap.py flask run --host=0.0.0.0
 * Serving Flask app "bootstrap.py"
 * Environment: production
   WARNING: Do not use the development server in a production environment.
   Use a production WSGI server instead.
 * Debug mode: off
 * Running on http://0.0.0.0:5000/ (Press CTRL+C to quit)

ブラウザで接続してみましょう。 http://動かしているサーバのIPアドレス:5000/ ( 私の場合だと、http://192.168.0.42:5000/ )とすると、次のようになります。

f:id:asato418:20180915013926p:plain

2.8 herokuで動作させる為のファイル作成

herokuについては、ユーザも登録されていて、チュートリアルあたりは終えていることを前提としています。 herokuにデプロイ後は、ウェブサーバはgunicornという先ほど入れたパッケージを使って動作する形になります。そのために、以下のようなファイルを Procfileという名前で作成します。(githubから落としてきた人は、すでにこのファイルも入っているはず)

web: gunicorn bootstrap:app --log-file -

2.9 heroku側の環境準備

heroku loginでログイン後、 heroku create アプリ名 でアプリ環境を作成します。 ( 最終的に、https://アプリ名.herokuapp.com/ で接続できるようになります。 )

作成が終わったら、

# git init 
# git add .
# git commit -m "Initial commit"
# heroku git:remote --app アプリ名
# git push heroku master
# heroku scale web=1

と実行しましょう。 その後、

#heroku logs 

と実行すると、うまく行っていれば

2018-09-14T15:55:57.980134+00:00 heroku[web.1]: State changed from crashed to starting
2018-09-14T15:56:03.696172+00:00 heroku[web.1]: Starting process with command `gunicorn bootstrap:app --log-file -`
2018-09-14T15:56:06.261177+00:00 app[web.1]: [2018-09-14 15:56:06 +0000] [4] [INFO] Starting gunicorn 19.9.0
2018-09-14T15:56:06.262261+00:00 app[web.1]: [2018-09-14 15:56:06 +0000] [4] [INFO] Listening at: http://0.0.0.0:25940 (4)
2018-09-14T15:56:06.262710+00:00 app[web.1]: [2018-09-14 15:56:06 +0000] [4] [INFO] Using worker: sync
2018-09-14T15:56:06.269944+00:00 app[web.1]: [2018-09-14 15:56:06 +0000] [10] [INFO] Booting worker with pid: 10
2018-09-14T15:56:06.324088+00:00 app[web.1]: [2018-09-14 15:56:06 +0000] [11] [INFO] Booting worker with pid: 11
2018-09-14T15:56:07.366091+00:00 heroku[web.1]: State changed from starting to up
2018-09-14T15:56:06.000000+00:00 app[api]: Build succeeded

といったログが表示されています。何かエラーがある場合にはここで確認できるので、エラーを取り除きましょう。

これで、めでたく接続ができるようになります。

f:id:asato418:20180915015055p:plain

後は自分なりに画像やら文章やらを書き換えて、良いホームページをつくっていきましょう。

今回はここまで。 まだ色々わかってない部分もありますので、自分でも色々試してみて何かあればまたブログに載せたいと思います。

Kaggle Learn

さて、Kaggle Learnです。 Kaggle Learnって何?っていうと、前の記事の続きで、Tutorialsを選ぶと Kaggle Learn と書かれたページに飛びます。

↓こんな感じ f:id:asato418:20180911231716p:plain

で、リンクをクリックすると、下のページに飛びます。 f:id:asato418:20180911231843p:plain

リンク先では、 Python, Machine Learning(機械学習)、Pandas, Data Visualizaition, SQL, R, Deep Learning についてのコースがあります。

色々と、各々の項目についての初歩の解説があるので、興味のあるかたは読んでいくのもよいかもしれません。・・・ 

と、なんか私にとって興味があることが一杯だったので脱線していろんなことやってたら時間がかなりすぎてしまいました。。 (機械学習のところ読んだり、 Jupyter Labでのスライドショーの作成のページ読んだりしてたら1時間以上過ぎてた。。。)

続きは明日。。

Kaggle: Titanic: Machine Learning from Disaster(内容)

さて、Kaggleです。 Prarctice Skillsの所に行くと

Competition Description

The sinking of the RMS Titanic is one of the most infamous shipwrecks in history. On April 15, 1912, during her maiden voyage, the Titanic sank after colliding with an iceberg, killing 1502 out of 2224 passengers and crew. This sensational tragedy shocked the international community and led to better safety regulations for ships. One of the reasons that the shipwreck led to such loss of life was that there were not enough lifeboats for the passengers and crew. Although there was some element of luck involved in surviving the sinking, some groups of people were more likely to survive than others, such as women, children, and the upper-class. In this challenge, we ask you to complete the analysis of what sorts of people were likely to survive. In particular, we ask you to apply the tools of machine learning to predict which passengers survived the tragedy.

Practice Skills

・Binary classification ・Python and R basics とあって、その下に動画なんかも貼ってあります。当然全部英語です。 まあ一応私 TOEIC 900点とったこともあり、この程度の英語であれば平気です(ちょっと自慢げ)
さらっと英語を読んでみると ・タイタニック号の沈没は歴史上もっとも有名な難破です。 ・1912年 4/15日、処女航海中に、タイタニックは氷山にぶつかって沈み、2224人の乗客及乗組員のうち、1502人が死亡。 ・センセーショナルな悲劇は国際コミュニティにショックを与え、船の安全基準をよくする動きにつながりました。 ・難破がそれだけの生命を失う事故に至った理由の一つは、乗客及び乗組員のための究明暴徒が十分になかったことです。沈没から生き残るいくつかの幸運もあったものの、いくつかのグループの人々はその他のグループの人々より生き残っていました。例えば、女性、子供、および上流階級の人々です。 ・このチャレンジでは、どのような種類の人々が生き残りそうであるかの分析をあなた方に競っていただきます。我々は、どの乗客が悲劇から生き残るかを予想する機械学習のツールを適用していただきます。

実践スキル

二項分類 Python 及び R の基礎 ということで、要は Pythonとか Rを使って、どの乗客が生き残るかを予想する機械学習ツールの開発を行うってことですね。(きっと) そもそも二項分類(Binary Classification)って何?って感じですが。。まあチュートリアルやればわかるようになる。。と信じてみます。

閑話 今実際にコンペが行われているものとしては、

TGS Salt Identification Challenge | Kaggle

がありますね。賞金 100,000 $ だそうです。一人で勝ち取ればウハウハですね(夢)

f:id:asato418:20180911230501p:plain

Overview (概要)のDescription(記述)を読み終えると、その下には Evaluation(評価) Tutorials (チュートリアル) Frequently Asked Questions (よくある質問。いわゆる FAQ) があり、さらに上のメニューには Data, Kernels, Discussion, Leaderboard, Rules, Team という項目があります。 まあ、素直に Evaluation, Tutorialsへと進みます。 Evaluationには、

Goal

It is your job to predict if a passenger survived the sinking of the Titanic or not. For each PassengerId in the test set, you must predict a 0 or 1 value for the Survived variable.

Metric

Your score is the percentage of passengers you correctly predict. This is known simply as "accuracy”.

Submission File Format

You should submit a csv file with exactly 418 entries plus a header row. Your submission will show an error if you have extra columns (beyond PassengerId and Survived) or rows. The file should have exactly 2 columns: PassengerId (sorted in any order) Survived (contains your binary predictions: 1 for survived, 0 for deceased)
と書かれてます。 まあ要するに、先ほど概要の所で書いてあった、生き残り予測をおこなって、正確性を競うってことが書いてあります。で、ファイルフォーマットは 892, 0 893, 1 というように、乗客IDと、生き残ったか(1), なくなったか(0) かというフォーマットで提出するってことのよう。
長くなったので、チュートリアルは次の記事に書きます

Kaggle

さて、とにかく何か新しいことを始めよう。。。

ということで最近話題の? kaggle
Kaggle: Your Home for Data Science にアカウントを作成してみました。

Pythonを選ぶと、次のようなメニューが f:id:asato418:20180910235525p:plain

今日は自動投稿のバグ取りに時間がかかっちゃいましたが、ちょっと Kaggleを勉強していきたいと思います。

ちょろっとだけ、多くの人が試しているタイタニック号のテストデータを見るところまでだけ進めました。

f:id:asato418:20180911000904p:plain

Jupyter Notebookはcsvとかの表示も簡単にできていいですよね。 明日から他の人がやってるチュートリアルに沿って試していきたいと思います。

バグ対応(https://kyouno-ryouri.hatenadiary.jp/)

まあただの実験だったので放置でもいいんですが、さすがに毎日同じ料理の情報が書き込まれ続けるのは恥ずかしいので、簡単な逃げを。。

一番先頭の料理情報だけをとってたんですが、とりあえず find_allにして、全リストをとってきたうえで、乱数でどれか一つを表示する形に変更しました。まあたまには同じ料理が続く場合があるかもしれませんが、まあそれは放置(w

まあ超適当に記事をとってくる部分を簡単に修正。。。

def get_todays_food():
    # ヘッドラインニュースのタイトル格納用リスト
    news_data = []

    # urlの指定
    url="https://www.kyounoryouri.jp"
    search_url = "https://www.kyounoryouri.jp/recipe/ranking"

    # ユーザーエージェントを指定
    ua = 'Mozilla/5.0 (Windows NT 10.0; WOW64; rv:60.0) '\
     'AppleWebKit/537.36 (KHTML, like Gecko) '\
     'Gecko/20100101 Firefox/60.0 '

    req = urllib.request.Request(search_url, headers={'User-Agent': ua})

    #htmlの取得
    html = urllib.request.urlopen(req)
    # htmlパース
    soup = BeautifulSoup(html, "html.parser")
    topicsindex = soup.find('div', attrs={'class': 'recipe--ranking-list'})

    # class「topicsindex」内から記事タイトルを抽出
    list1=topicsindex.find_all('img')
    list2=topicsindex.find_all('div',class_='col')
    num=random.randint(0,len(list1)-1)

    # 記事タイトルとURLを保存
    link=url+list1[num].get('src')
    #print(link)
    body=url+list2[num].get('data-url')
    #print(body)
    title=list1[num].get('alt')
    #print(title)
    news_data.append([title,body,link])

    return news_data

ついでに、今まで夜 8:00に動かしてたんですが朝の方がなにかとバグとかに気づくし、その気になれば自分で手修正したりとかもできるので、朝8:00 に1回だけ動くように変更しました。

from apscheduler.schedulers.blocking import BlockingScheduler
import os

sched = BlockingScheduler()

#@sched.scheduled_job('interval', minutes=720)
#def timed_job():
#       os.system("python hatenapost2.py")
#       os.system("python hatenapost.py")

@sched.scheduled_job('cron', hour=8)
def scheduled_job():
        os.system("python hatenapost1.py")
        os.system("python hatenapost2.py")
        os.system("python hatenapost3.py")
        os.system("python hatenapost4.py")

sched.start()

数回テストしただけで同じ記事が2回出てきたのでダメかもしれないけど、まあいいや。。大したことない処理を簡単に直そうとおもっただけなのに案外時間がかかった。 自動投稿はバグ対応以外は一旦やめて他のことをやろう。。。

そしてこっちは仕様のミス(というか考えが足らなかった)

昨日新しく作った、

kyouno-ryouri.hatenadiary.jp

のページですが、今日もきちんと動きました。。。が、記事が昨日と同じ。。アレ?とおもっってリンク元の記事見たら、そのページは人気順位を出しているので、1位が毎日必ず変わるわけじゃないのでした。。

ということで私が作った処理だと、1位が変わらない限り毎日同じ記事をリンクすることになるという。。。

まあリンク元の記事をよく読んでなかったからしょうがないですね(アホ)。 一応広告が昨日の広告と違う広告になってはいます(^^

まあ今日はだいぶお酒のんじゃったのでどう変更するか明日以降に考えます。。

【heroku】ビルド失敗。。。

なんか自動投稿されないと思ったら、herokuでビルドが失敗してた。。

ase.py", line 918, in _create_trigger
2018-09-08T16:18:19.665649+00:00 app[clock.1]: return self._create_plugin_instance('trigger', trigger, trigger_args)
2018-09-08T16:18:19.665654+00:00 app[clock.1]: File "/app/.heroku/python/lib/python3.6/site-packages/apscheduler/schedulers/base.py", line 903, in _create_plugin_instance
2018-09-08T16:18:19.666080+00:00 app[clock.1]: return plugin_cls(**constructor_kwargs)
2018-09-08T16:18:19.666108+00:00 app[clock.1]: TypeError: __init__() got an unexpected keyword argument 'hours'

新しく特定時間に1回だけ実行する処理の設定を、hours とか書いてたけど sはいらなかったようだ。。。

きちんと heroku logs で確認しないとだめだな。

from apscheduler.schedulers.blocking import BlockingScheduler
import os

sched = BlockingScheduler()

#間隔は1分ごとにしています
#minutesではなくてhourに変更したら、時間での指定も可能です
@sched.scheduled_job('interval', minutes=720)
def timed_job():
        os.system("python hatenapost2.py")
        os.system("python hatenapost.py")

@sched.scheduled_job('cron', hour=20)
def scheduled_job():
        os.system("python hatenapost3.py")

sched.start()

hours を hour に直してデプロイしなおして、今度はうまくいったようだ。。。明日実際動くのを確認する。

2018-09-08T17:08:27.000000+00:00 app[api]: Build started by user asa418@nifty.com
2018-09-08T17:08:42.747312+00:00 app[api]: Release v14 created by user asa418@nifty.com
2018-09-08T17:08:42.747312+00:00 app[api]: Deploy 2b8f66ef by user asa418@nifty.com
2018-09-08T17:08:43.234843+00:00 heroku[clock.1]: State changed from crashed to starting
2018-09-08T17:08:48.281287+00:00 heroku[clock.1]: Starting process with command `python timeclock.py`
2018-09-08T17:08:48.918123+00:00 heroku[clock.1]: State changed from starting to up
2018-09-08T17:08:51.000000+00:00 app[api]: Build succeeded