はじめに
本記事では、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月現在)
クラス「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
列名の指定
- columns
-
df.index.name
インデックス列の名称指定 -
df.to_csv
DataFrameをcsvで出力
取得したデータをDataFrameに変換後、csvとして出力します。
終わりに
今回はじゃらんの口コミページを例にスクレイピングを行いました。
全データを取得する際はHTMLの構造が繰り返しになっている部分を見つけることが重要だと感じました。
今後は取得した口コミデータを使って分析を行う予定です。