間が空いてしまいましたが、三井住友銀行の取引履歴を取得できるようになりました。
最初は真面目にHTMLをパースしようかと思ったのですが、三井住友銀行では取引履歴を CSV ファイルとして取得する機能があったので、CSV を取得して解析することで手抜きしています。
selenium の webdriver をより便利に使えるように、 webdriver クラスを継承した Browser というクラスを用意しました。webdriver に関してよく使うようなユーティティ関数を追加していこうと思ってます。
クラス図的にはこんな感じ?
仕事ではクラス図をほとんど書かないので、書けるようになるように練習がてらクラス図も書いていこうと思います。途中で投げ出すかもしれませんが。
苦労したのは CSV のダウンロードです。webdriver で CSV をクリックすると、ダウンロードのダイアログが表示されてしまいます。ダイアログの制御は webdriver では難しいらしく、色々調べた結果、webdriver を使わずに requests でダウンロードする方法が見つかりました。
ログイン情報を引き継ぐため、webdriver の cookie をすべて読み出して、requests に設定するのがポイントのようです。ただこの方法のままではうまく動かず、User-Agentも設定してあげる必要がありました。requests での User-Agent の設定は以下の記事を参考にしました。
また、前のブログでは sleep で待ち合わせしていたのですが、キー入力後に値が反映されるまで待つ sync_send_keys() という関数を用意しました。
ソースコードを以下に貼っておきます。main.py の USRID1, USRID2, PASSWORD を書き換えれば動作するはずです。
実行すると、Firefoxが起動してログインし、残高表示ページに遷移して CSV ファイルをダウンロードして表示します。
まずは明細情報を取得することができました。小さな一歩ですが少しだけ進むことができました。Python と Selenium を使うと簡単にスクレイピングできてしまうんですね。実際使ってみてコーディング量の少なさに驚きました。Python 初心者なのでここまでたどり着くのにも非常に時間がかかってしまいましたが、自由に使えるようになったらかなり便利そうです。
#!/usr/bin/python3
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.common.exceptions import NoSuchElementException
from browser import Browser
import csv
URL = "https://direct.smbc.co.jp/aib/aibgsjsw5001.jsp"
USRID1 = "12345"
USRID2 = "67890"
PASSWORD = "1111"
browser = Browser(webdriver.Firefox())
#browser = webdriver.Chrome()
#browser = webdriver.PhantomJS()
browser.implicitly_wait(3)
# open URL
browser.get(URL)
# enter
browser.sync_send_keys((By.ID, "USRID1"), USRID1)
browser.sync_send_keys((By.ID, "USRID2"), USRID2)
# Password
browser.sync_send_keys((By.ID, "PASSWORD"), PASSWORD)
# Click login
browser.find_element_by_name("bLogon.y").click();
# 期限切れなら次へをクリック
try:
es = browser.find_elements_by_name("imgNext.y")
except NoSuchElementException:
print("no entry")
else:
es[0].click()
# ログイン後画面
# 明細照会をクリック
browser.find_element_by_css_selector(".detailsBtn > a").click()
# csv形式でダウンロード
resp = browser.download(browser.find_element_by_id("DownloadCSV")
.get_attribute("href"))
# 先頭行を抜いて csv.reader に渡す
rows = csv.reader(resp.decode("shift_jis").split("\r\n")[1:])
for row in rows:
if len(row) != 5:
continue
print(row)
browser.quit()
# coding: utf-8
import requests
from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
class Browser(object):
def __init__(self, webdriver):
self.driver = webdriver
# webdriver のメソッドはそのまま透過
def __getattr__(self, name):
if hasattr(self.driver, name):
return getattr(self.driver, name)
raise AttributeError
def download(self, url):
ua = {'User-agent': self.execute_script("return navigator.userAgent")}
#print(ua)
session = requests.Session()
cookies = self.get_cookies()
for cookie in cookies:
session.cookies.set(cookie['name'], cookie['value'])
#print(cookie['name'], cookie['value'])
#print(url)
response = session.get(url, headers = ua)
#print(response.status_code)
#print(response.content)
#print(response.headers)
return response.content
def sync_send_keys(self, locator, key):
# wait for element
WebDriverWait(self, 120).until(
EC.element_to_be_clickable(locator)
)
# send keys
self.find_element(locator[0], locator[1]).send_keys(key)
# wait for update
WebDriverWait(self, 30).until(
EC.text_to_be_present_in_element_value(locator, key)
)