PythonのWebスクレイピングでAmazonの領収書を自動保存



PythonのWebスクレイピングでAmazonの領収書を自動保存

Amazonの領収書、みなさまはどのように管理されていますでしょうか?

私の場合は、確定申告時にいつもまとめて領収書を手作業で保存していました。

しかし、面倒くさいですし、時間がかかりますよね。この問題、 Pythonで解決できました。

今回ご紹介させて頂く Pythonプログラムは、 2018年版ですが、プログラムが読めると 2019年版、それから他のワンパターン作業も自動化できると思います。ご参考下さい。

【対象者】

  • Pythonに興味のある方
  • Pythonを学び始めた方
  • Webスクレイピングに興味のある方
  • データ分析に興味のある方
  • Web上の作業を自動化したいと考えている方
  • Amazonの集計・領収書管理にうんざりしている方

【できること】

  • Amazon.com の領収書を自動保存(HTMLファイル形式)
目次
  1. PythonのWebスクレイピングでAmazonの領収書を自動保存
  2. 今回Webスクレイピングで作成したAmazonの領収書自動保存の様子
  3. Amazonの領収書を自動保存する方法
  4. スクレイピング設計
  5. プログラミング(スクレイピングで領収書のURLを収集)
  6. プログラミング(スクレイピングで領収書の保存)
  7. 今回のPythonプログラムを実行する様子
  8. まとめ

PythonのWebスクレイピングでAmazonの領収書を自動保存

今回Webスクレイピングで作成したAmazonの領収書自動保存の様子

まずはじめに今回作成したボットの様子をご参考下さい。人間に代わってプログラムが自動で Amazonの領収書をパソコンに保存してくれています。

上記動画のPythonコード

Amazonの領収書を自動保存する方法

