Anaconda がエラーでどうしようもないので、Eclipse+PyDevにDjango REST frameworkの開発環境を戻したが、Visual Studio Code が十分使えそうなので、Visual Studio Code に環境を構築する。

venv 仮想環境は共用するのでこちらを参照、EclipseとPydevの環境構築はせずに、適当なフォルダをVisual Code で開き、端末から、venv 仮想環境をアクティベート。

そのあと、Django プロジェクトを作成する。

https://docs.djangoproject.com/en/1.11/intro/tutorial01/

(django) PS C:\workspaces\vscode\django_api_lesson> django-admin startproject firstapi

djangoapi_code01

試しにDjango サーバーを起動してみる。

(django) PS C:\workspaces\vscode\django_api_lesson\firstapi> python .\manage.py runserver
Performing system checks...

System check identified no issues (0 silenced).

You have 13 unapplied migration(s). Your project may not work properly until you apply the migrations for app(s): admin, auth, con
tenttypes, sessions.
Run 'python manage.py migrate' to apply them.
May 01, 2017 - 16:24:30
Django version 1.11, using settings 'firstapi.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CTRL-BREAK.

OK

djangoapi_code02

Anaconda やめて PyDev でDjango REST 設定 と同様、ソースコードを編集したのち、コマンドを実行してデータベースを作成する。

(django) PS C:\workspaces\vscode\django_api_lesson\firstapi> python .\manage.py migrate
Operations to perform:
  Apply all migrations: admin, auth, contenttypes, sessions
Running migrations:
  Applying contenttypes.0001_initial... OK
  Applying auth.0001_initial... OK
  Applying admin.0001_initial... OK
  Applying admin.0002_logentry_remove_auto_add... OK
  Applying contenttypes.0002_remove_content_type_name... OK
  Applying auth.0002_alter_permission_name_max_length... OK
  Applying auth.0003_alter_user_email_max_length... OK
  Applying auth.0004_alter_user_username_opts... OK
  Applying auth.0005_alter_user_last_login_null... OK
  Applying auth.0006_require_contenttypes_0002... OK
  Applying auth.0007_alter_validators_add_error_messages... OK
  Applying auth.0008_alter_user_username_max_length... OK
  Applying sessions.0001_initial... OK

管理ユーザーの作成

(django) PS C:\workspaces\vscode\django_api_lesson\firstapi> python .\manage.py createsuperuser
Username (leave blank to use 'pppiroto'):
Email address: pppiroto@gmail.com
Password:
Password (again):
Superuser created successfully.

再度、Djangoサーバーを起動し動作確認

OK

djangoapi_code03

djangoapi_code04

1.概要

Webページからデータを取ってきて、データベースに格納し、解析するまでの大まかな流れを試す。

対象のデータには、構造も簡単でデータ件数もほどほど(数千件)あるナンバーズ3の結果を使用してみる。

http://www.takarakujinet.co.jp/numbers3/index2.html

numbers3_02

2.環境

2.1 Python venv 環境

Visual Studio Code で Python を使えるようにして、NumPy、SciPy、matplotlibは、この間設定したので、venvの環境を有効化し、Webページ解析用、MySQL登録用に以下のライブラリをインストール

仮想環境をアクティブ化

PS C:\workspaces\vscode> cd ..
PS C:\workspaces> cd .\venv\datascience\Scripts\
PS C:\workspaces\venv\datascience\Scripts> .\activate
(datascience) PS C:\workspaces\venv\datascience\Scripts>

関連ライブラリをインストール

(datascience) PS C:\workspaces\venv\datascience\Scripts> pip install beautifulsoup4
(datascience) PS C:\workspaces\venv\datascience\Scripts> pip install lxml
(datascience) PS C:\workspaces\venv\datascience\Scripts> pip install pymysql

2.2 MySQLの設定とテーブルの作成

MySQLをインストールして、テーブルを作成

