間が空いてしまいましたが、三井住友銀行の取引履歴を取得できるようになりました。
最初は真面目に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) )