PythonのWebスクレイピングでAmazonのお買い物金額を一発集計



PythonのWebスクレイピングでAmazonのお買い物金額を一発集計

Amazon、利便性はいいものの、領収書の手配や買い物累計額など管理面はちょっとイマイチですよね。

特に確定申告時に Amazonの領収書や累計額を算出しようと思うとチョット大変。

今回は、そんな「大変」を Pythonの Webスクレイピング技術を使って解決してみました。

作成したプログラムは、 2018年版ですが、プログラムを理解すると 2019年でも使えると思いますし、楽天市場などの買い物累計額の算出にも活用できると思います。

【対象者】

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

【できること】

  • Amazon.com の年間買い物額累計を自動計算
目次
  1. PythonのWebスクレイピングでAmazonのお買い物金額を一発集計
  2. 今回Webスクレイピングで作成したAmazon買い物累計額自動計算ボットの様子
  3. Amazonの買い物金額管理方法
  4. スクレイピング設計
  5. プログラミング環境
  6. プログラムの作成(前半)
  7. 前半のプログラムを実行した結果
  8. プログラムの作成(後半)
  9. まとめ

PythonのWebスクレイピングでAmazonのお買い物金額を一発集計

今回Webスクレイピングで作成したAmazon買い物累計額自動計算ボットの様子

まずはじめに今回作成した自動計算の様子をご参考下さい。人間に代わってプログラムが自動で Amazonの注文履歴を確認し、計算してくれています。

上記動画のPythonコード

Amazonの買い物金額管理方法

image

img: https://amazon.co.jp

最初に Pythonを使わなくても、Amazonの買い物金額を算出できる方法を確認しておきます。

  • amazon business の利用
  • 会計ソフトの利用
  • 少ない取引件数

上記のようなサービスを利用していれば今回ご紹介する Pythonプログラムは不要と思いますが、利用していない方も多いと思います。 ちなみに amazon businessについては、申請から確認完了までに 3日ほどかかり、直近の青色申告書が必要。私のように急いでいる、白色申告者にとっては利用できないサービス。

そして会計ソフトについても、年間 8,000円〜 36,000円ほど支払っている方のみ利用可能。多くの個人事業者、年金受給で確定申告が必要な方は、こうした会計ソフト利用していませんよね。

お金を出して有償サービスを利用すれば今回のようなプログラミングは不要かもしれませんが、「経費節約」「時間節約」と考えている方にとっては役立つプログラムと思います。

スクレイピング設計

image

現在 Amazonでお買い物をした金額の累計を計算しようと思うと、注文履歴のページから金額を拾って手計算する必要があります。私の場合は、61件分の金額を確認する必要が(上図)。しかも 1ページに表示できる履歴は 10件、イチイチ「次へ」をクリックしないといけません。大変めんどくさい作業です、 実際に手計算してみると 15分ほどかかりました。

この面倒くさい作業を自分に代わってプログラムにやってもらおうというのが今回のお題。 Amazonの Webページ上の情報収集には 「Webスクレイピング」 という技術が活かせます。Webスクレイピングできるプログラミング言語は、 Ruby や Python、 PHP とありますが、現在学習中でもある Pythonを使ってスクレイピングしてみました。

そして Python で Webスクレイピングを手伝ってくれるライブラリは以下のようなのモノが。

  • Beautiful Soup
  • Selenium
  • Pandas
  • Scrapy

【Python入門】Webスクレイピングとは?サンプルコード付きでご紹介

今回の Amazon の累計額を確認しようと思うと、まず「ログイン」する必要があります。その「ログイン」を人間の代わりにやってくれるのが 「Selenium」 です。消去法で Selenium というライブラリを使って、スクレイピングしていきます。全体像をイメージすると下記のような感じに(画像クリックで拡大)。

それでは今回プログラミングしていくパソコンの環境を確認しておきましょう。

プログラミング環境

image

今回のプログラムを実行するために必要なパソコンの環境は以下の通りです。

  • OS/ Windowsでも Macでも Linux系でも可
  • Pythonバージョン 3.6系
  • pip(Pythonのライブラリ管理)
  • FireFox

