Udemyにホームページをカンタンに変更できるElementorの講座を新しくリリースしました。

食べログをスクレイピングしてみた

こんにちは
島村竜一です。

おいしい料理を探す「食べログ」ってとっても便利ですよね。
でも便利ですけど毎回検索するのって結構面倒くさかったりしますよね。

今回は便利な「食べログ」をスクレイピングしてみました。

PythonとSeleniumを組み合わせるとこうなります

さっそくですけどプログラムはこのような形になります。

# -*- coding: utf-8 -*-

"""
食べログの飲食店データを取得する

"""
import time
import pandas as pd
import os
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.service import Service as ChromeService
from webdriver_manager.chrome import ChromeDriverManager
from selenium.common.exceptions import NoSuchElementException

SLEEP_TIME = 4
CSV_NAME = "output/tabelog.csv"


def get_next(driver):
    pagenation_element = driver.find_elements(By.CLASS_NAME, "c-pagination__item")[-1]
    pagenation_element.find_element(By.TAG_NAME, "a").click()


def get_pagenum(driver):
    count_elements = driver.find_elements(By.CLASS_NAME, "c-page-count__num")
    paging_num = int(count_elements[1].text)
    total_num = int(count_elements[2].text)
    return total_num // paging_num


def get_store_url(driver):
    store_elements = driver.find_elements(
        By.CSS_SELECTOR, ".list-rst__wrap.js-open-new-window"
    )
    store_elements = [i.find_element(By.TAG_NAME, "h3") for i in store_elements]
    store_elements = [i.find_element(By.TAG_NAME, "a") for i in store_elements]
    return [i.get_attribute("href") for i in store_elements]


def get_store_info(driver, url):
    map_url = url + "dtlmap/"
    driver.get(map_url)
    time.sleep(SLEEP_TIME)
    table_elements = driver.find_element(
        By.CSS_SELECTOR, ".c-table.c-table--form.rstinfo-table__table"
    )
    th_texts = [i.text for i in table_elements.find_elements(By.TAG_NAME, "th")]
    td_texts = [i.text for i in table_elements.find_elements(By.TAG_NAME, "td")]
    return {k: v for k, v in zip(th_texts, td_texts)}


