1
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Pythonでじゃらんの口コミをスクレイピングする

Last updated at Posted at 2023-06-30

はじめに

本記事では、Pythonを使ったスクレイピングの例として、じゃらんの箱根湯本温泉の口コミをスクレイピングし、csvで出力します。

環境

python 3.10.4
Windows 11 Home
ChromeDriver 114.0.5735.110

必要なライブラリのインストール

seleniumとpandasを使用します。
seleniumはブラウザの操作を自動化するライブラリですが、スクレイピングも行うことができます。今回は「次へ」ボタンの押下も自動化し、全ページの口コミ取得を目的とするため、こちらを使用します。
pandasはデータ解析に使うライブラリです。今回はスクレイピングして取得したデータをcsvで出力する目的で使用します。

pip install selenium
pip install pandas

実装

作成したコードは以下になります。

from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.by import By
from selenium.common.exceptions import NoSuchElementException
import pandas as pd
import time

# ブラウザ起動
chromedriver = 'chromedriver.exe'
service = Service(executable_path=chromedriver)
driver = webdriver.Chrome(service=service)
url = "https://www.jalan.net/yad385995/kuchikomi/?contHideFlg=1&maxPrice=999999&rootCd=7701" \
      "&roomCrack=000000&screenId=UWW3701&idx=0&smlCd=141602&dateUndecided=1&minPrice=0" \
      "&yadNo=385995&callbackHistFlg=1&distCd=01"
driver.get(url)

# データを取得し、2次元配列に格納する
table = []
isContinue = True
while(isContinue):
  parentElems = driver.find_elements(By.CLASS_NAME, "jlnpc-kuchikomiCassette__rightArea")
  for parent_i in parentElems:
    # 評価値
    room = parent_i.find_elements(By.TAG_NAME,"dd")[0].text
    bath = parent_i.find_elements(By.TAG_NAME,"dd")[1].text
    breakfast = parent_i.find_elements(By.TAG_NAME,"dd")[2].text
    dinner = parent_i.find_elements(By.TAG_NAME,"dd")[3].text
    customerService = parent_i.find_elements(By.TAG_NAME,"dd")[4].text
    clean = parent_i.find_elements(By.TAG_NAME,"dd")[5].text
    # 表題
    head = parent_i.find_element(By.CLASS_NAME, 'jlnpc-kuchikomiCassette__lead').text
    # 改行を削除した口コミ本文
    body = parent_i.find_element(By.CLASS_NAME, 'jlnpc-kuchikomiCassette__postBody').text.replace("\n","")

    # 配列にデータを格納
    rowData = []
    rowData.append(room)
    rowData.append(bath)
    rowData.append(breakfast)
    rowData.append(dinner)
    rowData.append(customerService)
    rowData.append(clean)
    rowData.append(head)
    rowData.append(body)
    table.append(rowData)

  # 次へボタンがあったらボタンを押す、無ければフラグを変更してループを終了する
  try:
    driver.find_element(By.CSS_SELECTOR, "a.next")
    nextButton = driver.find_element(By.CSS_SELECTOR, "a.next")
    nextButton.click()
    time.sleep(2)
  except NoSuchElementException:
    isContinue = False

# 配列からDataFrameを作成し、csvで出力する
df = pd.DataFrame(table, columns=['部屋','風呂','料理(朝食)','料理(夕食)',
                                   '接客・サービス','清潔感','見出し','本文'])
df.index.name = 'index'
df.to_csv("ホテル南風荘_口コミデータ.csv", encoding="utf-8")

#ブラウザの終了
driver.quit()

解説

HTMLの構造

じゃらんの口コミページのHTMLは次のように構成されています。(2023年6月現在)
名称未設定ファイル.drawio (5).png

クラス「jlnpc-kuchikomiCassette__rightArea」、「next」をループの材料にして全データを取得していきます。