まず Python3 の実行環境が必要となります。 Pythonが未インストールの方は、こちらの記事を参考にインストールして下さい。 Python3 をインストールすれば pip も同時にインストールされます。

ブラウザの FireFoxが必要な理由は、今回自動で Webページをスクローリングするのに私が普段使っていない FireFox が軽量でいいかな、と判断したためです。プログラムを変更すれば Chrome や Safari などでもスクレイピング可能です。

プログラムの作成(前半)

まずは完成プログラムから見てみましょう。

image

GitHub

上記画像では本プログラムの前半部分が表示されています。前半部分には、FireFoxを起動し、自動ログイン、 2018年分の注文履歴ページまで自動移動する内容。

画像に追記されているコメント毎にプログラムの紹介をしていきます。

使用するライブラリ

今回は、Pythonライブラリの Selenium と csv、 time の 3つを使います。

from selenium import webdriver
import csv
import time

import の下の total = 0 は後半登場してきますので、今は控えます。

ブラウザの指定

今回は FireFox を使用しますので、

browser = webdriver.Firefox()

Chrome や Safari を使う場合は、

browser = webdriver.Chrome()
browser = webdriver.Safari()

尚、 Safariを使う場合は、事前に設定画面から「リモートオートメーションを許可」にチェックを入れる必要があります。

browser.implicitly_wait(10)

こちらのコードは、 指定したブラウザが起動するまで 10秒待ちます、という意味。パソコンによってブラウザの起動時間って違うと思いますので、 implicitly_wait() 関数を使ってブラウザのエラー制御を実行。チョット通信速度が遅かったり、ブラウザの起動が遅いという方は、 10 を 20とかに変えてみると良さそうですね。

ブラウザの起動

Selenium を使ってブラウザ起動する場合は、

browser.get("https://〇〇.com")

とします。 ここの browser は、先ほど設定した browser = webdriver.Firefox ですね。 指定URLは、単純に https://amazon.co,jp からでもいいのですが、なるべく手間を省くため注文履歴のページの URL を本プログラムではセットしています。これは注文履歴画面から一旦ログアウトした時に表示される URL。

スクレイピング技術を使って文字を入力

Selenium を使って Webページに文字を入力する時は、

入力先.send_keys("●●")

とすれば OK。入力先は、 HTML や CSS を使って指定します。例えば今回のユーザー名の場合は、

image

ユーザー名のところで右クリックし、 HTML要素を確認します。すると id = "ap_email" とありますね。この id を使って入力先を指定すると

入力先 = browser.find_element_by_id("ap_email")

となります。入力先については任意の値で、今回は email_elem としています。よってユーザー名の自動入力は、

email_elem = browser.find_element_by_id("ap_email")
email_elem.send_keys("★入力★ユーザー名")

で処理してくれます。★入力★ユーザー名を、自分の Amazonアカウントのユーザー名に置き換えて下さい。パスワードについても同じ要領で処理できますね。

ユーザー情報を入力した後は、「ログイン」ボタンを押してもらう必要が。これは

パスワードの入力先.submit() 

で処理可能。例えばこんな感じですね。

password_elem.submit()
【ここまでのコード】

  from selenium import webdriver
  import csv
  import time
  #
  total = 0
  #
  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()
  

これでスクレイピングの技術を使って、手入力ではなく、プログラムによって自動ログインできる方法を習得できましたね。

スクレイピング技術を使ってリンクをクリック

image

恐らくログインした直後に「注文履歴」の画面が表示されると思いますが、念の為、『注文履歴』ボタンが押されるようにプログラムしてみましょう。リンクのクリックは、

クリック先.click()

でOKですね。

クリック先については、注文履歴ボタン上で右クリックし、 HTML要素を確認。今度は id がありません。この場合は「注文履歴」という HTML 要素の周りを見ると <a>タグで「注文履歴」が囲まれていることが確認できます。これであれば Selenium の find_element_by_link_text("●●") が使えそう。よってコードにすると