def scrape_tabelog():
    driver = None
    try:
        # サービスオブジェクトを使用してChromeDriverを設定
        service = ChromeService(executable_path=ChromeDriverManager().install())
        driver = webdriver.Chrome(service=service)

        # もしもデータが存在しない場合URL 日によって変わる
        # base_url = "https://tabelog.com/tokyo/rstLst/?vs=1&sa=%E6%9D%B1%E4%BA%AC%E9%83%BD&sk=%25E5%2588%2580%25E5%2589%258A%25E9%25BA%25BA&lid=top_navi1&vac_net=&svd=20220822&svt=1900&svps=2&hfc=1&Cat=RC&LstCat=RC03&LstCatD=RC0304&LstCatSD=RC030402&cat_sk=%E5%88%80%E5%89%8A%E9%BA%BA"

        base_url = "https://tabelog.com/tokyo/rstLst/?vs=1&sa=%E6%9D%B1%E4%BA%AC%E9%83%BD&sk=%25E3%2582%25AB%25E3%2583%25AC%25E3%2583%25BC%25E3%2583%25A9%25E3%2582%25A4%25E3%2582%25B9&lid=hd_search1&vac_net=&svd=20240715&svt=1900&svps=2&hfc=1&sunday=&LstRange=&LstReserve=&ChkCard=&ChkCardType=&ChkRoom=&ChkSemiRoom=&ChkRoomType=&ChkCharter=&ChkCharterType=&LstSmoking=&ChkBunen=&ChkParking=&ChkVegKodawari=&ChkFishKodawari=&ChkHealthy=&ChkVegetarianMenu=&ChkSake=&ChkSakeKodawari=&ChkShochu=&ChkShochuKodawari=&ChkWine=&ChkWineKodawari=&ChkCocktail=&ChkCocktailKodawari=&ChkNomihoudai=&ChkOver180minNomihoudai=&ChkNomihoudaiOnly=&ChkTabehoudai=&ChkFineView=&ChkNightView=&ChkOceanView=&ChkHotel=&ChkKakurega=&ChkHouse=&ChkStylish=&ChkRelax=&ChkWideSeat=&ChkCoupleSeat=&ChkCounter=&ChkSofa=&ChkZashiki=&ChkHorikotatsu=&ChkTerrace=&ChkKaraoke=&ChkDarts=&ChkLive=&ChkSports=&ChkOver150minParty=&ChkCelebrate=&ChkBirthdayPrivilege=&ChkCarryOnDrink=&ChkSommelier=&ChkPet=&ChkTakeout=&ChkDelivery=&ChkHappyHour=&ChkPremiumCoupon=&ChkOnlineBooking=&freecall=&ChkNewOpen=&award_prize=&chk_hyakumeiten_genres=&ChkTpointGive=&ChkTpointUse=&ChkEnglishMenu=&ChkMorningMenu=&ChkAllergyLabeling=&ChkCalorieLabeling=&ChkSweetsTabehoudai=&ChkEMoneyPayment=&ChkKoutsuuIcPayment=&ChkRakutenEdyPayment=&ChkNanacoPayment=&ChkWaonPayment=&ChkIdPayment=&ChkQuicPayPayment=&ChkQrcodePayment=&ChkQrcodePaymentType=&ChkKids=&ChkBabies=&ChkPreschoolChild=&ChkElementarySchoolStudent=&ChkKidsMenu=&ChkBabycar=&ChkTachiNomi=&ChkProjector=&ChkPowerSupply=&ChkWheelchair=&ChkFreeWifi=&ChkPaidWifi=&ChkSeatOnly=&ChkCoordinatorReward=&LstCos=&LstCosT=&RdoCosTp=2&LstSitu=&LstRev=&ChkCoupon=&Cat=RC&LstCat=RC12&cat_sk=%E3%82%AB%E3%83%AC%E3%83%BC%E3%83%A9%E3%82%A4%E3%82%B9"

        driver.get(base_url)
        time.sleep(SLEEP_TIME)

        # 検索した結果データが存在しない場合のエラー処理
        try:
            error_element = driver.find_element(
                By.XPATH,
                "//*[contains(text(), 'ご指定の条件に該当するお店は見つかりませんでした。')]",
            )
            if error_element:
                raise Exception("ご指定の条件に該当するお店は見つかりませんでした。")
        except NoSuchElementException:
            pass

        page_num = get_pagenum(driver)
        # 出力するデータ件数
        page_num = 3

        store_urls = list()
        for i in range(page_num):
            urls = get_store_url(driver)
            # データの量を減らす
            urls = urls[:2]

            store_urls.extend(urls)
            get_next(driver)
            time.sleep(SLEEP_TIME)

        # データの量を減らす
        store_urls = store_urls[:2]

        results = list()
        for i_url in store_urls:
            store_info = get_store_info(driver, i_url)
            results.append(store_info)
    finally:
        if driver:
            driver.quit()

    print(results)

    # 出力ディレクトリが存在しない場合に作成
    os.makedirs(os.path.dirname(CSV_NAME), exist_ok=True)

    # データをCSVファイルとして保存
    df = pd.DataFrame(results)
    df.to_csv(CSV_NAME, index=False)
    print(f"Data saved to {CSV_NAME}")


if __name__ == "__main__":
    scrape_tabelog()

ちょっと長いプログラムなのでゲッっとなるかもしれませんね。

こちらに検索するホームページのデータが格納されています。

        base_url ="XXXXX"
        driver.get(base_url)

でも検索結果によってはデータが存在しないことがあります。

食べログの場合は
ご指定の条件に該当するお店は見つかりませんでした。
という風に画面に表示されます。

        # 検索した結果データが存在しない場合のエラー処理
        try:
            error_element = driver.find_element(
                By.XPATH,
                "//*[contains(text(), 'ご指定の条件に該当するお店は見つかりませんでした。')]",
            )
            if error_element:
                raise Exception("ご指定の条件に該当するお店は見つかりませんでした。")
        except NoSuchElementException:
            pass

その時は上記のプログラムで
ご指定の条件に該当するお店は見つかりませんでした。
の検知をおこなうことができます。

driver.find_element(By.XPATH,"//*[contains(text(), '言葉')]",)

上記の言葉の文章を置き換えるとさまざまなプログラムで使うことができます。
データをうまく取れない時など検知する時にぜひ使ってみてくださいね。

まとめ:ホームページをスクレイピングする時にはきちんとエラー処理もしておきましょう

ホームページからデータを検索して持ってくるときに検索結果が取得できないことももちろん存在します。

キチンとそのあたりも考えて設計、実装をしていきましょう。

ここまで読んでくださってありがとうございます。

Python開発、AI開発に興味のある会社様、ぜひメルマガに登録してみてくださいね。

お役に立つ情報やセミナー情報などをお届けます。

ではまた次のブログでお逢いしましょう。