親要素の取得

  parentElems = driver.find_elements(By.CLASS_NAME, "jlnpc-kuchikomiCassette__rightArea")
  for parent_i in parentElems:
  • driver.find_elements(By.CLASS_NAME, "jlnpc-kuchikomiCassette__rightArea")
    クラスが「jlnpc-kuchikomiCassette__rightArea」である全要素を取得

parentElemsをループに組み込み、子要素を取得する処理を共通化します。

データの取得

    # 評価値
    room = parent_i.find_elements(By.TAG_NAME,"dd")[0].text
    bath = parent_i.find_elements(By.TAG_NAME,"dd")[1].text
    breakfast = parent_i.find_elements(By.TAG_NAME,"dd")[2].text
    dinner = parent_i.find_elements(By.TAG_NAME,"dd")[3].text
    customerService = parent_i.find_elements(By.TAG_NAME,"dd")[4].text
    clean = parent_i.find_elements(By.TAG_NAME,"dd")[5].text
    # 表題
    head = parent_i.find_element(By.CLASS_NAME, 'jlnpc-kuchikomiCassette__lead').text
    # 改行を削除した口コミ本文
    body = parent_i.find_element(By.CLASS_NAME, 'jlnpc-kuchikomiCassette__postBody').text.replace("\n","")
  • parent_i.find_elements(By.TAG_NAME,"dd")[x].text
    parent_i内のタグ「dd」である要素を全て取得し、x番目の文字を取得
  • parent_i.find_element(By.CLASS_NAME, 'jlnpc-kuchikomiCassette__lead').text
    parent_i内のクラス名「jlnpc-kuchikomiCassette__lead」である最初の要素を取得
  • replace("\n","")
    文字列に含まれる改行を削除

親要素から必要なデータを取得していきます。
parent_i.find_elements(By.TAG_NAME,"dd")[x].textはxに0から5を指定し、以下のデータを取得します。
[0].text:部屋の点数
[1].text:朝食の点数
[2].text:接客の点数
[3].text:風呂の点数
[4].text:夕食の点数
[5].text:清潔感の点数

またparent_i内にクラス「jlnpc-kuchikomiCassette__lead」は1つしか存在しないため、確実に表題のデータを取得できます。

「次へ」ボタンの押下

isContinue = True
while(isContinue):

############################
######上で解説した処理#######
############################

  try:
    driver.find_element(By.CSS_SELECTOR, "a.next")
    nextButton = driver.find_element(By.CSS_SELECTOR, "a.next")
    nextButton.click()
    time.sleep(2)
  except NoSuchElementException:
    isContinue = False
  • isContinue
    ループを続けるか判定する変数
  • driver.find_element(By.CSS_SELECTOR, "a.next")
    タグ「a」でクラス「next」を持つ最初の要素(次へボタン)を取得
  • time.sleep(2)
    2秒間待機
  • NoSuchElementException
    driver.find_elementで検索した要素が見つからない時に発生するエラー

次へボタンがあれば押下しデータをさらに取得、なければデータ取得処理を終了します。
2秒間待機を挟むのは、ページが読み込まれる前に要素の検索が実行され、エラーとなるのを防ぐためです。

csv出力

df = pd.DataFrame(table, columns=['部屋','風呂','料理(朝食)','料理(夕食)',
                                   '接客・サービス','清潔感','見出し','本文'])
df.index.name = 'index'
df.to_csv("ホテル南風荘_口コミデータ.csv", encoding="utf-8")
  • pd.DataFrame
    • columns
      列名の指定
  • df.index.name
    インデックス列の名称指定
  • df.to_csv
    DataFrameをcsvで出力

取得したデータをDataFrameに変換後、csvとして出力します。

終わりに

今回はじゃらんの口コミページを例にスクレイピングを行いました。
全データを取得する際はHTMLの構造が繰り返しになっている部分を見つけることが重要だと感じました。
今後は取得した口コミデータを使って分析を行う予定です。

1
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?