さて、前回Amazonの2要素認証(OTP)をパスする方法を紹介しました。
今回はメインの領収書を取得して指定したフォルダに保存する方法の紹介です。これで自分の2020年のAmazon領収書集めも完了しました。
実際のコード
まずは何より、実際のコードを貼っていきます。前回の2FAをパスするためだけのコードから領収書保存のページング対応のために、変更している部分もありますので、ご注意ください。
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support import expected_conditions
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.support.expected_conditions import visibility_of
from pathlib import Path
import bs4,requests,time,os,sys,random,re,csv,json
url = "https://www.amazon.co.jp/ap/signin?_encoding=UTF8&openid.assoc_handle=jpflex" \
"&openid.claimed_id=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select" \
"&openid.identity=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select" \
"&openid.mode=checkid_setup&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0" \
"&openid.ns.pape=http%3A%2F%2Fspecs.openid.net%2Fextensions%2Fpape%2F1.0" \
"&openid.pape.max_auth_age=0&openid.return_to=https%3A%2F%2Fwww.amazon.co.jp%2Fgp%2Fyourstore%2Fhome%3Fie%3DUTF8%26action" \
"%3Dsign-out%26path%3D%252Fgp%252Fyourstore%252Fhome%26ref_%3Dnav_AccountFlyout_signout%26signIn%3D1%26useRedirectOnSuccess%3D1"
e_mail = "emailアドレス"
password = "パスワード"
downloadPath = "DLファイルの絶対パス"
options = webdriver.ChromeOptions()
settings = {"recentDestinations": [{"id": "Save as PDF",
"origin": "local",
"account": ""}],
"selectedDestinationId": "Save as PDF",
"version": 2}
prefs = {'printing.print_preview_sticky_settings.appState': json.dumps(settings),'savefile.default_directory':downloadPath}
options.add_experimental_option('prefs', prefs)
options.add_argument('--kiosk-printing')
wd = webdriver.Chrome("chrome_driverのパス", options=options)
wd.get(url)
time.sleep(1)
"""
メールアドレスの入力+送信
"""
email_box = wd.find_element_by_xpath('//*[@id="ap_email"]')
email_box.send_keys(e_mail)
emai_box_submit = wd.find_element_by_xpath('//*[@id="continue"]')
emai_box_submit.click()
time.sleep(1)
"""
passwordの入力
"""
password_box = wd.find_element_by_xpath('//*[@id="ap_password"]')
password_box.send_keys(password)
password_box_submit = wd.find_element_by_xpath('//*[@id="signInSubmit"]')
password_box_submit.click()
time.sleep(3)
"""
2FAコードの取得+入力
oathtoolを利用
"""
import subprocess, re
twoFA = ['oathtool', '--totp', '--base32', 'アカウント追加キー']
print(subprocess.check_output(twoFA))
LoginPass_array = re.findall(r'\d+', subprocess.check_output(twoFA).decode('utf-8'))
LoginPass = LoginPass_array[0]
"""
認証アプリ画面への移動
"""
"""
wd.find_element_by_xpath('//*[@id="auth-select-device-form"]/div[1]/fieldset/div[3]/label/input').click()
wd.find_element_by_xpath('//*[@id="auth-send-code"]').click()
time.sleep(1)
"""
"""
OTP入力画面
"""
otp_box = wd.find_element_by_xpath('//*[@id="auth-mfa-otpcode"]')
otp_box.send_keys(LoginPass)
otp_box_submit = wd.find_element_by_xpath('//*[@id="auth-signin-button"]')
otp_box_submit.click()
time.sleep(1)
"""
アカウント&リストへ遷移
"""
account_list_top = wd.find_element_by_xpath('//*[@id="nav-link-accountList"]/span[1]')
account_list_top.click()
account_list_page =wd.find_element_by_xpath('//*[@id="a-page"]/div[3]/div/div[2]/div[1]/a/div/div/div/div[2]/h2')
account_list_page.click()
"""
wd.find_element_by_id('a-autoid-1"').click()
wd.find_element_by_xpath('orderFilter_3').click()
"""
"""
2020年の選択
"""
select_year_tab = wd.find_element_by_xpath('//*[@id="a-autoid-8-announce"]')
select_year_tab.click()
select_2020_tab = wd.find_element_by_xpath('//*[@id="orderFilter_3"]')
select_2020_tab.click()
time.sleep(3)
while True:
main_brows = wd.current_window_handle
reciept_links = wd.find_elements_by_link_text('領収書等')
for reciept_link in reciept_links:
reciept_link.click()
time.sleep(3)
reciept_purcahseresult_link = wd.find_element_by_link_text('領収書/購入明細書')
before_click_handles = wd.window_handles
"""新しいタブでPDFを開く"""
actions = ActionChains(wd)
actions.key_down(Keys.COMMAND)
actions.click(reciept_purcahseresult_link)
actions.perform()
WebDriverWait(wd, 5).until(lambda a: len(wd.window_handles) > len(before_click_handles))
after_click_handles = wd.window_handles
handle_new = list(set(after_click_handles) - set(before_click_handles))
"""タブ移動"""
wd.switch_to.window(handle_new[0])
"""
pdf保存
"""
wd.execute_script('window.print();')
wd.close()
wd.switch_to.window(main_brows)
try:
wd.find_element_by_class_name('a-last').find_element_by_tag_name('a')
wd.find_element_by_class_name('a-last').click()
wd.switch_to.window(wd.window_handles[-1])
except:
break
wd.quit()
非常に長くなってますね、まぁ致し方ないですが。コードが長くてコードの解説は次回以降に回したいと思います汗
実行結果
実行すると以下のような感じで、指定のフォルダに2020年(暦年)分の領収書が一式保存されます。55件くらいあったのですが、selenium使って一気に保存できると本当に手間が省けます。
ぽちぽち一個一個やっていくことを考えたらゾッとしますが、これがコードのいいところですよね。

