でんき家計簿 (くらしTEPCO) をスクレイピングしてみた (30分毎電力データ)
Abstract
PythonからくらしTEPCO経由ででんき家計簿にログインして、 自宅の30分電力使用量データを遡れるだけ取得してみた。
Introduction
前回からの続きです。
くらしTEPCOのアカウントを使ってでんき家計簿にログインし、30分電力値データを遡れるだけ取得してみた。
Setup and Results
前準備
- 前回と同じ
どこにアクセスすればデータが取れるのか?
前回の時点で、月毎電力データのページまではたどり着けた。ここから更に進めてみる。
時間別ページに飛ぶためのリンクリンクはこんな感じ。
<a href="javascript:void(0);" onclick=" createHiddenTag(fnjdoc.forms['syo_electricUsageAmountActionForm'], new Array('xxxxxxxx','yyyyyyyyyyyyy'), new Array('key.officeCd', 'key.visitNum'), true); return submitForm(fnjdoc.forms['syo_electricUsageAmountActionForm'], '/dk/syo/electricUsageAmount/goElectricUsage30minGraph', null);">
月別使用量ページの表示とほぼ同じだが、 追加でofficeVisitCd = xxxxxxxx/yyyyyyyyyyyyy と、ヘッダのRefererとして遷移元のurlを指定しないといけないみたい。
htmlからの数値読み出しは、でんき家計簿側のコードが変更されないことを祈って、形式固定の力技で抜き出してみた。 (本当はjsのパーサと書けばよいのだろうけど...)
データが抜き出せたら、前日データの表示用のリンクから同様のことを繰り返す。
コード
# 30分値表示ページから、数値データを抜き出す def getData(html_text): def getCDATA(text): ret = "" isInCDATAArea = False for l in text.split("\n"): l = l.strip() if (l == "// <![CDATA["): isInCDATAArea = True elif (l.strip() == "// ]]>"): isInCDATAArea = False if(isInCDATAArea): ret += l + "\n" return ret d = {} function = "" for l in getCDATA(html_text).split("\n"): if(l.startswith("function")): function = l.split("function")[1].split("()")[0].strip() if(function.startswith("vbar_usage_grp")): d[function] = {} if(function.startswith("vbar")): if(l.startswith("var items = ")): d[function]["items"] = json.loads(l.split("=")[-1].strip(";")) html = BeautifulSoup(html_text, "html.parser") date_str = html.find(id="motion_area1").find_all("td")[1].contents[0] date = datetime.datetime.strptime(date_str.split("\u3000")[0], '%a %b %d %H:%M:%S JST %Y') return (date, d["vbar_usage_grp"]["items"][0][1:-1]) # 前日移動に必要な情報 def getParamsToMovePrev(html_text): html = BeautifulSoup(html_text, "html.parser") link_js = html.find(id="motion_area1").find("a")["onclick"] #print(link_js) key_d = link_js.split("'")[3] key_date = link_js.split("'")[5] post_to = link_js.split("'")[13] return(key_d, key_date, post_to) # 前日の30分データ表示ページ を取得 def getPrev(key_d, key_date, post_to): param = { 'key.d': key_d, 'key.date': key_date } header = { 'Referer':data_page.url } data_page_30min = session.post( 'https://www.kakeibo.tepco.co.jp'+post_to, data=param, headers=header) data_page_30min.encoding = data_page_30min.apparent_encoding return data_page_30min.text #取得可能な30分値データを、全て取得 current_page = data_page_30min.text with open("./usage30min.csv", "w") as f: while True: d, date, post_to = getParamsToMovePrev(current_page) current_page = getPrev(d, date, post_to) data = getData(current_page) if(len(data[1]) != 48): break f.write(data[0].strftime('%Y-%m-%d')) for usage in data[1]: f.write(" ," + str(usage)) f.write("\n") f.flush()
実行結果
くらし家計簿から、30分毎電力値を取得し、csvファイルに書き出した。
Reference
でんき家計簿 (くらしTEPCO) をスクレイピングしてみた (月毎電力データ)
Abstract
PythonからくらしTEPCO経由ででんき家計簿にログインして、 自宅の月毎電力使用量データを取得してみた。
Introduction
自宅の電力計がスマートメーター化され、東京電力のくらしTEPCOというサイトから自宅の30分電力使用量が取得できるらしい。 ただ私の場合、契約が電力自由化前のものであるため、調べてみるとでんき家計簿という別のサイトを使わないと電力値の取得ができないことが判明。
幸いくらしTEPCO経由ででんき家計簿にログインする方法が用意されていた。 くらしTEPCOのアカウントを使ってでんき家計簿ログインし、手始めに月毎電力値データ表示ページを取得してみた。
Setup and Results
前準備
- 前回と同じ
どこにアクセスすればデータが取れるのか?
くらしTEPCOのログイン後マイページにはでんき家計簿へのリンクがある。
この部分のHTMLはこんな感じ。
くらしTEPCOにログインした状態で https://www.kakeibo.tepco.co.jp/pf/ja/pco/mypage/redirect-sso.page?sitekbn=kakeibo に行くと、でんき家計簿の会員ホームに飛ばされるということみたい。
未ログイン状態だと普通にログインフォームが表示されるので、どうやらでんき家計簿もくらしTEPCOと同じ要領でやれば良さそう。
でんき家計簿ログイン後に、電力使用値を表示するページに移動するための「使用量と料金をグラフで見る」リンクはこんな感じ。
<a href="javascript:void(0);" onclick=" createHiddenTag(fnjdoc.forms['com_menuActionForm'], new Array('xxxxxxxx','yyyyyyyyyyyyy','amount'), new Array('key.officeCd', 'key.visitNum', 'key.display'), true); return submitForm(fnjdoc.forms['com_menuActionForm'], '/dk/com/menu/goElectricUsageAmount', null); ">
key.officeCd = xxxxxxxxxとkey.visitNum=yyyyyyyyyyyyyを/dk/com/menu/goElectricUsageAmountにpostすればよいみたい。 これで月別使用量のページが得られる。
データ自体はhtml内部の// <![CDATA[
と書かれた領域に埋め込まれていた。
この領域をひとまず切り出して、後は力技で該当部分を切り出してみる。
コード
# くらしtepcoからでんき家計簿にログイン param = { 'ACCOUNTUID': username, 'PASSWORD': password, 'HIDEURL': '/ls/pf/ja/pco/mypage/redirect-sso.page?sitekbn=kakeibo', 'LOGIN': 'EUAS_LOGIN', } header = { 'Referer': 'https://www.kakeibo.tepco.co.jp/dk/com/menu/' } login = session.post( 'https://www.kurashi.tepco.co.jp/kpf-login', data=param, headers=header) login.encoding = login.apparent_encoding # 月ごとデータへの移動リンクで発火するjs関数から、必要な情報を抜き出す html = BeautifulSoup(login.text, "html.parser") link_js = html.find(id="frame3").find(class_="box01 box firstBox").find("a")["onclick"] #print(link_js) key_officeCd = link_js.split("'")[3] key_visitNum = link_js.split("'")[5] key_display = link_js.split("'")[7] post_to = link_js.split("'")[17] # 月ごとデータの表示ページ に移動 param = { 'key.officeCd': key_officeCd, 'key.visitNum': key_visitNum, 'key.display': key_display } header = { 'Referer':login.url } data_page = session.post( 'https://www.kakeibo.tepco.co.jp'+post_to, data=param, headers=header) data_page.encoding = data_page.apparent_encoding # CDATA領域を切り出し def getCDATA(text): ret = "" isInCDATAArea = False for l in text.split("\n"): l = l.strip() if (l == "// <![CDATA["): isInCDATAArea = True elif (l.strip() == "// ]]>"): isInCDATAArea = False if(isInCDATAArea): ret += l + "\n" return ret # 月毎データを抜き出す d = {} function = "" for l in getCDATA(data_page.text).split("\n"): if(l.startswith("function")): function = l.split("function")[1].split("()")[0].strip() if(function.startswith("vbar")): d[function] = {} if(function.startswith("vbar")): if(l.startswith("var items = ")): d[function]["items"] = l.split("=")[-1] if(l.startswith("x:")): d[function]["x"] = json.loads(l.split(":")[-1]) if(l.startswith(",y:")): d[function]["y"] = json.loads(l.split(":")[-1]) # 表示 for f in d: print(f) for k in d[f]: print("\t", k, "\t", d[f][k])
実行結果
くらし家計簿から、月毎電力値の表示ページのhtmlを取得し、書かれているデータを抜き出すことができた。
Reference
PythonでくらしTEPCOをスクレイピングしてみた
Abstract
PythonからくらしTEPCO|東京電力のご家庭向け無料Webサービスにログインして、ページ内のユーザー情報を取得してみた。
Introduction
最近、自宅の電力計がスマートメーター化された。で調べてみると、使用電力の30分値が計測されていてデータも取得できるらしい。 www.tepco.co.jp どうせならデータをすべて手元に置いて、分析(の真似事)をしてみたい。 まずはPython経由でくらしTEPCOにログインし、ログイン後に表示されるページのデータを取得する方法を調べてみた。
Setup and Results
前準備
- htmlを解析するため、Beautifulsoupというライブラリをインストール。
pip install beautifulsoup4
くらしTepcoのアカウントを作成しておく。
ログイン情報は設定ファイルから読み込む方式とした。 (本当は環境変数にしたほうが良いのでしょうが。) .passwordという名前で、くらしTEPCOにログインするためのIDとPasswordを書いた以下の設定ファイルを用意しておく。
[settings] username = my_username password = my_password
どこにアクセスすればログインできるのか?
https://www.kurashi.tepco.co.jp/のログインフォームを見てみるとこんな感じ。
要は、https://www.kurashi.tepco.co.jp/kpf-login に対して、
- ACCOUNTUID:
- PASSPWORD:
- HIDE_URL: /pf/ja/pc/mypage/home/index.page?
- LOGIN': EUAS_LOGIN
をPOSTしてやれば良いみたい。
コード
import configparser import requests from bs4 import BeautifulSoup #IDとパスワードをファイルから読み込み config = configparser.ConfigParser() config.read('.password', 'UTF-8') username = config.get("settings", 'username') password = config.get("settings", 'password') # くらしtepcoにログイン session = requests.Session() param = { 'ACCOUNTUID': username, 'PASSWORD': password, 'HIDEURL': '/pf/ja/pc/mypage/home/index.page?', 'LOGIN': 'EUAS_LOGIN', } login = session.post( 'https://www.kurashi.tepco.co.jp/kpf-login', data=param) login.encoding = login.apparent_encoding #ログインページのhtmlから、フッタに書いてあるユーザー情報を取り出してみる html = BeautifulSoup(login.text, "html.parser") for element in html.find("footer").find_all("input"): print(element["name"], element["value"])
実行結果
契約者名とか契約者住所が取得できた。
Conclusion
これでログインが必要なWebサイトであっても、ログイン後の情報がPython経由で取得することができた。 実際のブラウザ上でどのようなアクセスをしているかを一つ一つ確認して、それをプログラム上で再現していく方法が一番早かった。 次は、使用電力量を取得するところまで試してみたい。
Reference
Python+jupyter+plotlyでインタラクティブなグラフを書いてみた
Abstract
jupyter notebook上でPlotlyというグラフライブラリを使い、3次元データをインタラクティブに可視化してみました。
Introduction
Pythonでグラフライブラリと言うと、真っ先に出てくるのがmatplotlib。 ただやはり、グラフを描画することに特化しているのか、プロットしたものをズームするとかマウスオーバーで値を表示とかがサクッとはできないみたい。 そんな中で、Plotlyという良さげなライブラリを見つけたので試してみた。
Setup and Results
Plotlyのインストール。
pip install plotly
プロットする内容
プロットする関数自体は、以前の記事と全く同じ。 あと折角なので、自作したfloat拡張range関数も使ってみた。
コード
import math from plotly.offline import iplot, init_notebook_mode import plotly.graph_objs as go init_notebook_mode(connected=True) x = [_x for _x in drange(0, math.pi, math.pi/100)] y = [_y for _y in drange(0, math.pi, math.pi/100)] z = [] for _y in y: z.append([]) for _x in x: z[-1].append(math.sin(3*_x) * math.sin(2*_y)) data = [ go.Heatmap( x=x, y=y, z=z, colorscale='jet', ) ] iplot(data)
実行結果
カーソル位置のデータ値を表示したり、ズームやオートスケールがブラウザ上のUI操作で可能。
Conclusion
jupyter上で使うなら、matplotlibよりこちらのほうが好みかも。デモもいろいろあるようなので、そのうち試してみようと思います。
Reference
Pythonのrange関数をfloat型に拡張してみた
Abstract
Pythonのrange関数はInt型しか扱えない。0.1 ステップ刻みのようなfloat型でも同じことをやりたかったので、作ってみた。
Introduction
Pythonのrange関数は、整数値にしか使えない。 float型でやろうとするとnumpyのarrange関数を使うという手があるが、そのためだけに "import numpy"するのも気が引ける。
検索すると、以下のような関数を自分で定義するというのが割と知られているらしい。
def frange(start, end, step): for i in range(int((end-start)/step)): yield start + i*step
が、これを実際につかってみると、丸め誤差の影響が出るのであまり美しくない。
for f in frange(1.3, 2.1, 0.1): print(f) #1.3 #1.4000000000000001 #1.5 #1.6 #1.7000000000000002 #1.8 #1.9000000000000001 #2.0
やりたいこと
float型に拡張したrange関数で、かつ、丸め誤差が乗らないようなものを作りたい。
コードと実行結果
from decimal import Decimal def drange(start, end, step): start = Decimal(str(start)) end = Decimal(str(end)) step = Decimal(str(step)) for i in range(int((end-start)/step)): yield float(start + i*step)
for f in drange(1.3, 2.1, 0.1): print(f) #1.3 #1.4 #1.5 #1.6 #1.7 #1.8 #1.9 #2.0
Conclusion
今回は、一度Decimal型に内部で変換して扱うことで丸め誤差を抑えた。 Pythonの標準ライブラリの一部なので、numpyのようにインストールせずとも使えるのがメリット。
Reference
Python+jupyter+matplitlibでヒートマップを書いてみた
Abstract
matplotlibのヒートマップを使い、jupyter notebook上で3次元データを可視化してみました。
Setup and Results
プロットする内容
x, yが100x100の範囲について、z=sin(3πx/100) + sin(2πx/100)という関数をプロットしてみる。
コード
%matplotlib inline import math import matplotlib.pyplot as plt x = [] y = [] z = [] for i in range(0,100): x.append([]) y.append([]) z.append([]) for j in range(0,100): x[i].append(i) y[i].append(j) z[i].append(math.sin(3*math.pi *i/100) * math.sin(2*math.pi *j/100)) plt.pcolormesh(x,y,z, cmap="jet") plt.show()
実行結果
Conclusion
x, y共に2次元配列で渡すのがコツ。オプションで最大最小値やカラーマップも変更できるみたい。
Reference
github.com matplotlib.pyplot.pcolormesh — Matplotlib 3.0.2 documentation
jupyter notebookでPythonプログラミングしてみた
Abstract
jupyter notebookというPythonの実行環境で、hello worldをやってみました。
Setup and Results
jupyterのインストール
ターミナルを開いて以下のコマンドでjupyterをインストール。
pip install jupyer
インストールができたら、適当に作業ディレクトリを作成して以下を実行。
jupyter notebook
ブラウザが開くので、あとは新しくPython3のnotebookを作成するとPythonでコードが書けるようになる。
コード
print("hello world!")
実行結果
実行したいコードが書かれているセルにカーソルをあわせて、Ctrl+Enterで実行。 ブラウザ上で"hello world!" と表示された。
Conclusion
jupyterすごい。コマンドラインで実行するよりも簡単だし、何よりgithubがノートブック形式に対応しているので、やったことがgithub上でそのまま見られる。