Blow Up by Black Swan

PythonーSeleniumを使って、ZOZOのファッションコーディネートサイト、WEARの店舗一覧を取得してみた

[2019/12/19追記: 誤ってマイマップを削除してしまったためマップの表示例が出ないようになっています。]

一つ前の記事でgoogleスプレッドシートを使ってZOZOのファッションコーディネートサイトをスクレイピングし、googleマップにプロットするという記事を書きました。

しかし、思った以上に力技の部分があり、1ページ分しかスクレイピングできませんでした。そこで今回は、pythonのSeleniumモジュールを利用して本格的にWEARのセレクトショップ一覧を取得し、googleマップにプロットしてみたいと思います。

1. プロジェクト内容と構築環境

今回のプロジェクト内容は以下になります。

  • プロジェクト内容: Seleniumを利用して、ZOZOのファッションコーディネートサイト、WEARからセレクトショップ一覧を取得し、googleマップのマイマップにプロットする
  • 流れ:
    1. Seleniumでセレクトショップ一覧を取得
    2. googleマップのマイマップにプロット
  • 備考:
    • 対象地域は兵庫県のみとする

また今回の構築環境は以下になります。

  • 使用PC: Macbook(OSX)

2. Seleniumのインストール

まずはSeleniumを導入します。基本的には直近1年くらいに絞ってググれば丁寧にインストールの仕方が書いてあるブログがありますので、そちらを参考にするのが良いと思いますが、自分が色々なサイトを参考にインストールする中でいくつか疑問に思い調べたことがあるので、それらを下記に整理ました。

  • Q. 一部のブログや書籍では、SeleniumとセットでPhantomJSのインストールが必要だと書いてあったが、本当にPhantomJSのインストールは必要か
    • A. ここでいうSeleniumはPythonのモジュールで、PhantomJSはWebブラウザ(グーグルクロムやFireFox、Safariなどのこと)です。少し前まではSeleniumでの仕様に適していたのはPhantomJSだけだったようですが、今ではグーグルクロムやFireFoxでも十分Seleniumを使うことができます。またPhantomJSはすでにサポートが終了していることもあり、現在ではグーグルクロムを利用するのが一般的になりつつあるようです。もし、自身のPCにグーグルクロムがインストールされていない場合は、グーグルクロムをインストールする必要があります。
  • Q. いくつかのブログでグーグルクロムを使うためのドライバをインストールページが異なっているようだが、正式なものはどれか
  • Q. グーグルクロムをヘッドレス(ブラウザを実際には表示しないこと)で使うために他のモジュールなどを追加でインストールする必要があるか
    • A. ありません。のちのコードでヘッドレスで実行するよう設定しています。
  • グーグルクロムのドライバへのパスを通す必要はあるか。
    • 通さなくとも使用することができます。ただし、ドライバまでのパスは把握しておく必要はあります。

実際の流れは下記になります。

1. Seleniumモジュールのインストール

pip install selenium

2. 上記サイトでグーグルクロムのドライバをダウンロードし、どこでも良いので保存(あとでそのパスが必要になる)。

以上でSeleniumの導入は完了です。

3. Seleniumを使ってWEARの店舗一覧を取得

該当ページのイメージは以下になります。

ここから「店舗名」と「住所」データを取得していきます。htmlページの見方などは他のサイトや以前の記事を見て頂ければすぐにわかると思うので割愛します。スクレイピングをする上でページの特徴を知る必要がありますが、ここでわかった特徴は以下になります。

  • 店舗リストは動的に生成されるため、Request+beautifulsoupのようにシンプルにhtmlを取得する方法では店舗リストを取得できない
  • ページ関連
    • ページのURL構造: 「 https://wear.jp/shop/?country_id=1&region_id=28&pageno=◯ 」
    • 合計ページ数は56ページ
  • 店舗情報関連
    • 1ページにつき20件程度の店舗が載っている
    • 店舗名のXpath: 「//*[@id=”list_1column”]/ul/li[〜]/div[1]/div[2]/h3/a」(“〜”部分が変わる場所)
      • ただし、liの要素数は1から順々に増えていくか一部データがないものが存在する
    • 住所のXpath: 「//*[@id=”list_1column”]/ul/li[2]/div[1]/div[2]/ul[1]/li[〜]」(“〜”部分が変わる場所)
      • 郵便番号がある場合はliの要素は「1」、ない場合は「2」となっている

