S0-ma's Blog

s0-maのブログです。

でんき家計簿 (くらし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

github.com

www.kurashi.tepco.co.jp www.kakeibo.tepco.co.jp