こんにちは。ツバサです。家計簿のカード連携を自力でやってみようの第1回です。
今回は楽天カードのenaviへログインし、利用明細(csv)をダウンロードするまでを実装します。このプロジェクトの全体像についてはPart0に書いています。ぜひこちらもご覧ください↓
現在の動作環境はMac OS 11.2 python3.8です。
Mac OS のアップデートしないといけないですね・・・
フロー
明細をDLするフローはざっくりこんな感じです。
- 昨日(前回)DLした明細をyesterday.csvにリネーム
- enaviへログイン
- 1枚目のカードの明細をDL
- 2枚目のカードの明細をDL
- 3と4でDLした明細を合体
注意点
注意点は3つあります。
1つ目は、利用金額が確定しているかどうかです。
確定していると「次月」のボタンが押せるようになります。
最新月のデータが今月利用分のデータなので、「次月」ボタンが押せる時は押さないといけないです。
2つ目は、カードの選択についてです。
このセレクトボックスをクリックする時は、都度セレクトボックスのxpathを取得してください。
そうしないと、selenium.common.exceptions.StaleElementReferenceExceptionの例外が出ます。
詳しくはこちら↓
また、このセレクトボックスのxpathがたまに変わる?みたいで急にクリックできん!ってエラーが出て止まることがあります。その時は都度xpathを修正しています。
3つ目はDLボタンが広告で隠れてしまい、seleniumでクリックできないことです。
そのため、DLの処理だけはrequestsを使っています。
ここに関しては、参考にさせていただいた記事があります。それをこの記事の最後に紹介します。
プログラム
完成したプログラムを記載します。114行目のmain関数から処理が始まります。
import os
import time
from selenium import webdriver
from selenium.webdriver.support.select import Select #セレクトボックス
from webdriver_manager.chrome import ChromeDriverManager #webdriver自動更新用
import requests
import csv
import keyring
# ① 昨日のデータの名前変更
def rename_csv_file(old_filename, new_filename):
try:
os.rename(old_filename, new_filename)
print(f"File '{old_filename}' renamed to '{new_filename}' successfully.")
except OSError as e:
print(f"Error: {e}")
def get_today_csv():
# ② enaviへログインする
# ユーザ情報
user = "****"
pw = keyring.get_password('rakuten', user)
#DL先のディレクトリを指定しておく
script_path = os.path.abspath(__file__)
download_dir = os.path.dirname(script_path)
driver = webdriver.Chrome(ChromeDriverManager().install()) #webdriver自動更新して実行
#chrome
#楽天のログインページ
driver.get('https://www.rakuten-card.co.jp/e-navi/members/statement/index.xhtml?l-id=enavi_all_glonavi_statement')
#ページが開くまで待機
time.sleep(5)
#ID入力フォームを取得
_user = driver.find_element_by_name('u')
#pw入力フォームを取得する
_pw = driver.find_element_by_name('p')
_user.send_keys(user)
_pw.send_keys(pw)
#ログインボタン押下
driver.find_element_by_id('loginButton').click()
time.sleep(3)
# ③ 1枚目のカードを選択
card = driver.find_element_by_xpath('/html/body/div[2]/div/div[2]/div[4]/div[2]/form/div[2]/select')
select = Select(card)
select.select_by_index(0) # 1枚目のカードを選択
# 次月ボタンが押せるなら押す
nextMonthButton = driver.find_elements_by_class_name('stmt-head-calendar__next')
if nextMonthButton:
nextMonthButton[0].click()
# csvをダウンロードする
href = 'https://www.rakuten-card.co.jp/e-navi/members/statement/index.xhtml?downloadAsCsv=1'
download_path1 = os.path.join(download_dir, 'card1.csv')
c = {}
for cookie in driver.get_cookies():
c[cookie['name']] = cookie['value']
# requestsを利用してデータのダウンロード
r = requests.get(href, cookies=c)
with open(download_path1, mode='wb') as f:
f.write(r.content)
# ④ 2枚目のカードを選択
card = driver.find_element_by_xpath('/html/body/div[2]/div/div[2]/div[4]/div[2]/form/div[2]/select')
select = Select(card)
select.select_by_index(1) # 2枚目のカードを選択
# 次月ボタンがあったら押す
nextMonthButton = driver.find_elements_by_class_name('stmt-head-calendar__next')
if nextMonthButton:
nextMonthButton[0].click()
# # Chromeからクッキーデータを得る
# csvをダウンロードする
download_path2 = os.path.join(download_dir, 'card2.csv')
c = {}
for cookie in driver.get_cookies():
c[cookie['name']] = cookie['value']
# requestsを利用してデータのダウンロード
r = requests.get(href, cookies=c)
with open('card2.csv', mode='wb') as f:
f.write(r.content)
#5sec待機
time.sleep(5)
driver.quit()
# ⑤ 2つのcsvを合体
data = []
with open(download_path1, mode='r') as file:
reader = csv.reader(file)
for row in reader:
data.append(row)
with open(download_path2, mode='r') as file:
reader = csv.reader(file)
next(reader) # 最初の行をスキップする
for row in reader:
# 行の処理
data.append(row)
today_path = './today.csv'
with open(today_path, mode='w',newline='') as file:
writer = csv.writer(file)
writer.writerows(data)
def main():
old_file = "today.csv"
new_file = "yesterday.csv"
# ① 昨日取得した明細をリネーム
rename_csv_file(old_file, new_file)
get_today_csv()
main()
2枚カードがあるのでダウンロードを2回実施します。
for文で書いた方がプログラムの行数は短くなりますが、所詮2回です。今回は愚直にダウンロードしていきます。
また、ログイン部分はkeyringというモジュールを使ってMacBookのキーチェーンに保存してあるパスワードを読み出します。
キーチェーンには「rakuten」という名前でパスワードを保存しています。この名前とユーザIDを指定することでパスワードの読み出しができます(プログラムの22行目)。
キーチェーンの画面はこんな感じです↓
まとめ
keyringを使うことで、パスワードの手入力不要、かつソースコードに埋め込み不要にできたことがGOODでした。
できればユーザIDも埋め込みたくないんですが、keyringはパスワードの取得しか出来ないみたいです・・・
次回は、本記事のプログラムで作成したyesterday.csvとtoday.csvの差分を出して、家計簿へ新たに登録が必要なデータだけを抽出します。
参考にしたサイト
明細をDLするところで、こちらの記事を参考にさせていただきました。
コメント