注意点
以下何点かコードをカスタマイズされる方向けに注意点を紹介していきます。
ヘッドレスだと保存がうまくいかない可能性
seleniumのヘッドレスを利用されるケースも多いかと思いますが、今回のコードではヘッドレスは利用していません。
それは、ヘッドレスの場合、今回利用したkioskオプション(–kiosk-printing)との併用ができず(kioskプリントはブラウザの印刷画面を利用してPDF化させる方法のため)、PDF保存するという本来の目的を達成できないためです。
対象コードは以下の部分になります。
options.add_argument('--kiosk-printing')
認証アプリ画面への遷移画面の経由の発生・不発生
認証アプリ画面への遷移が発生するケースとしないケースが存在します。というか、何回か試しに動かすと認証アプリ選択の画面が発生せず、そのままOTP入力に遷移するようです。
そのため、上記のコードでは、認証アプリ選択の画面に関するコードをコメントアウトしています。ただ、多分初回動かすときは下記の部分のコメントアウトを外して動作させる必要があると思われます。
"""
認証アプリ画面への移動
"""
"""
wd.find_element_by_xpath('//*[@id="auth-select-device-form"]/div[1]/fieldset/div[3]/label/input').click()
wd.find_element_by_xpath('//*[@id="auth-send-code"]').click()
time.sleep(1)
"""
まとめ
さて、今回は【selenium・pythonを使ってAmazonの領収書を自動取得する方法〜シリーズ2:2020年を選択して領収書PDFを保存〜】を紹介しました。
今回は実際のコードと注意点の説明だけになっています。次回以降でコードで何を実施しているかの解説をつけていきたいと思います。
自分の場合は2020年は55件だけでしたが、これだけでもコード書くメリットが非常に感じられました。100件を超えて購入している方などは、ぜひ実装してみると手間が省けていいです。
自動化は自分の身を助けるは本当ですw
関連記事: seleniumでAmazon領収書をPDF保存する方法関連記事
確定申告の時期にいつも必要になる領収書。そしてよく使うAmazon。そんなAmazonの領収書を一つ一つクリックして保存するなんて、時間的にも精神的にも辛い。というわけで、Amazonの領収書をseleniumを使って自動で指定フォルダにPDF保存する方法の紹介をするシリーズです。