こんにちは。ツバサです。出費の管理をするために、Amazonの購入履歴をスクレイピングしてみようと思います。
「クレカの明細見れば分かるやん?」と思いますが、商品名に「Amazon」と表示されるため何を買ったか分からないんです。
と、いうわけで今回は第1回です。購入履歴画面を開くところまで実装します。
開発環境はMacbookAir M1でPython 3.8.13です。
購入履歴を開くまでのフロー
購入履歴までのフローは・・・
- Chromeを起動する
- Amazonにログインする
- 購入履歴を開く
実際のところ、chrome起動後に開くページのURLを購入履歴のものにしておけば、ログイン完了後購入歴画面へ自動で遷移します。つまり2と3は一度に実行できます。
注意事項
seleniumを扱ったことがある人は分かると思いますが、ブラウザとwebドライバーのバージョンが違うと動きません。
ただブラウザは頻繁にアップデートされるため、その度にwebドライバーを手動更新するのは超めんどくさいです。
なのでプログラムを実行するたびにwebドライバーを更新してから、webドライバーを起動するようにします。(「web driver 自動更新」などで検索すれば出てきます。)
ソースコード
実際に書いたソースコードです。コメントにフローの番号も書きました。39行目と45行目です。
# coding:utf-8
import time
from selenium import webdriver
from selenium.webdriver.common.keys import Keys #キー入力
from webdriver_manager.chrome import ChromeDriverManager #webdriver自動更新用
from getpass import getpass
def main():
user = "****@gmail.com" # ユーザID
print('user name is ' + user)
pw = getpass('input password:') # パスワード
# ログインページのURLとXpath
loginPage = {
'url':'https://www.amazon.co.jp/ap/signin?以下略',
'userForm':'/html/body/div[1]/div[1]/div[2]/div/div[2]/div/div[1]/form/div/div/div/div[1]/input[1]',
'pwForm':'/html/body/div[1]/div[1]/div[2]/div/div[2]/div/div/div/form/div/div[1]/input',
'nextButton':'/html/body/div[1]/div[1]/div[2]/div/div[2]/div/div[1]/form/div/div/div/div[2]/span/span/input',
'loginButton':'/html/body/div[1]/div[1]/div[2]/div/div[2]/div/div/div/form/div/div[2]/span/span/input'
}
controller = WebController(user,pw,loginPage)
controller.login()
#待機(確認用)
time.sleep(5)
class WebController:
# 初期設定
def __init__(self,user,pw,loginPage):
self.userID = user
self.pw = pw
self.loginPage = {
'url':loginPage['url'],
'userForm':loginPage['userForm'],
'pwForm':loginPage['pwForm'],
'nextButton':loginPage['nextButton'],
'loginButton':loginPage['loginButton']
}
self.driver = webdriver.Chrome(ChromeDriverManager().install()) # 1.webdriverを更新してChromeを起動
self.driver.implicitly_wait(10) # 要素が見つかるまで10秒待機
# ログイン部分
def login(self):
#2~3.Amazonのログインページを開く
self.driver.get(self.loginPage['url'])
# ユーザID入力フォームを取得
userSelector = self.driver.find_element_by_xpath(self.loginPage['userForm'])
# ユーザID入力
print('Input user name.')
userSelector.send_keys(self.userID)
# 次へボタンを取得(ID入力後、PW入力フォームへ進むためのボタン)
# ボタンがないサイトもあると思うのでない場合はスキップする
nextButtonSelector = self.driver.find_element_by_xpath(self.loginPage['nextButton'])
#次へボタン
if(len(self.loginPage['nextButton']) > 0):
print('Push next button.')
nextButtonSelector.click()
#pw入力フォームを取得
pwSelector = self.driver.find_element_by_xpath(self.loginPage['pwForm'])
#pw入力
print('Input password.')
pwSelector.send_keys(self.pw)
#ログインボタンを取得
loginButtonSelector = self.driver.find_element_by_xpath(self.loginPage['loginButton'])
#ログインボタン押下
print('Push login button.')
loginButtonSelector.click()
# クラス外で動かしたい時用(あれば)
def getDriver(self):
return self.driver
main()
※ログインページのURLは長すぎてここでは見にくくなったので省略しました。
URLの取得元は下記の通りです。
Amazonにログインしていない状態でメニューの「購入履歴」をクリックします。
するとログイン画面が出てくるので、そこに表示されているURLをコピーして15行目に入れてください。
ソースコード補足
上記ソースコードで工夫したを挙げると・・・(工夫と言って良いのか?)
- パスワードはターミナルで手入力(getpass)
- selenium使用部分はクラス化
- webドライバーはプログラム実行時に自動アップデート
1. パスワードはターミナルで手入力
セキュリティ的なあれです。本来はユーザ名(メールアドレス)も入力すべきですね。デバッグが面倒なのでパスワードだけにしました。
from getpass import getpass
pw = getpass('input password:') # パスワード
2. selenium使用部分はクラス化
Amazon以外でも使う場面があると思うので、一応クラス化しておいて都度機能追加できるようにしておきます。
コンストラクタでドライバーを起動し、インスタンス変数として保持してみました。
クラス外でも使えるようにドライバーを返すメソッドも作っておきました。(使う場面があるのかは不明)
また、loginPageというディクショナリ変数を用意し、そこに購入履歴画面のURLとログインフォームのXPathを持たせておきます。
class WebController:
# 初期設定
def __init__(self,user,pw,loginPage):
self.userID = user
self.pw = pw
self.loginPage = {
'url':loginPage['url'],
'userForm':loginPage['userForm'],
'pwForm':loginPage['pwForm'],
'nextButton':loginPage['nextButton'],
'loginButton':loginPage['loginButton']
}
self.driver = webdriver.Chrome(ChromeDriverManager().install()) # 1.webdriverを更新してChromeを起動
self.driver.implicitly_wait(10) # 要素が見つかるまで10秒待機
# ログイン部分
def login(self):
#2~3.Amazonのログインページを開く
self.driver.get(self.loginPage['url'])
# ユーザID入力フォームを取得
userSelector = self.driver.find_element_by_xpath(self.loginPage['userForm'])
# ユーザID入力
print('Input user name.')
userSelector.send_keys(self.userID)
# 次へボタンを取得(ID入力後、PW入力フォームへ進むためのボタン)
# ボタンがないサイトもあると思うのでない場合はスキップする
nextButtonSelector = self.driver.find_element_by_xpath(self.loginPage['nextButton'])
#次へボタン
if(len(self.loginPage['nextButton']) > 0):
print('Push next button.')
nextButtonSelector.click()
#pw入力フォームを取得
pwSelector = self.driver.find_element_by_xpath(self.loginPage['pwForm'])
#pw入力
print('Input password.')
pwSelector.send_keys(self.pw)
#ログインボタンを取得
loginButtonSelector = self.driver.find_element_by_xpath(self.loginPage['loginButton'])
#ログインボタン押下
print('Push login button.')
loginButtonSelector.click()
# クラス外で動かしたい時用(あれば)
def getDriver(self):
return self.driver
正直なところ、クラス設計とか全然理解できていません。なので今回作ったWebControllerクラスは雰囲気です。ご了承ください。
3. webドライバーの自動アップデート部分
ここが今回のメインです。コンストラクタでアップデートしましたが、下記の1〜2行目までがあればOKです。
自動アップデートはChromeDriverManagerというライブラリを使用することで可能になります。
ちなみに、3行目のimplicitly_wait関数で要素(idやclassなど)が見つかるまでの間、引数に指定した時間待機してくれます。
from webdriver_manager.chrome import ChromeDriverManager #webdriver自動更新用
driver = webdriver.Chrome(ChromeDriverManager().install()) #webdriver自動更新して実行
driver.implicitly_wait(10) #要素が見つかるまで10秒待機
さいごに・・・
今回はAmazonにログインして購入履歴画面を表示するところまでを実装しました。
次回は購入履歴にある、日付、価格、商品名の取得をしていきます。
下記の赤枠部分です。
以上!最後までご覧いただき、ありがとうございました。
コメント