リンク = browser.find_element_by_link_text("注文履歴")
リンク.click()

今回は「リンク」部分を element の elem としました。

スクレイピング技術を使ってリスト(li)を表示

image

今回は 2018年分の取引を確認したいので、期間指定で 2018 を選択する必要があります。今までと同じように 期間を選択するボタンの上で右クリックすると

id="orderFilter_3"

が見つかります。早速 browser.find_element_by_id("orderFilter_3") で実行するものの、「見つかりません」というエラーが。

image

どうも <a>タグ内のリンク

href = "javascript:void(0)"

が Slenium では処理できない様子。リンク先が JavaScript だったら何だかの中間処理が必要なのかもしれません。他に Slenium で処理できるキーワードがないか検索するも、これといった要素がみあたりません。改めて Slenium で HTML を指定する方法を確認してみますと、

  • find_element_by_id()
  • find_element_by_name()
  • find_element_by_xpath()
  • find_element_by_link_text()
  • find_element_by_partial_link_text()
  • find_element_by_tag_name()
  • find_element_by_class_name()
  • find_element_by_css_selector()

2019 や 2018、 2017 は、HTMLのリスト構造(<li>)をなしているので xpath() でもいけそうですが、設定が難しいです。そこでHTMLコードの範囲を広げて確認してみると、

<form id="timePeriodForm" method="get" action="/gp/yo・・・・・・・・

というコードがあります。こちらの id を使うと期間指定のリストを表示できました。

リンク = browser.find_element_by_id("timePeriodForm")
リンク.click()

今回は リンクを elem2 でセット。

スクレイピングでリスト内<li>の要素を選択

image

先ほどの 「期間のリストを表示」 の項目ではダメだった 2018年の要素 find_element_by_id("orderFilter_3") を使ってみます。今度は一度リストを開いた状態なので Slenium が 『2018年』をクリックしてくれました。

elem3 = browser.find_element_by_id("orderFilter_3")
elem3.click()

ここで一旦 1秒間のプログラム休憩を入れています。

time.sleep(1)

これがなくても動くのですが、動きの確認とエラーの未然予防として一旦休憩を入れています。

以上で前半のプログラム終了です。次の後半では、Webページからのデータ抽出とページ送りを繰り返すプログラムを作成していきます。

前半のプログラムを実行した結果

【前半のコード】

from selenium import webdriver
import csv
import time
#
total = 0
#
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()
#
elem = browser.find_element_by_link_text("注文履歴")
elem.click()

elem2 = browser.find_element_by_id("timePeriodForm")
elem2.click()

elem3 = browser.find_element_by_id("orderFilter_3")
elem3.click()
time.sleep(1)
  

ここまでご紹介したコードを実際に動かした結果です。 Selenium はじめての方は、この BOT感、たまらないと思います。今まで手動でログインしていたことが、プログラムによって自動ログインし、必要なページに自動でアクセス。プログラミングって、おもしろいですね。


プログラムの作成(後半)

image

プログラムの後半は、ページ内に表示されている金額を抽出し、合計金額を自動計算。そして次のページヘ自動で移動して、また自動計算、ということをプログラムします。

ページ内の金額抽出から次のページをクリックするまでを一つの動きとして、それを繰り返すように while文でループ。

順番にコードをご紹介していきましょう。

ページ内の注文毎の金額を取得(スクレイピング方法の選択)

image

ここの作業は難しかったのですが、まずダイレクトに金額を抽出することは不可能と判断。上図のように金額の HTML を確認すると id はなく、 CSS も他の要素と同じものを使用。金額だけ・・を特定する要素は見当たりません。

そこで試しに Selenium の CSS を使った抽出方法を実行

  • find_element_by_class_name()
  • find_element_by_css_selector()

金額付近の CSS、 span.a-color-secondary.value も div.a-row.a-size-base も抽出できないと、 Seleniumエラーがでます。

【実行したが上手くいかなかったコード】

browser.find_element_by_class_name("span.a-color-secondary.value")
browser.find_element_by_css_selector("span.a-color-secondary.value")