Amazonの領収書は、ノーマルアカウントの場合、一注文ずつ手作業で印刷もしくは保存する必要があります。しかし、現在のところ下記のようなサービスを利用するとその手間は省けるようです。

  • 有料の会計ソフト(年間 8,000〜36,000円)
  • Chromeの拡張機能(アマゾン注文履歴フィルタ
  • amazon businessへのアカウント・アップグレード

まずこの中で直ぐに試せるものとすれば、Chromeの拡張機能でしょう。実際に私も使ってみました。しかし、はじめて試した時はエラーで使用できず。その後、3月9日改めて使ってみるとエラーなく使えました。誰でも直ぐに使えてとっても便利です。

しかし、 Chromeの拡張機能というとログイン情報の流出やハッキング・リスクと安全性の懸念がありますね。もちろんコードを確認した上で大丈夫!と判断できればいいのでしょうが、今回試した「アマゾン注文履歴フィルタ」のメインプログラムは 3500行以上に(下図参照)。

image

「アマゾン注文履歴フィルタ」は、コードを GitHubでも公開され、開発経緯や開発者のお人柄的にも大丈夫なプログラムと思います。あくまで「Chromeの拡張機能」には、一様にリスクが存在する、ということを伝えたいだけです。

Chromeの拡張機能(プラグイン)は、HTML、CSS、JavaSciptをベースにソフト開発されます。

JavaScriptに精通していないとコードを読んでも、ナニをしているのか分かりませんし、また拡張機能エラー発生時も開発側の対応を待つしかない、という状況に。

特に今回の「領収書」、カード支払いしている方は、領収書下部にカード番号の末尾が記載されています。また個人の方は住所等の個人情報も。なるべく外部の方に知られたくない、という方もいらっしゃるのでは。そういった場合は、自分で領収書を保存すればいいのですが、面倒くさい。それを自作の Pythonプログラムで解決しよう!というわけですね。

拡張機能と自作プログラムの違いをまとめると以下のようになるでしょう。

自作 拡張機能
安全性 高い たぶん大丈夫
機密性 高い たぶん大丈夫
エラー 腕次第 時々
利便性 腕次第 高い
時間 腕次第 すぐ使える

それでは Pythonの Webスクレイピングを使って Amazonの領収書を自動保存するプログラムを作っていきましょう。最初は大変かもしれませんが、一度要領が別れば来年や再来年、それから他の自動化処理したい事柄にも応用が聞くと思いますよ。

スクレイピング設計

画像クリックで拡大

今回は、2018年注文分の領収書全てを自動でパソコンに保存していきたいと思います。

まず自動化させる作業工程を確認しておきましょう。上図に示すように

  • 表示期間を2018年にセット
    上から順番に領収書ボタンをクリック
  • 領収書を保存
    注文履歴の一覧ページに戻る
  • 次の商品の領収書ボタンをクリック、領収書の保存を繰り返し
  • ページ内の領収書を保存できたら、「次のページヘ」をクリック
  • 上から順番に領収書保存を繰り返す

この流れをプログラムできればOKですね。

プログラミング(スクレイピングで領収書のURLを収集)

スクレイピングでログイン

image

まず ① の2018年注文履歴ページを表示するには、 Amazon.co.jp にログインする必要があります。ログイン作業を自動で処理する場合、 Selenium という Pythonライブラリが便利ですよね。

【復習】Pythonのスクレイピングを手伝ってくれるライブラリ群

- Beautiful Soup / 処理が早い、スクレイピングの定番ツール
- Selenium / 文字の入力やクリックも自動でできる
- Pandas / 表データのスクレイピングならお手のもの
- Scrapy / ページ送りもお手のもの

今回の Amazon.co.jp ページに自動でログインしようと思うと以下のような Pythonコードになるでしょう。

from selenium import webdriver
import time

browser = webdriver.Firefox()
browser.implicitly_wait(10)

browser.get("https://www.amazon.co.jp/ap/signin?_encoding=UTF8&accountStatusPolicy=P1&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%2Fyour-account%2Forder-history%3Fie%3DUTF8%26digitalOrders%3D1%26opt%3Dab%26orderFilter%3Dyear-2018%26returnTo%3D%26unifiedOrders%3D1&pageId=webcs-yourorder&showRmrMe=1")
email_elem = browser.find_element_by_id("ap_email")
email_elem.send_keys("★入力★ユーザー名")
password_elem = browser.find_element_by_id("ap_password")
password_elem.send_keys("★入力★パスワード")
password_elem.submit()

今回 スクレイピングで使用するブラウザは、 Firefoxとし、ブラウザの反応があるまでの待機時間は 10秒にセット( browser.implicitly_wait(10) )。

browser.get() で指定URLの Webページが開くわけですが、今回は Amazon.co.jp のトップページではなく、注文履歴ページが開く URL をセット。これでログインすると直ぐに注文履歴を確認できます。

文字の自動入力は、 Seleniumの send_keys()関数で処理できますね。入力先の指定は、ユーザー名の入力欄の上で右クリックし、 HTMLを確認。

image

すると id = "ap_email" とありますね。この id を使って文字の入力先を指定すると

ログインの入力先 = browser.find_element_by_id("ap_email")

パスワードの入力も同じ要領で設定すると

パスワードの入力先 = browser.find_element_by_id("ap_password")

後は「ログイン」ボタンのクリックですが、こちらは パスワードの入力先を submit()すれば OKです。

password_elem.submit()

スクレイピング・プログラムの実行

【自動ログイン・プログラム実行の様子】

Pythonのプログラムを実行する際は、仮想環境を構築して環境を整える方法が一般的ですよね。今回も同じように Virtualenv で仮想環境を構築しておきましょう。

【仮想環境の構築コマンド】

【Mac, Ubuntu】
virtualenv env
source env/bin/activate

【Windows】
python -m virutalenv env
env\Scritps\activate

仮想環境が作成できたら Selenium をインストールしましょう。

pip install selenium

そして先ほど作成した Pythonを実行ですね。

python sampleCode.py

すると Firefoxが自動で起動し、ログイン情報が自動入力されている様子を確認できると思います。

次は領収書ページを自動で開いて、データ保存する作業をプログラムしていきましょう。

スクレイピング・メソッドの選択

image

人間の手作業であればスクレイピング設計でもご紹介したように、「領収書をクリック → 保存/印刷 → ページ戻る → 次の注文の領収書をクリック ・・・・」 となりますが、スクレイピング・プログラムを使った場合、もう少しスマートな手順で領収書を連続表示することが可能です。

それはページ内の領収書リンク 10件分をまとめて取得し、そのリンクへ順次アクセス、そして順次領収書を保存していくというやり方。この方法であれば、ページの移動数が減り、処理時間の短縮になります。

ページ内の領収書URL取得は、いくつか方法があるかもしれませんが、 find_elements_by_xpath() 関数を使って領収書URLリストの取得に挑戦しました。理由は、 find_elements_by_xpath() で取得したデータはリスト型で扱いやすそうだったからです。

リンク対象の「領収書/購入明細書」の HTMLを確認すると 

image

<a class="a-link-normal" href="/gp/css/summary/print.html/ref=ppx_yo_dt_b_invoice_o00?ie=UTF8&amp;orderID=249-7933883-1043038">
領収書/購入明細書</a>

Seleniumの find_element_by_xpath()関数、 find_element_by_link_text()関数、それから find_element_by_class_name() や find_element_by_css_selector() も使えそうです。

実際にそれぞれの関数で領収書リンクを取得したデータとデータ型は下記の通り。

【find_element_by_xpath()】 image

【find_element_by_link_text()】 image

【find_element_by_css_selector()】 image

find_element_by_class_name()は、スクレイピング失敗でした。この中で取得データをリストで返しているのは find_element_by_xpath() だけ。よって find_element_by_xpath() を使うことに決めました。

スクレイピング取得データのURLのみを抽出

image

さて先ほど選択した Seleniumのメソッドですが、このデータリスト型の中にどんなデータが入っているのでしょうか。確認してみましょう。Seleniumで取得したデータは、 text変換すれば確認できましたよね。追記コードは以下のように。

receipt_link_element2 = [x.text for x in receipt_link_element]
【コード全体】

  from selenium import webdriver
  import time
  #
  browser = webdriver.Firefox()
  browser.implicitly_wait(10)
  #
  browser.get("https://www.amazon.co.jp/ap/signin?_encoding=UTF8&accountStatusPolicy=P1&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%2Fyour-account%2Forder-history%3Fie%3DUTF8%26digitalOrders%3D1%26opt%3Dab%26orderFilter%3Dyear-2018%26returnTo%3D%26unifiedOrders%3D1&pageId=webcs-yourorder&showRmrMe=1")
  email_elem = browser.find_element_by_id("ap_email")
  email_elem.send_keys("★ユーザー名★")
  password_elem = browser.find_element_by_id("ap_password")
  password_elem.send_keys("★パスワード★")
  password_elem.submit()
  time.sleep(1)
  #
  pages_remaining = True
  #
  while pages_remaining:
      try:
          time.sleep(2)
          receipt_link_element = browser.find_elements_by_xpath("//a[@class='a-link-normal']")
          #receipt_link_element = browser.find_element_by_link_text("領収書/購入明細書")
          #receipt_link_element = browser.find_element_by_css_selector("a.a-link-normal")
          #
          receipt_link_element2 = [x.text for x in receipt_link_element]
          print(receipt_link_element2)
          print(type(receipt_link_element2))
          #
      except:
          browser.close()
  

【実行結果】 image

領収書のリンク要素以外にもたくさんデータが含まれていることが確認できますが、領収書のみの要素を抽出するように配列構造を制御すれば良さそうですね。尚、実際にプログラムを動かしてみると、 スクレイピングする前に time.sleep() を入れておかないとログインページの様子を取得してしまいます。ブラウザにページを読み込む時間的猶予を与えてあげる必要がありますね。

次はこのリスト内の各要素の URL を取得。そしてそれから「領収書/購入明細書」のURLのみをピックアップするように試してみましょう。要素内の URL 取得は、 get_attribute()関数を使えばよさそうですね。今回はスクレイピングで取得した配列データ全てに get_attribute() を行いたいので以下のようなコードになりました。

receipt_link_url = [x.get_attribute('href') for x in receipt_link_element]
【コード全体】

  from selenium import webdriver
  import time
  #
  browser = webdriver.Firefox()
  browser.implicitly_wait(10)
  #
  browser.get("https://www.amazon.co.jp/ap/signin?_encoding=UTF8&accountStatusPolicy=P1&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%2Fyour-account%2Forder-history%3Fie%3DUTF8%26digitalOrders%3D1%26opt%3Dab%26orderFilter%3Dyear-2018%26returnTo%3D%26unifiedOrders%3D1&pageId=webcs-yourorder&showRmrMe=1")
  email_elem = browser.find_element_by_id("ap_email")
  email_elem.send_keys("★ユーザー名★")
  password_elem = browser.find_element_by_id("ap_password")
  password_elem.send_keys("★パスワード★")
  password_elem.submit()
  time.sleep(1)
  #
  pages_remaining = True
  #
  while pages_remaining:
      try:
          time.sleep(3)
          receipt_link_element = browser.find_elements_by_xpath("//a[@class='a-link-normal']")
          #receipt_link_element = browser.find_element_by_link_text("領収書/購入明細書")
          #receipt_link_element = browser.find_element_by_css_selector("a.a-link-normal")
          #
          #receipt_link_element2 = [x.text for x in receipt_link_element]
          #
          receipt_link_url = [x.get_attribute('href') for x in receipt_link_element]
          print(receipt_link_url)
          print(type(receipt_link_url))
          #
      except:
          browser.close()
  

【実行結果】

image

先ほどのスクレイピング取得データのリスト内を確認した時、領収書の項目は前から 4番目にありましたよね。その URL を確認してみると

https://www.amazon.co.jp/gp/css/summary/print.html/ref=ppx_yo_dt_b_invoice_o00?ie=UTF8&orderID=249-7933883-1043038

URLの中に "invoice" という他にはない特有のキーワードがありますね。この "invoice" を含む要素のみを抽出すれば領収書のURLをピックアップできそうですが、なぜか "invoice" の要素が 20こあります。 1ページに表示されている "領収書" は 10こなのに "invoice" は 20こ。この現象は、HTMLを確認してみると納得できました。

image

同じ注文の領収書のリンクが 2つ存在するんですね。そのため画面上は "領収書" が10しか表示されていないのに、スクレイピングした要素は 20となるんですね。

スクレピング取得データをスライス(飛び飛び)

先ほど取得した URL、データを確認すると

['最初の領収書URL','最初の領収書URL','2番目の領収書URL','2番目の領収書URL',・・・・]

となっています。一つずつデータを削除、もしくは飛び飛びでデータを取得、整形できれば 10この領収書 URLをゲットできそう。 1こ飛ばしのスライスのコードは

スライス対象のデータ[::2]

ですね。

【コード全体】

  from selenium import webdriver
  import time
  #
  browser = webdriver.Firefox()
  browser.implicitly_wait(10)
  #
  browser.get("https://www.amazon.co.jp/ap/signin?_encoding=UTF8&accountStatusPolicy=P1&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%2Fyour-account%2Forder-history%3Fie%3DUTF8%26digitalOrders%3D1%26opt%3Dab%26orderFilter%3Dyear-2018%26returnTo%3D%26unifiedOrders%3D1&pageId=webcs-yourorder&showRmrMe=1")
  email_elem = browser.find_element_by_id("ap_email")
  email_elem.send_keys("★ユーザー名★")
  password_elem = browser.find_element_by_id("ap_password")
  password_elem.send_keys("★パスワード★")
  password_elem.submit()
  time.sleep(1)
  #
  pages_remaining = True
  #
  while pages_remaining:
      try:
          time.sleep(3)
          receipt_link_element = browser.find_elements_by_xpath("//a[@class='a-link-normal']")
          #receipt_link_element = browser.find_element_by_link_text("領収書/購入明細書")
          #receipt_link_element = browser.find_element_by_css_selector("a.a-link-normal")
          #
          #receipt_link_element2 = [x.text for x in receipt_link_element]
          #
          receipt_link_url = [x.get_attribute('href') for x in receipt_link_element]
          link_format = receipt_link_url[::2]
          print(link_format)
          print(type(link_format))
          #
      except:
          browser.close()
  

【実行結果】 image

あとは "invoice" を含む要素のみピックアップすれば 1ページ内の領収書URLをゲットできますね。

スクレイピング取得データから必要なものだけを抽出

配列内の必要な要素のみを抽出する方法としては、下記コードが使えますね。

link_data = [s for s in link_format if "この文字を含むもの" in s]

【今回の場合】
link_data = [s for s in link_format if "invoice" in s]
【コード全体】

  from selenium import webdriver
  import time
  #
  browser = webdriver.Firefox()
  browser.implicitly_wait(10)
  #
  browser.get("https://www.amazon.co.jp/ap/signin?_encoding=UTF8&accountStatusPolicy=P1&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%2Fyour-account%2Forder-history%3Fie%3DUTF8%26digitalOrders%3D1%26opt%3Dab%26orderFilter%3Dyear-2018%26returnTo%3D%26unifiedOrders%3D1&pageId=webcs-yourorder&showRmrMe=1")
  email_elem = browser.find_element_by_id("ap_email")
  email_elem.send_keys("★ユーザー名★")
  password_elem = browser.find_element_by_id("ap_password")
  password_elem.send_keys("★パスワード★")
  password_elem.submit()
  time.sleep(1)
  #
  pages_remaining = True
  #
  while pages_remaining:
      try:
          time.sleep(3)
          receipt_link_element = browser.find_elements_by_xpath("//a[@class='a-link-normal']")
          #receipt_link_element = browser.find_element_by_link_text("領収書/購入明細書")
          #receipt_link_element = browser.find_element_by_css_selector("a.a-link-normal")
          #
          #receipt_link_element2 = [x.text for x in receipt_link_element]
          #
          receipt_link_url = [x.get_attribute('href') for x in receipt_link_element]
          link_format = receipt_link_url[::2]
          link_data = [s for s in link_format if "invoice" in s]
          print(link_data)
          print(type(link_data))
          #
      except:
          browser.close()
  

【実行結果】

image

たくさんあった URL も、領収書の URLのみになりましたね。次は、この領収書URLに順次アクセスするプログラムを作りましょう。

プログラミング(スクレイピングで領収書の保存)

image

スクレイピングで複数のURLに自動アクセス

まず 1ページ内にある 10の領収書ページにアクセスする方法を考えると、 for文で繰り返し処理するとよさそうです。そして 1ページ内の 10の領収書ページにアクセスしたら、もとの「注文履歴」のページに戻り、「次のページ」をクリック、それを繰り返し処理すれば 2018年の領収書ページ全てにアクセスできそう。

まずは for文を作成してみましょう。

for receipt_page in link_data:
    browser.get(receipt_page)
    time.sleep(1)
else:
    browser.get(current_URL_address)
【コード全体】

  from selenium import webdriver
  import time
  #
  browser = webdriver.Firefox()
  browser.implicitly_wait(10)
  #
  browser.get("https://www.amazon.co.jp/ap/signin?_encoding=UTF8&accountStatusPolicy=P1&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%2Fyour-account%2Forder-history%3Fie%3DUTF8%26digitalOrders%3D1%26opt%3Dab%26orderFilter%3Dyear-2018%26returnTo%3D%26unifiedOrders%3D1&pageId=webcs-yourorder&showRmrMe=1")
  email_elem = browser.find_element_by_id("ap_email")
  email_elem.send_keys("★ユーザー名★")
  password_elem = browser.find_element_by_id("ap_password")
  password_elem.send_keys("★パスワード★")
  password_elem.submit()
  time.sleep(1)
  #
  pages_remaining = True
  #
  while pages_remaining:
      try:
          time.sleep(3)
          current_URL_address = browser.current_url

          receipt_link_element = browser.find_elements_by_xpath("//a[@class='a-link-normal']")
          #receipt_link_element = browser.find_element_by_link_text("領収書/購入明細書")
          #receipt_link_element = browser.find_element_by_css_selector("a.a-link-normal")
          #receipt_link_element2 = [x.text for x in receipt_link_element]
          receipt_link_url = [x.get_attribute('href') for x in receipt_link_element]
          link_format = receipt_link_url[::2]
          link_data = [s for s in link_format if "invoice" in s]
          #print(link_data)
          #print(type(link_data))
          #
          for receipt_page in link_data:
              browser.get(receipt_page)
              print(receipt_page)
              time.sleep(1)
          else:
              browser.get(current_URL_address)
              #
      except:
          browser.close()
  

【実行結果】 image

実際に動かしてみると、自動的に 10の領収書ページにアクセスできていることが確認できます。 10の領収書ページにアクセスした後は注文履歴のページに戻らないといけないのですが、これは 注文履歴ページの URL を変数管理すると扱いやすいです。現在いる Webページの URL取得は

URL = browser.current_url

でいけますね。今回の場合は、 for文の前に

current_URL_address = browser.current_url

をセットしています。

自動アクセスしたページのHTMLコードを確認

次は領収書ページにアクセスした時、そのページを保存する処理を加えてみましょう。今回はデータ保存を目的にしていますので、 Webページの書式である HTMLファイルのまま保存。Webページの HTMLコードを抽出する方法としては、 Seleniumの page_sourceが使えますね。

【追加コード】
receipt_page_html = browser.page_source
【コード全体】

  from selenium import webdriver
  import time
  #
  browser = webdriver.Firefox()
  browser.implicitly_wait(10)
  #
  browser.get("https://www.amazon.co.jp/ap/signin?_encoding=UTF8&accountStatusPolicy=P1&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%2Fyour-account%2Forder-history%3Fie%3DUTF8%26digitalOrders%3D1%26opt%3Dab%26orderFilter%3Dyear-2018%26returnTo%3D%26unifiedOrders%3D1&pageId=webcs-yourorder&showRmrMe=1")
  email_elem = browser.find_element_by_id("ap_email")
  email_elem.send_keys("★ユーザー名★")
  password_elem = browser.find_element_by_id("ap_password")
  password_elem.send_keys("★パスワード★")
  password_elem.submit()
  time.sleep(1)
  #
  pages_remaining = True
  #
  while pages_remaining:
      try:
          time.sleep(3)
          current_URL_address = browser.current_url
          receipt_link_element = browser.find_elements_by_xpath("//a[@class='a-link-normal']")
          #receipt_link_element = browser.find_element_by_link_text("領収書/購入明細書")
          #receipt_link_element = browser.find_element_by_css_selector("a.a-link-normal")
          #receipt_link_element2 = [x.text for x in receipt_link_element]
          receipt_link_url = [x.get_attribute('href') for x in receipt_link_element]
          link_format = receipt_link_url[::2]
          link_data = [s for s in link_format if "invoice" in s]
          #print(link_data)
          #print(type(link_data))
          #
          for receipt_page in link_data:
              browser.get(receipt_page)
              print(receipt_page)
              time.sleep(1)
              #
              receipt_page_html = browser.page_source
              print(receipt_page_html)
          else:
              browser.get(current_URL_address)
              #
      except:
          browser.close()
  

【実行結果】

image

領収書のHTMLコードをスクレイピングできていることが確認できますね。このコードを保存するには write()関数を使えば OK ですが、その前にパソコンに自動保存するファイル名の設定を行っておきましょう。

今回ファイル名は 001.html、 002.html など連番で自動保存していきたいと思います。

自動保存するファイル名の設定

ファイル名を連番の 001.html、 002.html と保存していきたい時は、ファイル名の設定をフォーマット形式でセットすれば OKですね。

ファイル名 = "{0:03d}".format(1)

{0:03d} は、 3桁の数字で空き番号のところを 0で埋めてくれ、表示される番号は format(1) の 1 になりますね。この format(1) が一つずつ増えていけばいいので、 1 を変数で管理します。今回は format(html_file_number) として、 1領収書毎に html_file_number を 1ずつ増やしていくようにプログラム。コードにするとこんな感じでしょう。

ファイル名 = "{0:03d}".format(html_file_number)

領収書の保存コード

html_file_number += 1

新しい領収書ページへ移動、ページのHTML要素を抽出、ファイルに保存の繰り返し
【コード全体】

  from selenium import webdriver
  import time
  #
  html_file_number = 1
  #
  browser = webdriver.Firefox()
  browser.implicitly_wait(10)
  #
  browser.get("https://www.amazon.co.jp/ap/signin?_encoding=UTF8&accountStatusPolicy=P1&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%2Fyour-account%2Forder-history%3Fie%3DUTF8%26digitalOrders%3D1%26opt%3Dab%26orderFilter%3Dyear-2018%26returnTo%3D%26unifiedOrders%3D1&pageId=webcs-yourorder&showRmrMe=1")
  email_elem = browser.find_element_by_id("ap_email")
  email_elem.send_keys("★ログイン名★")
  password_elem = browser.find_element_by_id("ap_password")
  password_elem.send_keys("★パスワード★")
  password_elem.submit()
  time.sleep(1)
  #
  pages_remaining = True
  #
  while pages_remaining:
      try:
          time.sleep(3)
          current_URL_address = browser.current_url
          receipt_link_element = browser.find_elements_by_xpath("//a[@class='a-link-normal']")
          #receipt_link_element = browser.find_element_by_link_text("領収書/購入明細書")
          #receipt_link_element = browser.find_element_by_css_selector("a.a-link-normal")
          #receipt_link_element2 = [x.text for x in receipt_link_element]
          receipt_link_url = [x.get_attribute('href') for x in receipt_link_element]
          link_format = receipt_link_url[::2]
          link_data = [s for s in link_format if "invoice" in s]
          #print(link_data)
          #print(type(link_data))
          #
          for receipt_page in link_data:
              browser.get(receipt_page)
              #print(receipt_page)
              time.sleep(1)
              receipt_page_html = browser.page_source
              #
              i_format = "{0:03d}".format(html_file_number)
              print(i_format)
               #領収書の保存コード
              html_file_number += 1
          else:
              browser.get(current_URL_address)
              #
      except:
          browser.close()
  

【実行結果】 image

ファイル名が自動で 001、 002、 003 と連番になっていることを確認できますね

スクレイピングで取得したデータをファイルに保存

ここまでの過程で、Amazonの領収書ページに自動アクセスし、そのファイルデータ(HTML)を取得し、保存するファイル名の自動設定までプログラムできました。後は、取得データをファイルに保存できれば一段落ですね。

Pythonを使ったデータの自動保存は、下記のよう処理フロー。

  • 新規ファイルの作成
  • データの書き込み、保存
  • ファイルを閉じる

新規ファイルの作成は open()、 データの書き込みは write() ですね。これらをまとめると以下のようなコードで領収書ページのHTMLデータをファイルに保存できます。

ファイル名 = "{0:03d}".format(html_file_number)

新規ファイル = open(ファイル名 + ".html", "w")
新規ファイル.write(HTMLコード)
新規ファイル.close()

html_file_number += 1
【コード全体】

  from selenium import webdriver
  import time
  #
  html_file_number = 1
  #
  browser = webdriver.Firefox()
  browser.implicitly_wait(10)
  #
  browser.get("https://www.amazon.co.jp/ap/signin?_encoding=UTF8&accountStatusPolicy=P1&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%2Fyour-account%2Forder-history%3Fie%3DUTF8%26digitalOrders%3D1%26opt%3Dab%26orderFilter%3Dyear-2018%26returnTo%3D%26unifiedOrders%3D1&pageId=webcs-yourorder&showRmrMe=1")
  email_elem = browser.find_element_by_id("ap_email")
  email_elem.send_keys("★ログイン名★")
  password_elem = browser.find_element_by_id("ap_password")
  password_elem.send_keys("★パスワード★")
  password_elem.submit()
  time.sleep(1)
  #
  pages_remaining = True
  #
  while pages_remaining:
      try:
          time.sleep(3)
          current_URL_address = browser.current_url
          receipt_link_element = browser.find_elements_by_xpath("//a[@class='a-link-normal']")
          #receipt_link_element = browser.find_element_by_link_text("領収書/購入明細書")
          #receipt_link_element = browser.find_element_by_css_selector("a.a-link-normal")
          #receipt_link_element2 = [x.text for x in receipt_link_element]
          receipt_link_url = [x.get_attribute('href') for x in receipt_link_element]
          link_format = receipt_link_url[::2]
          link_data = [s for s in link_format if "invoice" in s]
          #print(link_data)
          #print(type(link_data))
          #
          for receipt_page in link_data:
              browser.get(receipt_page)
              #print(receipt_page)
              time.sleep(1)
              receipt_page_html = browser.page_source
              #
              i_format = "{0:03d}".format(html_file_number)
              receipt_link_file = open(i_format + ".html", "w")
              receipt_link_file.write(receipt_page_html)
              receipt_link_file.close()
              print(receipt_link_file)
              #
              html_file_number += 1
          else:
              browser.get(current_URL_address)
              #
      except:
          browser.close()
  

【実行結果】 image

注文履歴のページ内の領収書が次々に HTMLファイルとしてパソコンに保存されていく様子を確認できます。あとはページ送りを自動化できればよさそうですね。

スクレイピングを使ってページ移動の自動化

image

スクレイピングツール Seleniumを使って次のページに移動したい場合、

リンク.click()

のコードを作成すれば OKですね。肝心のリンクになる HTML要素を確認すると、どうも Seleniumのリンクテキスト find_element_by_partial_link_text が使えそう。コードを実行してみました。

next_link = browser.find_element_by_partial_link_text("次へ")
next_link.click()
【コード全体】

  from selenium import webdriver
  import time
  #
  html_file_number = 1
  #
  browser = webdriver.Firefox()
  browser.implicitly_wait(10)
  #
  browser.get("https://www.amazon.co.jp/ap/signin?_encoding=UTF8&accountStatusPolicy=P1&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%2Fyour-account%2Forder-history%3Fie%3DUTF8%26digitalOrders%3D1%26opt%3Dab%26orderFilter%3Dyear-2018%26returnTo%3D%26unifiedOrders%3D1&pageId=webcs-yourorder&showRmrMe=1")
  email_elem = browser.find_element_by_id("ap_email")
  email_elem.send_keys("★ログイン名★")
  password_elem = browser.find_element_by_id("ap_password")
  password_elem.send_keys("★パスワード★")
  password_elem.submit()
  time.sleep(1)
  #
  pages_remaining = True
  #
  while pages_remaining:
      try:
          time.sleep(3)
          current_URL_address = browser.current_url
          receipt_link_element = browser.find_elements_by_xpath("//a[@class='a-link-normal']")
          #receipt_link_element = browser.find_element_by_link_text("領収書/購入明細書")
          #receipt_link_element = browser.find_element_by_css_selector("a.a-link-normal")
          #receipt_link_element2 = [x.text for x in receipt_link_element]
          receipt_link_url = [x.get_attribute('href') for x in receipt_link_element]
          link_format = receipt_link_url[::2]
          link_data = [s for s in link_format if "invoice" in s]
          #print(link_data)
          #print(type(link_data))
          #
          for receipt_page in link_data:
              browser.get(receipt_page)
              #print(receipt_page)
              time.sleep(1)
              receipt_page_html = browser.page_source
              #
              i_format = "{0:03d}".format(html_file_number)
              receipt_link_file = open(i_format + ".html", "w")
              receipt_link_file.write(receipt_page_html)
              receipt_link_file.close()
              print(receipt_link_file)
              #
              html_file_number += 1
          else:
              browser.get(current_URL_address)
          #
          next_link = browser.find_element_by_partial_link_text("次へ")
          next_link.click()
          time.sleep(1)
          #
      except:
          browser.close()
  

【実行結果】

image

いけましたね。これで 1注文ずつ領収書のページを開いて保存/印刷ボタンをクリックしなくても、プログラムを実行すれば後はコンピュータが自動で領収書ページをパソコンに保存してくれます。

今回のPythonプログラムを実行する様子

コード

まとめ

1年前確定申告をした時、36枚の Amazonの領収書を手作業で保存していました。しかし、今年はPythonのスクレイピングのことを知っていたので領収書を自動化して保存することができました。プログラムの作成には時間がかかったものの、これから 10年、 20年と長い目で見た時、おそらく自動で領収書を保存する方がトータル時間は短いように思います。またネガティブな印象の強い確定申告も、プログラミングを使って楽しく資料作成することができそう。

このようにめんどくさい事、時間のかかる単純作業を自動化できる Python、それから Web上のデータを味方につけられる スクレイピング技術、自由に操れたらもっと人生を、時間を豊かに過ごせそうですね。

Pythonの基礎学習は参考書やネットコンテンツなど色々ありますが、細かく・正確に・スピーディーに・自由に対応できるのは「オンライン型のプログラミング・スクール」ぐらいではないでしょうか? 一時的に受講料は必要ですが、今後長い人生を考えれば決して高くないと思いますよ。

「オンライン型のプログラミング・スクール???」という方、まずはお試しでどんなレッスン内容か体験することができます。CodeCampでは、プログラミング初心者を対象に現役エンジニアの先生が分かりやすく教えてくれますよ。まずは公式ページから『無料体験』確認してみて下さい。

オシママサラ
この記事を書いた人
オシママサラ
\ 無料体験開催中!/自分のペースで確実に習得!
オンライン・プログラミングレッスンNo.1のCodeCamp