CREATE TABLE `numbers3` (
  `kaigou` int(11) NOT NULL,
  `chusen_date` date DEFAULT NULL,
  `chusen_num` varchar(3) DEFAULT NULL,
  `straight_kuchi` int(11) DEFAULT NULL,
  `straight_yen` int(11) DEFAULT NULL,
  `box_kuchi` int(11) DEFAULT NULL,
  `box_yen` int(11) DEFAULT NULL,
  `set_straight_kuchi` int(11) DEFAULT NULL,
  `set_straight_yen` int(11) DEFAULT NULL,
  `set_box_kuchi` int(11) DEFAULT NULL,
  `set_box_yen` int(11) DEFAULT NULL,
  `min_kuchi` int(11) DEFAULT NULL,
  `min_yen` int(11) DEFAULT NULL,
  PRIMARY KEY (`kaigou`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

3.サンプルソース

3.1 Webページを解析してデータベース登録

# -*- coding: utf-8 -*-
'''
numbers3 の結果を Database へ登録する
'''
from urllib.request import urlopen
from urllib.parse import urlencode
from bs4 import BeautifulSoup
import re
import math 
import time
import pymysql
from settings import DB_HOST, DB_USER, DB_PASSWORD, DB_SCHEME

DEFAULT_HOWMANY = 100

def save_numbers3_history(from_k, to_k):
    '''
    指定範囲のナンバーズ3の結果をデータベースに取込む
    from_k - 開始回
    to_k - 終了回
    '''
    rec_map = get_numbers3_history(from_k, to_k)

    try:
        con = pymysql.connect(
            host=DB_HOST,
            user=DB_USER,
            password=DB_PASSWORD,
            db=DB_SCHEME,
            charset='utf8mb4',
            cursorclass=pymysql.cursors.DictCursor)

        with con.cursor() as cur:
            for rec in rec_map.values():
                sql = """
                    INSERT INTO `app`.`numbers3`
                    (`kaigou`,
                    `chusen_date`,
                    `chusen_num`,
                    `straight_kuchi`,
                    `straight_yen`,
                    `box_kuchi`,
                    `box_yen`,
                    `set_straight_kuchi`,
                    `set_straight_yen`,
                    `set_box_kuchi`,
                    `set_box_yen`,
                    `min_kuchi`,
                    `min_yen`)
                    VALUES(
                    {0[kaigou]},
                    {0[chusen_date]},
                    {0[chusen_num]},
                    {0[straight_kuchi]},
                    {0[straight_yen]},
                    {0[box_kuchi]},
                    {0[box_yen]},
                    {0[set_straight_kuchi]},
                    {0[set_straight_yen]},
                    {0[set_box_kuchi]},
                    {0[set_box_yen]},
                    {0[min_kuchi]},
                    {0[min_yen]});
                    """.format(rec)
                print(sql)
                cur.execute(sql)
            con.commit()
    except Exception as exception:
        print(exception)
    finally:
        con.close()
    print('finish work')

def get_numbers3_history(from_k, to_k):
    '''
    指定範囲のナンバーズ3の結果を取得する
    from_k - 開始回
    to_k - 終了回
    '''
    result = {}

    start_kai = int(from_k)
    end_kai = int(to_k)
    calc_diff = lambda end_kai, start_kai: end_kai - start_kai + 1
    diff_kai = calc_diff(end_kai, start_kai)
    howmany = DEFAULT_HOWMANY if DEFAULT_HOWMANY < diff_kai else diff_kai

    while end_kai >= start_kai:
        result.update(
            get_numbers3(
                end_kai,
                howmany if calc_diff(end_kai, start_kai) > howmany else calc_diff(end_kai, start_kai)))

        end_kai = end_kai - howmany

    return result

def get_numbers3(kaigou, howmany):
    '''
    指定範囲のナンバーズ3の結果をWEBから取得する
    kaigou - 指定回
    howmany - 指定回を含み、何回過去分を取得するか
    '''

    time.sleep(2)

    result = {}

    post_data = {
        'searchway':'kaigou', # kaigou or day
        'year':'',
        'month':'',
        'day':'',
        'kaigou':kaigou,
        'howmany':howmany
        }

    # HTTP リクエストは、data パラメーターが指定された場合 POST に、指定されない場合に GET になります。
    url = 'http://www.takarakujinet.co.jp/ajax/numbers3/pastResultPage.do'
    html = urlopen(url, urlencode(post_data).encode('utf-8'))
    print("url:{0}, data:{1}", url, post_data)
    soup = BeautifulSoup(html, "lxml")
    #print(soup)
    tr_tag_list = soup.find_all("tr")

    header_keys = [
        'kaigou',
        'chusen_date',
        'chusen_num',
        'straight_kuchi',
        'box_kuchi',
        'set_straight_kuchi',
        'set_box_kuchi',
        'min_kuchi']

    yen_keys = ['straight_yen', 'box_yen', 'set_straight_yen', 'set_box_yen', 'min_yen']

    rec = None
    for tr_tag in tr_tag_list:
        td_tag_list = tr_tag.find_all("td")

        is_header_tr = tr_tag.find('td', {'rowspan':'2'})
        if is_header_tr:
            rec = {}
            td_pos = 0
            for td_tag in td_tag_list:
                val = td_tag.get_text()
                if td_pos == 0:
                    result[val] = rec
                if td_pos == 1:
                    val = re.sub(r'\r\n[ ]*$', r'', val)
                    val = re.sub(r'\r\n[ ]*', r'/', val)
                    val = re.sub(r'/', r'-', val)
                    val = "'{0}'".format(val)
                if td_pos == 2:
                    val = "'{0}'".format(val)
                if td_pos >= 3:
                    if re.match(r'.*該当なし.*', val):
                        val = '0'
                    else:
                        val = re.sub(r'[^0-9]', '', val)
                        if val == '':
                            val = 'null'
                rec[header_keys[td_pos]] = val

                td_pos = td_pos + 1
        else:
            td_pos = 0
            for td_tag in td_tag_list:
                val = td_tag.get_text()
                if re.match(r'.*該当なし.*', val):
                    val = '0'
                else:
                    val = re.sub(r'[^0-9]', '', val)
                assert rec != None, "rec must not be None"
                rec[yen_keys[td_pos]] = val
                td_pos = td_pos + 1

    return result

if __name__ == '__main__':
    save_numbers3_history('1', '11')

登録できた!

numbers3

3.2 ヒストグラムを表示

# -*- coding: utf-8 -*-
'''
ナンバーズ3のヒストグラムを作成
'''
import matplotlib.pyplot as plt
import numpy as np

import pymysql
from settings import DB_HOST,DB_USER,DB_PASSWORD,DB_SCHEME

def get_conn():
    '''
    MySQL コネクションを取得
    '''
    conn = pymysql.connect(
        host=DB_HOST,
        user=DB_USER,
        password=DB_PASSWORD,
        db=DB_SCHEME,
        charset='utf8mb4',
        cursorclass=pymysql.cursors.DictCursor)

    return conn

def fetch_all(sql):
    '''
    SELECT SQLを実行し結果を全件返す
    '''
    conn = get_conn()
    result = {}
    try:
        with conn.cursor() as cur:
            cur.execute(sql)
            result = cur.fetchall()
    finally:
        conn.close()
    return result

def hist_chusen_num(hist_type, pos=None):
    '''
    抽選結果からヒストグラムを生成する
    '''
    #http://matplotlib.org/api/pyplot_api.html#matplotlib.pyplot.bar
    recs = fetch_all('SELECT chusen_num FROM numbers3')
    hist = {}

    if hist_type == 'all':
        # 3桁の整数としての出現頻度
        data_list = [int(rec['chusen_num']) for rec in recs]
        bins = np.arange(0, 1000)
        hist = np.histogram(data_list, bins)
        plt.bar(bins[:-1], hist[0])

    if hist_type == 'num':
        # 1桁ずつの出現頻度
        nested = [list(rec['chusen_num']) for rec in recs]
        data_list = [int(x) for inner in nested for x in inner]
        bins = np.arange(0, 11)
        hist = np.histogram(data_list, bins)
        plt.bar(bins[:-1], hist[0])

    if hist_type == 'pos':
        # 出現位置を指定した頻度
        data_list = [int(list(rec['chusen_num'])[pos]) for rec in recs]
        bins = np.arange(0, 11)
        hist = np.histogram(data_list, bins)
        plt.bar(bins[:-1], hist[0])

    plt.show()
    
if __name__ == '__main__':
    hist_chusen_num('all')
    #hist_chusen_num('num')
    #hist_chusen_num('pos',pos=1)

出現値の分布ヒストグラムを表示できた!

numbers3_03

以上。

Anaconda が全部入ってて便利だと思ったのだが、PC新調で環境構築したら使えないので、VS Code で利用できるように設定する。

1.環境を作る

1.1. venv仮想環境を作成する。

>python -m venv c:\workspaces\venv\datascience

1.2  VS Code 用フォルダを作成

作業用フォルダを作成し、VS Codeで開く

datascience01

1.3 Python拡張機能をインストール

http://qiita.com/bigengelt/items/780440a146e6a3bdffd4

Ctrl + Shift + p から

ext install python

で Python用の拡張機能がリストされるで、Python をインストール

datascience02

1.4 Python の設定

メニュー - ファイル - 基本設定 - 設定

datascience03

  1. settings.json が開くので、設定の検索で python を検索し、Python Configuration に絞り込む。
  2. 画面右上で、ワークスペースの設定を選択し、ワークスペース用に設定を上書き
  3. Pythonおよびライブラリのパスをvenvの環境に上書き

datascience04

// 既定の設定を上書きするには、このファイル内に設定を挿入します
{
    "python.pythonPath":"C:\\workspaces\\venv\\datascience\\Scripts\\python",
    "python.autoComplete.extraPaths": [
        "C:\\workspaces\\venv\\datascience\\Lib\\site-packages"
    ],
}

2.主要ライブラリのインストール

このあたりがAnaconda便利だったのだが、

pip はバイナリからインストールできないから。
pure python でないパッケージはソースからコンパイルしないといけないが、 linux と違って windows には C コンパイラがないことが多いため、 そういうパッケージをインストールできない。そのため windows 向けにバイナリパッケージが用意されている(XXX-1.2.1.win32-py2.7.exe など)。このバイナリパッケージは easy_install なら問題なくインストールできるが、 pip ではインストールできない。

ということで、

Windows で VirtualEnv の Python2.7 に pip と wheel を使って コンパイルエラーが発生するパッケージ(例 scipy)をWindows用バイナリ提供サイトから入手してインストールする

と同じ対応をする(WinPython という手もあるが)。

まず、pip install wheel を行った後、以下をダウンロードし、venvをActivateして、 pip インストール

(datascience) PS C:\workspaces\venv\datascience\Scripts> pip install "C:\Users\pppiroto\Downloads\numpy-1.12.1+mkl-cp36-cp36m-win32.
whl"
Processing c:\users\pppiroto\downloads\numpy-1.12.1+mkl-cp36-cp36m-win32.whl
Installing collected packages: numpy
Successfully installed numpy-1.12.1+mkl
(datascience) PS C:\workspaces\venv\datascience\Scripts> pip install "C:\Users\pppiroto\Downloads\scipy-0.19.0-cp36-cp36m-win32.whl"

Processing c:\users\pppiroto\downloads\scipy-0.19.0-cp36-cp36m-win32.whl
Requirement already satisfied: numpy>=1.8.2 in c:\workspaces\venv\datascience\lib\site-packages (from scipy==0.19.0)
Installing collected packages: scipy
Successfully installed scipy-0.19.0
(datascience) PS C:\workspaces\venv\datascience\Scripts> pip install "C:\Users\pppiroto\Downloads\matplotlib-2.0.0-cp36-cp36m-win32.
whl"
Processing c:\users\pppiroto\downloads\matplotlib-2.0.0-cp36-cp36m-win32.whl
 :
Installing collected packages: pyparsing, six, python-dateutil, cycler, pytz, matplotlib
Successfully installed cycler-0.10.0 matplotlib-2.0.0 pyparsing-2.2.0 python-dateutil-2.6.0 pytz-2017.2 six-1.10.0

3.デバッグ

ライブラリの確認もかねてデバッグを行う。

  1. 画面左端の、虫禁止アイコンを選択
  2. 画面上部のデバッグ構成で、Pythonを選択
  3. デバッグ 横の再生アイコンを選択すると、画面上部にデバッグコントロールアイコンが表示される
  4. 画面上部に表示されたコントロールアイコンから、実行ボタンを押下
  5. デバッグコンソールに各ライブラリのバージョンが表示

datascience09

datascience10

以上。