browser.find_element_by_class_name("div.a-row.a-size-base")
browser.find_element_by_css_selector("div.a-row.a-size-base")

そこで Selenium の抽出方法を CSS から XPATH に変更。 XPATH は、 id や name など絶対的な要素がない場合に有効。HTMLタグを上から順番に辿っていき、要素を特定する方法です。コードにすると以下のような感じでしょう。

【spanタグ指定の場合】
browser.find_elements_by_xpath("//span[@class='a-color-secondary value']")

【divタグ指定の場合】
browser.find_elements_by_xpath("//div[@class='a-row a-size-base']")

サンプルで実行してみました。

while pages_remaining:
    try:
        price_element1 = browser.find_elements_by_xpath("//span[@class='a-color-secondary value']")
        print(price_element1)

    except:
        browser.close()        

image

するとわけのわからない記号が。。。これは XPATHでスクレイピングした結果、取得データが Selenium 特有のデータ型になっているためこのような表示に。データ型をテキストスタイルに変換すれば抽出内容を確認できるでしょう。テキストスタイルへの変換は、 ○○.text で処理できますね。今回はページ内の取得要素全てをテキスト型に変換しますので for文を使ってループ処理しました。

while pages_remaining:
    try:
        price_element1 = browser.find_elements_by_xpath("//span[@class='a-color-secondary value']")
        price = [x.text for x in price_element1]
        print(price)

    except:
        browser.close()

image

参考までに divタグを指定した場合のコードでも実行してみました。

browser.find_elements_by_xpath("//div[@class='a-row a-size-base']")

image

どちらでも金額を抽出できているので使えそうですが、このあと領収書の自動保存も考えていたため、今回は「領収書/購入明細書」のデータを拾えている div の方を採用することにしました。ちなみに上記プログラムは無限にデータ取得の処理を繰り返しますので、実行後は コマンド画面で Ctrl + C でプログラムを終了して下さい。

次はこの抽出データの中から、金額のみを拾って計算準備をしたいと思います。

スクレイピングデータから特定要素のみを抽出

image

先ほどのセクションではダイレクトに金額を取得できなかったため、金額が含まれる項目をスクレイピングしました。取得データを見てみると、リスト型の中に

'2018年11月30日', '¥ 2,671', '大島孝之', '注文の詳細 領収書/購入明細書',

と 4項目が繰り返し羅列されています。まずは、この中の ¥ を含む要素だけをピックアップしてみます。配列内の特定要素をピックアップする方法は、

s for s in 編集する配列データ if "ピックアップしたい要素内にある文字" in s

今回のケースでは、

price_data = [s for s in price if "¥" in s]

これでいけそうですね。

【実行結果】

image

【上図の実行コード】

  from selenium import webdriver
  import csv
  import time
  #
  total = 0
  #
  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()
  #
  elem = browser.find_element_by_link_text("注文履歴")
  elem.click()
  #
  elem2 = browser.find_element_by_id("timePeriodForm")
  elem2.click()
  #
  elem3 = browser.find_element_by_id("orderFilter_3")
  elem3.click()
  time.sleep(1)
  #
  pages_remaining = True
  #
  while pages_remaining:
      try:
          price_element = browser.find_elements_by_xpath("//div[@class='a-row a-size-base']")
          price = [x.text for x in price_element]
          price_data = [s for s in price if "¥" in s]
          print(price_data)
  #
      except:
          browser.close()
  

やっと欲しかった金額データがここで取得できました。しかし、これらの配列内にある金額、データ型は文字列で計算はできないのですね。ここで配列内のデータ型を Str から Int に変換する必要が。

配列内のデータ型の確認は、print文を

print(type(price_data[0]))

とすると確認できます。

image

スクレイピングデータから特定の文字を削除

image

Webスクレイピングで見事金額のみを抽出できたのですが、計算するためには以下の 2つをクリアする必要がありますね。

  • データ型を Int に変換
  • ¥ マークを削除

まずは ¥マークを削除し、それから 数値型(Int) に変換しましょう。

