outlier

建築士、プログラミング、ライフハック、etc.

Pythonでマネーフォワードをスクレイピングして、ポートフォリオを管理する(その1)

Pythonの勉強がてら、マネーフォワードのサイトから口座残高などの情報をスクレイピングしてきて、日々のポートフォリオを作成するというコードを書いてみました。

いろいろと勉強になることたくさんでして、忘れないように記録しておきます。(その1)では、プログラム作成の動機や内容などを、(その2)では実際のコーディングにあたってはまった点などを紹介します。

マネーフォワードの良さと問題点

マネーフォワードは、銀行・証券会社・クレジットカードの情報を登録しておくと、口座残高やカード使用履歴などを記録してくれるアプリで、すでに多くのひとが活用していると思います。

moneyforward.com

マネーフォワードの機能のひとつに、現在保有している資産の内訳や資産履歴をグラフ化してくれるものがあります。現金や預金だけでなく、株や投資信託の評価額も含めて資産管理をしてくれる点がとても便利ですが、1点こまったことがあります。それは、資産の区分が、「預金」、「株式」、「投資信託」、「債券」、「不動産」、「年金」、「ポイント・マイル」という分類で出力されること。

f:id:lucky-radio:20180714120913p:plain

私の現在の資産運用は、以下の本などで紹介されている、低コストのインデックス投資信託を中心としたものです。よって、アセットアロケーションを意識して分類して、「流動資産」「国内債券」「国内株式」「海外債券」「海外株式」といった分け方をしたほうが、全体の資産状況を把握しやすいと考えました。

内藤忍の資産設計塾【第4版】 (豊かな人生に必要なお金を手に入れる方法)

内藤忍の資産設計塾【第4版】 (豊かな人生に必要なお金を手に入れる方法)

 

今までは、それぞれの銀行や証券会社のサイトから残高をダウンロードして、エクセルで集計していたのですが、なかなか面倒くさい。ということで、Pythonで自動化を試みました。

やりたいこと

実際にやろうとしたことは、以下のようになります。

  • マネーフォワードに自動的にログイン
  • 資産内訳のページにアクセスし、保有している資産の名前と評価額をスクレイピング
  • それぞれの保有資産を、「流動資産」「国内債券」「国内株式」「海外債券」「海外株式」に分類し、アセットごとの合計を計算
  • その結果をcsvファイルに保存。また、グラフ化して画像も保存

実装したコード

実際に作成したコードはこちら。まだまだ洗練されておらず、だいぶ泥臭いところも多々ありますが。

### STEP0:初期設定
from selenium import webdriver
from selenium.webdriver.common.by import By
import pandas as pd
import datetime
import matplotlib.pyplot as plt

browser = webdriver.Chrome()
df = pd.read_csv("default.csv",index_col=0)
asset_type_list = pd.read_csv("asset_type_list.csv",encoding="SHIFT-JIS")

# アセットリストファイルを参照して、アセット種別を判定する関数
def get_asset_type(name):
    for i in range(len(asset_type_list.index)):
        if name == asset_type_list["name"][i]:
            asset_type = asset_type_list["asset_type"][i]
            return asset_type

### STEP1:マネーフォワードにログイン
url = "https://moneyforward.com/users/sign_in"
user_name = " ここにメールアドレスを入力"
password = " ここにパスワードを入力"
browser.get(url)
#メールアドレスを入力
e = browser.find_element_by_id("sign_in_session_service_email")
e.clear()
e.send_keys(user_name)
# パスワードを入力
e = browser.find_element_by_id("sign_in_session_service_password")
e.clear()
e.send_keys(password)
# ログインボタンを押す
frm = browser.find_element_by_name("commit")
frm.click()

### STEP2:資産内訳のページへ移動し、保有資産の現在評価額を取得
url_bs = "https://moneyforward.com/bs/portfolio"
browser.get(url_bs)
icount = 0

#(1)資産内訳の表を取得
table_total_asset = browser.find_element_by_class_name("table-bordered")
trs = table_total_asset.find_elements(By.TAG_NAME,"tr")  # テーブルの行数を取得
# 資産内訳の表を出力して確認
for i in range(len(trs)):
    name = trs[i].find_elements(By.TAG_NAME,"th")[0].text
    values = trs[i].find_elements(By.TAG_NAME,"td")
    print(name,":",values[0].text,values[1].text)

