ナンバーズ3のWebページを解析し結果をMySQLに登録して出現頻度のヒストグラム表示するPythonサンプルプログラムをVisual Studio Codeで作成して実行する
1.概要
Webページからデータを取ってきて、データベースに格納し、解析するまでの大まかな流れを試す。
対象のデータには、構造も簡単でデータ件数もほどほど(数千件)あるナンバーズ3の結果を使用してみる。
http://www.takarakujinet.co.jp/numbers3/index2.html
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')
登録できた!
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)
出現値の分布ヒストグラムを表示できた!
以上。