¥マークの削除は、 replace()メソッドを使って処理できるでしょう。replace()のコードは、

変換元のデータ.replace("¥ ", "")

ですね。¥とついでに , マークも削除します。これを今回のケースにあてはめると、

for data in price_data:
    after_data = data.replace("¥ ", "")
    next_after_data = after_data.replace(",", "")
print(next_after_data)
【上記コードの全体】

  from selenium import webdriver
  import csv
  import time
  #
  total = 0
  #
  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()
  #
  elem = browser.find_element_by_link_text("注文履歴")
  elem.click()
  #
  elem2 = browser.find_element_by_id("timePeriodForm")
  elem2.click()
  #
  elem3 = browser.find_element_by_id("orderFilter_3")
  elem3.click()
  time.sleep(1)
  #
  pages_remaining = True
  #
  while pages_remaining:
      try:
          price_element = browser.find_elements_by_xpath("//div[@class='a-row a-size-base']")
          price = [x.text for x in price_element]
          price_data = [s for s in price if "¥" in s]
          print(price_data)
          #
          for data in price_data:
              after_data = data.replace("¥ ", "")
              next_after_data = after_data.replace(",", "")
          print(next_after_data)
  #
      except:
          browser.close()
  

image

おかしいですね、 ¥ と , の2つを削除しているはずなのに、出力結果は変わりません。この問題を解決する方法の一つに、「配列を作りなおす」方法があります。

replace()処理の前にカラの配列を用意し、削除・編集したデータを新しいカラの配列に足していくというやり方です。コードにすると

price_data_N = []
for data in price_data:
    after_data = data.replace("¥ ", "")
    next_after_data = after_data.replace(",", "")
    price_data_N.append(next_after_data)
print(price_data_N)
【上記コードの全体】

  from selenium import webdriver
  import csv
  import time
  #
  total = 0
  #
  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()
  #
  elem = browser.find_element_by_link_text("注文履歴")
  elem.click()
  #
  elem2 = browser.find_element_by_id("timePeriodForm")
  elem2.click()
  #
  elem3 = browser.find_element_by_id("orderFilter_3")
  elem3.click()
  time.sleep(1)
  #
  pages_remaining = True
  #
  while pages_remaining:
      try:
          price_element = browser.find_elements_by_xpath("//div[@class='a-row a-size-base']")
          price = [x.text for x in price_element]
          price_data = [s for s in price if "¥" in s]
          print(price_data)
          #
          price_data_N = []
          for data in price_data:
              after_data = data.replace("¥ ", "")
              next_after_data = after_data.replace(",", "")
              price_data_N.append(next_after_data)
          print(price_data_N)
  #
      except:
          browser.close()
  

image

思うような結果が得られましたね。スクレイピングで取得したデータから不要な文字を削除することに成功しました。あとはこの金額のデータ型を Str から Int に変換する手続きを行えばOKですね。

スクレイピングした要素のデータ型変換

Pythonのデータ型の変換、文字列から整数型に変換するコードは、

Int(変換したいデータ)

でしたね。これを今回のケースにあてはめると

Int_Price_Data = [int(s) for s in price_data_N]
print(Int_Price_Data)

print(type(Int_Price_Data[0]))
【上記コードの全体】

  from selenium import webdriver
  import csv
  import time
  #
  total = 0
  #
  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()
  #
  elem = browser.find_element_by_link_text("注文履歴")
  elem.click()
  #
  elem2 = browser.find_element_by_id("timePeriodForm")
  elem2.click()
  #
  elem3 = browser.find_element_by_id("orderFilter_3")
  elem3.click()
  time.sleep(1)
  #
  pages_remaining = True
  #
  while pages_remaining:
      try:
          price_element = browser.find_elements_by_xpath("//div[@class='a-row a-size-base']")
          price = [x.text for x in price_element]
          price_data = [s for s in price if "¥" in s]
          print(price_data)
          #
          price_data_N = []
          for data in price_data:
              after_data = data.replace("¥ ", "")
              next_after_data = after_data.replace(",", "")
              price_data_N.append(next_after_data)
          print(price_data_N)
          #
          Int_Price_Data = [int(s) for s in price_data_N]
          print(Int_Price_Data)
          #
          print(type(Int_Price_Data[0]))
  #
      except:
          browser.close()
  