上記を踏まえ作成したプログラムが下記になります。

# URL一覧を生成 -> 56page
url = "https://wear.jp/shop/?country_id=1®ion_id=28&pageno={}"
pages = []
for i in range (1, 57):
    pages.append(url.format(i))


from selenium.webdriver import Chrome, ChromeOptions

path = "/Users/hoge/Applications/webdrivers/chromedriver"    #WEBdriverのパス
name_path = "//*[@id=\"list_1column\"]/ul/li[{}]/div[1]/div[2]/h3/a"    #店舗名のXPath
address_path = "//*[@id='list_1column']/ul/li[{}]/div[1]/div[2]/ul[1]/li[2]"    #住所のXPath(郵便番号がある場合を想定したXPath)

#ヘッドレスでブラウザを扱うための処理
options = ChromeOptions()
options.add_argument("--headless")

#ドライバの生成
driver = Chrome(path, options=options)

shop_list = []    #店舗名と住所を格納するリスト
num = 1    #ページ数

for page in pages:    #各ページに対し以下の処理を行っていく
    driver.get(page)
    i = 1    #店舗名
    err = 0    #
    while True:
        #店舗名を取得
        try:
            name = driver.find_element_by_xpath(name_path.format(i))
        except Exception:
            #3回エラーが出た場合=要素が存在しなかった場合は次のページへ
            if err > 3:
                break
            err += 1
            continue
        
        #住所を取得
        try:
            address = driver.find_element_by_xpath(address_path.format(i))
        #郵便番号がある場合でエラーが出た場合は、郵便番号ない場合のXPathを実行
        except Exception:
            address = driver.find_element_by_xpath("//*[@id='list_1column']/ul/li[{}]/div[1]/div[2]/ul[1]/li[1]".format(i))
        shop_list.append((name.text, address.text))
        print(str(i)+"店舗目終了")
        i += 1
    print(str(num)+"ページ目終了")
    num += 1

流れとしては、店舗名と住所を取得する流れを構築し、店舗名の部分で3回エラー(要素が存在しない)が出た場合に次のページへ進む、というものです。また、郵便番号の部分は基本は存在する前提で進め、それでエラーが出た場合のみ存在しない場合のXPathを実行するというフローにしています。

以上のコードで兵庫県のセレクトショップ情報を入手することができます。

4. googleマップにプロット

続いては、上記をgoogleマップのマイマップにプロットしていきます。ここについては、まずCSVに上記リストを書き込み、それをマイマップにプロットするというフローになります。CSVへの保存方法はシンプルに下記になります。

import csv

with open("/Users/hoge/shop_list.csv", "w") as csvfile:
    writer = csv.writer(csvfile, lineterminator='\n')
    writer.writerows(shop_list)

なお、グーグルマップへのプロット方法は前回の記事と全く同じ方法になりますので、割愛します。プロットされたグーグルマップは以下になります。

[2019/12/19 追記: 誤ってマイマップを消してしまいましたm(_ _)m]

5. まとめ

以上が今回のまとめないようになります。Seleniumは昨年一度学習した時、よくわからず挫折した経験があったのですが、今回はかなり簡単に使うことができました。スクレイピングについても色々と情報の収集に利用していきたいので、beuatifulsoupなど含め幅広く勉強していきたいと思います。

読んで頂き、ありがとうございました。

6. 参考サイト

今回の参考サイトはこちらです。