見出し画像

【selenium】スクレイピングで新宿駅の穴場居酒屋を探してみよう

こんにちは、分析屋の長田です。
突然ですが、飲み会のお店選びって悩みませんか?

私は結構悩んでしまうので割と後回しにしがちで、そうすると人気所はすでに予約が埋まってたりします。ギリギリでも予約が取れやすく、かつ評価の高い、いわゆる穴場である居酒屋を見つけたいというのが今回のテーマです。
ただ、その目線で1つ1つお店を見ていくのも面倒です。楽して探したいので、Pythonのseleniumを用いてグルメサイトからスクレイピングで店舗情報を抽出して、隠れた名店居酒屋を探してみました。

前半でスクレイピング、後半で今回のテーマである穴場居酒屋の調査をしています。


スクレイピングの注意点

スクレイピングを実行するサイトの利用規約robots.txtを確認し、それら規約を遵守するようにしてください
利用規約等でスクレイピングを禁止しているサイトもあります。
利用規約に明示されていない場合でも、サイトに負荷をかけないように注意しましょう。

実装前に用意すること

seleniumを実行するにはChromeDriverのダウンロードが必要です。
また、使用しているChromeのバージョンとChromeDriverのバージョンは一致している必要があるので、Chromeのバージョンを確認して、Chromeのバージョンに合ったChromeDriverをインストールしてください。

スクレイピング実装

先に各種モジュールのインポートと、webdriverの設定をします。

#モジュールのインポート
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.options import Options
import time
from time import sleep
import pandas as pd

#driverの設定
options = webdriver.ChromeOptions()
options.add_argument('--headless')  

インポート諸々が終わったらさっそく実装に入っていきます。

全体の処理をざっくり説明すると、検索結果ページに表示されている店舗数分の情報を取得して、ページ内の店舗情報をすべて取得し終わったら次のページに行って同じように取得、次のページが存在しなければ処理を終了する、という流れでスクレイピングしています。

今回は希望する検索条件が反映された状態の検索結果ページURLを用意してserch_urlという変数に入れて処理していますが、条件が反映されたURLを作成するところからseleniumでブラウザ操作することも可能です(検索ボックスにテキストを入力したり、日付や人数などを選択したり)。
お使いのサイトに合わせて実装しましょう。

#空のリストを用意
list_data = []

#スクレイピング開始
driver = webdriver.Chrome(options=options)
driver.get(serch_url)

# 繰り返し処理(全要素文取得後、「次の20件」ボタンの有無でループ判定)
while True:
    # 表示ページの全要素取得
    time.sleep(10)
    all_elements = driver.find_elements(By.CLASS_NAME,'list-rst.js-bookmark.js-rst-cassette-wrap.js-is-need-redirect.js-done')
    
    # 要素数をカウント
    # 基本1ページ20件だが、最終ページは20件に満たない場合もあるため、
    # 1ページで処理する件数をあらかじめカウントしておく
    num_elements = len(all_elements)

    # 要素の数だけ各要素に対して処理を行う
    for i in range(num_elements):
        element = all_elements[i]

        try:

            # 店舗名を取得
            name = element.find_element(By.CLASS_NAME,'list-rst__rst-name')
            name = name.text

            # 最寄り駅と距離を取得
            station_distance = element.find_element(By.CLASS_NAME,'list-rst__area-genre.cpy-area-genre')
            station_distance_category = station_distance.text

            # 評価を取得
            stars = element.find_element(By.CLASS_NAME,'c-rating__val.c-rating__val--strong.list-rst__rating-val')
            stars = stars.text

            # 口コミ数を取得
            reviews = element.find_element(By.CLASS_NAME,'list-rst__rvw-count-num.cpy-review-count')
            reviews = reviews.text

            # ブックマーク数を取得
            bookmarks = element.find_element(By.CLASS_NAME,'list-rst__save-count-num.u-text-num')
            bookmarks = bookmarks.text

            # 価格帯を取得
            budget = element.find_element(By.CLASS_NAME,'list-rst__info')
            budget = budget.text

            # 詳細ページURLを取得
            url = element.find_element(By.CLASS_NAME,'list-rst__rst-name-target.cpy-rst-name')
            url = url.get_attribute('href')

            # 取得した各要素をリストに格納していく
            list_data.append({"name": name,
                        "station_distance_category": station_distance_category,
                        "stars": stars,
                        "reviews": reviews,
                        "bookmarks": bookmarks,
                        "budget": budget,
                        "url": url})
           
        # エラーが発生したらその要素をスキップして次の要素の取得へ進む
        except Exception as e:
            continue

    # 「次の20件」ボタンを探して、次ページへ遷移する
    try:
        next_page = driver.find_element(By.CLASS_NAME, 'c-pagination__arrow.c-pagination__arrow--next')
        next_page.click()
    except Exception:
        break  # 「次の20件」ボタンがなければwhileループを抜ける
   