image

¥ も , も取れて、データ型も Str から Int に変換できました。後はこのデータを元に計算していけば累計金額を算出できますね。

スクレイピングしたデータの集計

今回スクレイピングした金額のデータは、配列型に収まっています。1つのページに表示されている金額が、一つの配列に納まっている形。つまり1ページの合計金額を出すには、配列内の要素を足せばOKですね。足し算には Python の sum() 関数が使えます。今回のケースにあてはめると、

sum(Int_Price_Data)
【上記コードの全体】

  from selenium import webdriver
  import csv
  import time
  #
  total = 0
  #
  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()
  #
  elem = browser.find_element_by_link_text("注文履歴")
  elem.click()
  #
  elem2 = browser.find_element_by_id("timePeriodForm")
  elem2.click()
  #
  elem3 = browser.find_element_by_id("orderFilter_3")
  elem3.click()
  time.sleep(1)
  #
  pages_remaining = True
  #
  while pages_remaining:
      try:
          price_element = browser.find_elements_by_xpath("//div[@class='a-row a-size-base']")
          price = [x.text for x in price_element]
          price_data = [s for s in price if "¥" in s]
          print(price_data)
          #
          price_data_N = []
          for data in price_data:
              after_data = data.replace("¥ ", "")
              next_after_data = after_data.replace(",", "")
              price_data_N.append(next_after_data)
          print(price_data_N)
          #
          Int_Price_Data = [int(s) for s in price_data_N]
          print(Int_Price_Data)
          #
          print(sum(Int_Price_Data))
  #
      except:
          browser.close()
  

image

手計算しても合計金額があっていますね。これで Webスクレイピングしたデータを使って、演算することができるようになりました。

ただ、今回のケースでは 1つのページ内の合計値を求めるだけでなく、 2ページ目、 3ページ目と限りあるだけの合計金額を足していく必要があります。この処理については、累積金額を total = 0 などとして、ループ毎に足していく処理をすれば OK。コードにすると、

print(sum(Int_Price_Data))
total = sum(Int_Price_Data) + total
print(total)
【上記コードの全体】

  from selenium import webdriver
  import csv
  import time
  #
  total = 0
  #
  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()
  #
  elem = browser.find_element_by_link_text("注文履歴")
  elem.click()
  #
  elem2 = browser.find_element_by_id("timePeriodForm")
  elem2.click()
  #
  elem3 = browser.find_element_by_id("orderFilter_3")
  elem3.click()
  time.sleep(1)
  #
  pages_remaining = True
  #
  while pages_remaining:
      try:
          price_element = browser.find_elements_by_xpath("//div[@class='a-row a-size-base']")
          price = [x.text for x in price_element]
          price_data = [s for s in price if "¥" in s]
          print(price_data)
          #
          price_data_N = []
          for data in price_data:
              after_data = data.replace("¥ ", "")
              next_after_data = after_data.replace(",", "")
              price_data_N.append(next_after_data)
          print(price_data_N)
          #
          Int_Price_Data = [int(s) for s in price_data_N]
          print(Int_Price_Data)
          #
          print(sum(Int_Price_Data))
          total = sum(Int_Price_Data) + total
          print(total)
  #
      except:
          browser.close()
  

totalの値が、 2018年アマゾンで買い物をした金額の合計値になるはずです。

