作成する物
Amazonの商品URLをExcelに箇条書きし、そのURLを基に商品名と価格をスクレイピングしてExcelに出力するアプリケーションを作成します。
①ExcelにURLを記載する(手動)
②アプリケーションを実行
③Excelに商品名と価格を出力
④グラフ表示
Pythonの環境構築がまだの方は以下の記事を参考に環境構築してください。
ソースコード
プロジェクト毎ダウンロードする場合は以下のGithubからどうぞ。
※スクレイピングではHTMLのタグや属性からページ情報を取得しています。
Amazonの商品ページ構成に変更があった場合、掲載しているソースコードをそのまま実行してもエラーとなる可能性があります。いつ変更されるかもわからないため、随時対応は行いません。
また、使用しているライブラリに破壊的な変更があった場合もエラーとなる可能性があります。
使用するライブラリ
このアプリケーションでは以下のライブラリを使用します。
pipからインストールをお願いします。
・openpyxl
Excel操作ライブラリです。
1 |
pip install openpyxl |
・selenium
Webブラウザ操作ライブラリです。
1 |
pip install selenium |
・webdriver_manager
seleniumで使用するwebdriverを自動インストールするライブラリです。
1 |
pip install webdriver_manager |
・BeautifulSoup4
HTMLパーサー。
1 |
pip install beautifulsoup4 |
プロジェクトの構成
AmazonScraping
│
├─data
│ scraping.xlsx(入出力するExcelファイル)
│
├─src
│ │ main.py(アプリケーションメインプログラム)
│ │
│ └─modules
│ ├─amazonscraping
│ │ │ amazon_scraping.py(自作モジュール)
│ │ │ init.py
│ │ │
│ │ └─pycache
│ │ amazon_scraping.cpython-310.pyc
│ │ init.cpython-310.pyc
│ │
│ ├─excel
│ │ │ excel.py(自作モジュール)
│ │ │ init.py
│ │ │
│ │ └─pycache
│ │ excel.cpython-310.pyc
│ │ init.cpython-310.pyc
│ │
│ ├─utils
│ │ │ utils.py(自作モジュール)
│ │ │ init.py
│ │ │
│ │ └─pycache
│ │ utils.cpython-310.pyc
│ │ init.cpython-310.pyc
│ │
│ └─pycache
│ amazon_scraping.cpython-310.pyc
│ init.cpython-310.pyc
│
└─pycache
amazon_scraping.cpython-310.pyc
socks.cpython-310.pyc
sockshandler.cpython-310.pyc
解説
ExcelからURLを読込む
Excel関連の処理をまとめたクラスExcelを定義したモジュール。(excel.py)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 |
from openpyxl import Workbook, load_workbook class Excel: alphabet = { 1 : 'A', 2 : 'B', 3 : 'C', 4 : 'D', 5 : 'E', 6 : 'F', 7 : 'G', 8 : 'H', 9 : 'I', 10 : 'J', 11 : 'K', 12 : 'L', 13 : 'M', 14 : 'N', 15 : 'O', 16 : 'P', 17 : 'Q', 18 : 'R', 19 : 'S', 20 : 'T', 21 : 'U', 22 : 'V', 23 : 'W', 24 : 'X', 25 : 'Y', 26 : 'Z' } def __init__(self, path): self.path = path self.wb = load_workbook(path) def __del__(self): if self.wb != None: self.wb.close() def get_sheet_names(self): return self.book.sheetnames def get_book(self): return self.book def get_sheet(self, name): return self.wb[name] def add_sheet(self, name): return self.wb.create_sheet(name) def remove_sheet(self, name): self.book.remove(name) def save(self, path=''): if path == '': path = self.path self.wb.save(path) def get_row_values(self, ws, idx): values = [list(filter(None,list(cell))) for cell in ws.iter_cols(min_col=ws.min_column, max_col=ws.max_column, min_row=idx, max_row=idx, values_only=True)] return [item for value in values for item in value] def change_col_number_from_index(self, idx): return self.alphabet[idx] |
Excel読込み処理(main.py)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
# 作業ディレクトリをmain.py格納ディレクトリに設定 os.chdir(os.path.dirname(os.path.abspath(__file__))) print('---target urls----------') # Excelを開く excel = Excel('..\\data\\scraping.xlsx') # urlシートを取得 ws = excel.get_sheet('url') urls = [] # A1~A1000までを探索 for i in range(1, 1000): cell = 'A' + str(i) val = ws[cell].value # URLが指定されてなければ終了 if val == None: break # URLをリストに取得 urls.append(val) print(val) |
パスを指定してExcelを開き、urlシートのA列の1行目から1000行目までをリストに取得します。
1行目から1000行目というのはこれだけあれば足りるだろうという適当な数字なのであまり気にしないでください。
openpyxlでセルの値を取得するには、ワークシートオブジェクトのcellメソッドを使用するか、インデクサー([‘A1’]等)を使用します。
seleniumでURLをスクレイピングする
アマゾンのスクレイピング処理をまとめたクラスAmazonScrapingを定義したモジュール。(amazon_scraping.py)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
import os from selenium.webdriver.chrome.service import Service from selenium.webdriver.chrome.options import Options from selenium import webdriver from bs4 import BeautifulSoup from webdriver_manager.chrome import ChromeDriverManager class AmazonScraping: def __init__(self, headress=True): options = Options() if headress: options.add_argument('--headless') # ブラウザを表示するかどうか driver = ChromeDriverManager( log_level=0, print_first_line=False, ).install() self.driver = webdriver.Chrome(driver, options=options) self.driver.implicitly_wait(5) def __del__(self): # webdriver終了 if self.driver != None: self.driver.quit() def set_url(self, url): # 指定したURLに遷移 self.driver.get(url) # HTMLをBeautifulSoupオブジェクトでパース self.soup = BeautifulSoup(self.driver.page_source, 'html.parser') def get_page(self, url): return self.driver.page_source def get_productname(self): return str.strip(self.soup.find(id='productTitle').string) def get_price(self): div = self.soup.find('div', id='corePrice_feature_div') span = div.find('span', class_='a-price-whole') if span == None: span = div.find('span', class_='a-offscreen') return span.string.replace('\\', '').replace('¥', '').replace(',', '') |
Amazonスクレイピング処理(main.py)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
# amazonスクレイピングオブジェクト初期化 amazon = AmazonScraping() print('---get value from target urls----------') map = {} for url in urls: # amazonスクレイピングオブジェクトにURLを設定 amazon.set_url(url) map[url] = {} # 欲しい情報を取得 # 商品名 map[url]['商品名'] = amazon.get_productname() print(map[url]['商品名']) # 値段 map[url]['価格'] = amazon.get_price() print(map[url]['価格']) |
AmazonScrapingクラスのコンストラクタでseleniumを初期化しています。
商品名はspanにproductTitleというidが振られているので、beautifulsoupでidを指定して取得します。
1 2 |
def get_productname(self): return str.strip(self.soup.find(id='productTitle').string) |
価格はクラス名が固定ではなく、商品によって2パターンあるようです。(セール商品と通常で違うっぽい?)
とりあえず上記2パターンに対応した価格取得メソッドを作成します。
1 2 3 4 5 6 7 8 |
def get_price(self): div = self.soup.find('div', id='corePrice_feature_div') span = div.find('span', class_='a-price-whole') if span == None: span = div.find('span', class_='a-offscreen') return span.string.replace('\\', '').replace('¥', '').replace(',', '') |
a-price-wholeクラスのspanが取得できなかった場合、a-offscreenクラスのspanを取得します。
取得した商品名と価格を出力するために、連想配列に設定しておきます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
for url in urls: # amazonスクレイピングオブジェクトにURLを設定 amazon.set_url(url) map[url] = {} # 欲しい情報を取得 # 商品名 map[url]['商品名'] = amazon.get_productname() print(map[url]['商品名']) # 値段 map[url]['価格'] = amazon.get_price() print(map[url]['価格']) |
Excelに商品名と価格を出力する
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
# outputシートを取得 ws = excel.get_sheet('output') now = datetime.datetime.now() for key in map.keys(): product = map[key]['商品名'] price = int(map[key]['価格']) cols = excel.get_row_values(ws, 1) idx = indexof(cols, product) # 商品名列が既にある場合 if idx > -1: col_number = excel.change_col_number_from_index(idx+2) # 商品名列がない場合 else: col_number = excel.change_col_number_from_index(ws.max_column+1) ws[col_number+str(1)] = product row = ws.max_row # 日時が出力されていない場合 if ws['A'+str(row)].value != now: row = row+1 # 日時 ws['A'+str(row)] = now # 価格 ws[col_number+str(row)] = price excel.save() |
クソコードで申し訳ないですが、ここではExcelにスクレイピング日時、商品名、価格を出力しています。
Excel1行目B列以降が商品名行、2行目のA列はスクレイピング日時、2行目B列以降に価格を出力しています。
面倒な事をせずに時間、商品名、価格を1行毎に出力すればいいのでは?と思われるかもしれませんが、Excelのグラフを作成する時に楽なんです….!
グラフを表示する
グラフはExcelのグラフを使用しています。
openpyxlでもグラフを作成できるようですが、スクレイピング練習用のアプリなので今回は楽をしちゃいました。
範囲を選択してリボンの挿入→線グラフクリック
適当にスタイルを変更して完成です!
後はmain.pyをタスクスケジューラで毎日実行するように設定すれば日次の価格推移を解析できます。
タスクスケジューラをコマンドプロンプトで設定する方法を下記で解説しているので、参考にどうぞ。
まとめ
ごりへい自身Ptyhonでスクレイピングをするのが初めてなので、説明がものすごく雑になってしまいましたが、Pythonでのスクレイピングの雰囲気を感じてもらえたらと思います。
注意点として、同一ページ(ドメイン)に対して短時間に連続してスクレイピングを行うとDOS攻撃と判断されかねないので、スクレイピングの間隔は少なくとも数秒は空けるようにしましょう。
コメント
コメント失礼いたします。
こちらダウンロードしてなにも変更せずに、動かしてみたのですが下記エラーとなり使用できませんでした。
何か原因等お分かりになりますでしょうか。
Traceback (most recent call last):
File “y:\Python\Program\TEST\AmazonScraping-main\AmazonScraping-main\src\modules\amazonscraping\amazon_scraping.py”, line 23, in __del__ zonscraping\amazon_scraping.py”, line 23, in __del__
if self.driver is not None:
AttributeError: ‘AmazonScraping’ object has no attribute ‘driver’
コメントありがとうございます!
こちらで確認してみたところ、該当のエラーは発生しませんでした。
別件でAmazonページのHTML構成が変わっているようでして、セレクタの指定に修正必要でしたのでGitHubに修正をプッシュしました。
再度GitHubから最新を取得して確認いただけますでしょうか。
ただこちらの問題は連絡いただいた内容とは関係ないような気もしますので、エラーは解決しないかもしれません。