# セッションを終了する
driver.quit()

※サイトセッション時と、次ページに遷移する際はサイトに負荷をかけないようにしましょう。sleepやWebDriverWaitなどで待機処理を実行し、読み込みが完了してから次の処理をするよう実装してください。

スクレイピングが完了したので、取得できたデータを見てみます。

全部で507店舗の情報を取得できたようです。
実際に表示された検索結果ページではもう少し数が多かったのですが、一部情報が欠損している店舗もあり、そういったものは無視して次に行くよう処理しているので少し数が減っています。

今回は割愛しますが、取得したままのデータだとグラフを作成したり今後の処理で扱いづらいので、扱いたい内容に合わせてデータを整形します。
行ったことは、今回使わない指標の削除、数値のデータ型変換、budget(予算帯)から夜予算帯の抜き出しくらいです。

穴場居酒屋探し

今回のテーマは穴場居酒屋ということで、取れたデータからまずは穴場の基準を考えます。
matplotlibとseabornというライブラリで取得したデータを可視化してみました。

評価と口コミの分布はこんな感じでした。
ほとんどのお店が口コミ数200件未満のようです。ざっくりですが、口コミ数は一旦100件未満を基準に探していきます。新宿のお店で口コミ数100件未満は少ない方なのでは?という肌感覚に基づいた割と適当な設定です。

評価の方は、ざっくり肌感覚だと3.5以上だと優良店というイメージを持っていましたが、以下を見ると星3.3以上から上位20%をに入っているようなので、3,3以上を目安に見ていきましょう。

あまり高いところだと手が出せないので、予算はとりあえず3000~6000くらいで見ておきます。

下記の条件が、今回探し求める穴場居酒屋ということにして、当てはまるお店を一覧で見てみます。

 評価:3.3以上
 口コミ件数:100件未満
 予算帯:¥3,000~¥5,999

ここまで絞ることができれば、あとは予算や他の人の希望などを考慮してサクッと決められそうです。
比較的マイナーなお店だと考えると、知る人ぞ知る的なセンスの良いお店選びになっているのでは?

まとめ

seleniumを使ってスクレイピングでグルメサイトから穴場居酒屋を探してみました。
手動で1つずつ探していくのは面倒だと思ったので、ある程度希望に近いお店を一覧で見てから1つずつ見ていく方が性に合っていそうです。
今回は簡単な方法で取れる範囲のデータを抽出しましたが、実際の口コミなんかも抽出して分析してみるとより面白い発見ができそうなので、次のステップとしては口コミ収集を目指したいですね。



ここまでお読みいただき、ありがとうございました!
この記事が少しでも参考になりましたら「スキ」を押していただけると幸いです!

株式会社分析屋について

弊社が作成を行いました分析レポートを、鎌倉市観光協会様HPに掲載いただきました。

ホームページはこちら。

noteでの会社紹介記事はこちら。

【データ分析で日本を豊かに】
分析屋はシステム分野・ライフサイエンス分野・マーケティング分野の知見を生かし、多種多様な分野の企業様のデータ分析のご支援をさせていただいております。 「あなたの問題解決をする」をモットーに、お客様の抱える課題にあわせた解析・分析手法を用いて、問題解決へのお手伝いをいたします!

【マーケティング】
マーケティング戦略上の目的に向けて、各種のデータ統合及び加工ならびにPDCAサイクル運用全般を支援や高度なデータ分析技術により複雑な課題解決に向けての分析サービスを提供いたします。

【システム】
アプリケーション開発やデータベース構築、WEBサイト構築、運用保守業務などお客様の問題やご要望に沿ってご支援いたします。

【ライフサイエンス】
機械学習や各種アルゴリズムなどの解析アルゴリズム開発サービスを提供いたします。過去には医療系のバイタルデータを扱った解析が主でしたが、今後はそれらで培った経験・技術を工業など他の分野の企業様の問題解決にも役立てていく方針です。

【SES】
SESサービスも行っております。