ここまでで金額の計算処理は一旦完了です。あとは 2ページ目に移動するように Selenium に指示する必要がありますね。

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

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 csv
  import time
  #
  total = 0
  #
  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()
  #
  elem = browser.find_element_by_link_text("注文履歴")
  elem.click()
  #
  elem2 = browser.find_element_by_id("timePeriodForm")
  elem2.click()
  #
  elem3 = browser.find_element_by_id("orderFilter_3")
  elem3.click()
  time.sleep(1)
  #
  pages_remaining = True
  #
  while pages_remaining:
      try:
          price_element = browser.find_elements_by_xpath("//div[@class='a-row a-size-base']")
          price = [x.text for x in price_element]
          price_data = [s for s in price if "¥" in s]
          print(price_data)
          #
          price_data_N = []
          for data in price_data:
              after_data = data.replace("¥ ", "")
              next_after_data = after_data.replace(",", "")
              price_data_N.append(next_after_data)
          print(price_data_N)
          #
          Int_Price_Data = [int(s) for s in price_data_N]
          print(Int_Price_Data)
          #
          print(sum(Int_Price_Data))
          total = sum(Int_Price_Data) + total
          print(total)
          #
          next_link = browser.find_element_by_partial_link_text("次へ")
          next_link.click()
  #
      except:
          browser.close()
  

image

いけましたね。これで Webスクレイピングを使って、複数ページにまたがるデータ収集および抽出データの演算に成功しました。実行してみると分かると思うのですが、ブラウザの反応とコマンドの反応にズレが出たりします。このエラーに繋がりそうな要因は、 time.sleep() を使うと安心してデータ収集の様子を見ていられます。

CSVファイルへのデータ保存も含めた最終的なコードは下記のようになります。

完成形のコード

【完成形のコード】

  from selenium import webdriver
  import csv
  import time
  #
  total = 0
  #
  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()
  #
  elem = browser.find_element_by_link_text("注文履歴")
  elem.click()
  #
  elem2 = browser.find_element_by_id("timePeriodForm")
  elem2.click()
  #
  elem3 = browser.find_element_by_id("orderFilter_3")
  elem3.click()
  time.sleep(1)
  #
  pages_remaining = True
  #
  while pages_remaining:
      try:
          price_element = browser.find_elements_by_xpath("//div[@class='a-row a-size-base']")
          price = [x.text for x in price_element]
          price_data = [s for s in price if "¥" in s]
          print(price_data)
          #
          price_data_N = []
          for data in price_data:
              after_data = data.replace("¥ ", "")
              next_after_data = after_data.replace(",", "")
              price_data_N.append(next_after_data)
          print(price_data_N)
          #
          Int_Price_Data = [int(s) for s in price_data_N]
          print(Int_Price_Data)
          #
          print(sum(Int_Price_Data))
          total = sum(Int_Price_Data) + total
          print(total)
          #
          with open("アマゾン注文額履歴.csv", "a") as csvFile:
              writer = csv.writer(csvFile)
              writer.writerow(Int_Price_Data)
              csvFile.close()
              time.sleep(1)
          #
          next_link = browser.find_element_by_partial_link_text("次へ")
          next_link.click()
          time.sleep(1)
  #
      except:
          browser.close()
  

まとめ

HTML や Python に慣れていないと 「そんなことぐらい手計算した方が早いじゃん」 と思うことでしょう。しかし、こうした技術は単なる「計算」という枠を超えて、データ分析にも活用できます。例えば、サーバーで今回のようなプログラムを定期的に実行し、定期的に Web上のデータを収集。その結果、誰も持っていないような価格変動のデータや気象データの変化、 SNSの状況変化など Web上の多くのデータを使うことができるようになります。内容によっては、売れます。

今回は身近な Amazon の価格をスクレイピング、と単純そうなことからはじまり、 Pythonの配列データの要素抽出や要素の編集、それから要素の演算と Pythonの基礎学習には出てこないような配列処理を体験しました。

「Pythonも HTML、CSS もよく分からないけど、データ分析やデータアナリティクスには興味ある」という方、まずは基礎から学習はじめませんか? 「効率」と「正確性」「スピード」を考えるとやはりプログラミング・スクールが有効でしょう。中でもオンライン・タイプは、場所と時間の制約が少ないので受講しやすいです。

CodeCamp では、オンライン学習をよりイメージしやすくするために『無料体験』を実施しています。ご興味ある方は、公式ページより『無料体験』確認してみて下さい。

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