#(2)預金・現金・仮想通貨の表を取得
table_depo = browser.find_element_by_class_name("table-depo")
trs = table_depo.find_elements(By.TAG_NAME,"tr")
nrow = len(trs)
for i in range(1,nrow):
    depo_name = trs[i].find_elements(By.TAG_NAME,"td")[0].text
    depo_value = trs[i].find_elements(By.TAG_NAME,"td")[1].text
    icount += 1
    depo_type = get_asset_type(depo_name)
    print(icount,depo_name,depo_value,depo_type)
    depo_value = int(depo_value.replace("円","").replace(",",""))
    se = pd.Series([depo_name,depo_value,depo_type],["name","value","asset_type"])
    df = df.append(se,ignore_index=True)    

#(3)株(現物)の表を取得
table_eq = browser.find_element_by_class_name("table-eq")
trs = table_eq.find_elements(By.TAG_NAME,"tr")
nrow = len(trs)  # ヘッダー行を含めた行数
###  表の2列目を銘柄名、6列目を現在の評価額として抽出する
for i in range(1,nrow):
    eq_name = trs[i].find_elements(By.TAG_NAME,"td")[1].text
    eq_value = trs[i].find_elements(By.TAG_NAME,"td")[5].text
    icount += 1
    eq_type = get_asset_type(eq_name)
    print(icount,eq_name,eq_value,eq_type)
    eq_value = int(eq_value.replace("円","").replace(",",""))
    se = pd.Series([eq_name,eq_value,eq_type],["name","value","asset_type"])
    df = df.append(se,ignore_index=True)    

#(4)投資信託の表を取得
table_mf = browser.find_element_by_class_name("table-mf")
trs = table_mf.find_elements(By.TAG_NAME,"tr")
nrow = len(trs)
#銘柄名と評価額を抽出
for i in range(1,nrow):
    mf_name = trs[i].find_elements(By.TAG_NAME,"td")[0].text
    mf_value = trs[i].find_elements(By.TAG_NAME,"td")[4].text
    icount += 1
    mf_type = get_asset_type(mf_name)
    print(icount,mf_name,mf_value,mf_type)
    mf_value = int(mf_value.replace("円","").replace(",",""))
    se = pd.Series([mf_name,mf_value,mf_type],["name","value","asset_type"])
    df = df.append(se,ignore_index=True)    


### STEP3:アセット種別の分類、データの保存、グラフ化
# ブラウザを終了
browser.close()

# 日付をファイル名につけて、その日の資産一覧(df)を保存
filename1 = "./daily_asset/" + datetime.date.today().strftime("%Y%m%d") + "_asset-list.csv"
df.to_csv(filename1)

# dfから、それぞれのアセットタイプごとに集計
asset_allocation = df.groupby("asset_type").sum()["value"]
print(asset_allocation)

# グラフ化して保存
#※グラフ化の際、凡例を日本語にすると文字化けしたので、英語に変換
asset_allocation = asset_allocation.rename(index={"その他資産":"other","国内債券":"Domestic-bonds","国内株式":"Domestic-stocks","流動資産":"current-assets","海外債券":"foriegn-bonds","海外株式":"foriegn-stocks"})

fig = plt.figure()
ax = fig.add_subplot(1,1,1)
ax.pie(list(asset_allocation),labels=asset_allocation.index,counterclock=False,startangle=90,autopct="%1.1f%%")
title = "date: " + datetime.date.today().strftime("%Y/%m/%d") + "  Total: " + '{:,}'.format(sum(asset_allocation)) + "JPY"
ax.set_title(title)
filename2 = "./daily_asset/" + datetime.date.today().strftime("%Y%m%d") + "_asset-pi-chart.png"
fig.savefig(filename2)

結果

アウトプットとしては、以下のように現在の資産合計とアセットごとの比率がグラフ化されます。

f:id:lucky-radio:20180714120359p:plain

 

ということで、Pythonによるスクレイピングで、マネーフォワードのデータからポートフォリオを作成するプログラムでした。次回、プログラムの中身と作成する際にはまった点などを書きたいと思います。