#author("2024-12-09T05:29:33+01:00","","") #author("2024-12-09T05:30:31+01:00","","") [[水上/技術資料]] ---- 目次 #contents ---- *プログラム[#z00fd092] 今回使うプログラムはこちら。zipファイルを解凍して、「1.食べログからレビューの取得」を実行 #ref(1食べログ取得.zip) *目標 [#z00fd092] 店の名前を入力すると店のレビューを食べログから取得する。 *環境 [#h82a02b0] Python 3.10.1 64bitでやってますが,たぶんどのバージョンもできるはず... &br; pythonインストールは[[こちら>https://www.python.org/]] * 処理の流れ[#h82a02b0] 1.プログラムを起動すると、店の名前を入力するテキストボックスがでる&br; 2.店の情報(店の名前やキーワード)を入力すると、プログラムが食べログでキーワード検索を行い、一番関連した店の情報を取得&br; 3.取得した店のレビューをスクレイピングし、レビューに加工を施し、csvファイルに保存する&br; *下準備 [#h82a02b0] **プログラム実行見必要なモジュール [#h82a02b0] プログラム実行に以下のモジュールが必要なので、インストール pip install requests pandas beautifulsoup4 selenium janome lxml **プログラムのファイル構成 [#h82a02b0] 使用するプログラムのほかに、「file」という名前のファイルを作成し、以下のように配置する。fileは、取得したレビューのcsvファイルが保存されるファイル。&br; (「1.食べログからレビューの取得」は今回使うプログラム)&br; #ref(dir.png,,367x100) * プログラムの解説[#h82a02b0] ***1. モジュールの解説 [#o9f1700e] import re import requests import pandas as pd from bs4 import BeautifulSoup from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.common.keys import Keys import time from janome.tokenizer import Tokenizer 各モジュールの役割 - `re`: 正規表現による文字列処理 - `requests`: HTTPリクエストの送信 - `pandas`: データフレームを使ったデータ操作 - `BeautifulSoup`: HTMLデータの解析 - `selenium`: 動的Webページのスクレイピング - `janome`: 日本語形態素解析 ***2. レビューの加工の関数と加工内容の解説[#hdabb39f] レビューをそのまま取得するだけでは感情分析の精度が悪くなるので、口コミを文節ごとに区切ったのち以下の処理を施す -名詞を含まない口コミは削除→意味のない文章は名詞を含まない傾向があるため、名詞を含まない文節は削除 -英語単語が50%以上の口コミは削除→英語の文章は分析精度が悪いため -長すぎる口コミは区切る(60文字を基準)→一文節が長すぎるレビューは途中で区切る -日本語が含まない口コミは削除→「(^^)」のような、記号だけで構成されている文節を削除 以下、処理の関数の解説 &br; - 名詞を含むかを判定する関数 (`contains_noun`)&br; 日本語テキストに名詞が含まれているかを確認する。 def contains_noun(text): tokens = tokenizer.tokenize(text) for token in tokens: if token.part_of_speech.startswith('名詞'): return True return False - 日本語文字を含むかを判定する関数 (`contains_japanese`)&br; ひらがな、カタカナ、漢字のいずれかが含まれているかを判定する。 def contains_japanese(text): if re.search(r'[ぁ-んァ-ン一-龯]', text): return True return False - 英語の割合を計算する関数 (`english_word_percentage`)&br; 英単語の割合が50%以上の場合、そのレビューをはじく。 def english_word_percentage(text): words = re.findall(r'\S+', text) if not words: return 0 english_words = re.findall(r'[a-zA-Z]+', text) return len(english_words) / len(words) - 長文をカットする関数 (`cut_text_at_noun`)&br; テキストが60文字を超える場合、次のレビューとして区切る def cut_text_at_noun(text, max_length=60): if len(text) <= max_length: return text # 60文字以内の場合、そのまま返す tokens = list(tokenizer.tokenize(text)) # リストに変換 current_length = 0 # 60文字を超える位置まで読み進める for i, token in enumerate(tokens): current_length += len(token.surface) if current_length > max_length: # 名詞が出現する位置でカット if token.part_of_speech.startswith('名詞'): return ''.join([t.surface for t in tokens[:i+1]]) return text # もし名詞が見つからなければ元のテキストを返す ***3. 食べログの店の名前とURLをスクレイピングする関数の解説 [#yf8e9799] 以下の関数は、キーワードを入力するとキーワードを食べログで検索する関数である 検索結果から店舗情報を取得 (`get_tabelog_top_result`) def get_tabelog_top_result(keyword): # WebDriverのセットアップ(Chromeを使用する例) options = webdriver.ChromeOptions() options.add_argument("--headless") # ヘッドレスモード(ブラウザを非表示にして実行) driver = webdriver.Chrome(options=options) try: # 食べログのトップページを開く driver.get("https://tabelog.com/") time.sleep(2) # ページが完全に読み込まれるのを待つ # 検索ボックスを探してキーワードを入力 search_box = driver.find_element(By.NAME, "sk") search_box.send_keys(keyword) search_box.send_keys(Keys.RETURN) # Enterキーを押す time.sleep(3) # 検索結果が表示されるのを待つ # 最初の店舗名とURLを取得 first_store = driver.find_element(By.CSS_SELECTOR, ".list-rst__rst-name a") store_name = first_store.text store_url = first_store.get_attribute("href") return store_name, store_url except Exception as e: print(f"エラーが発生しました: {e}") return None finally: # WebDriverを閉じる driver.quit() ***4. レビューの収集 [#b80a32c1] 3で取得したurlをもとに、店のレビューを取得する - スクレイピングのループ処理 for i in range(1, 2): ... title_links = soup.find_all('a', class_='rvw-item__title-target') 各レビュー本文を取得してリストに追加する。 ***5. データ加工と整形[#r5e24c1a] - レビューをデータフレームに変換 df = pd.DataFrame(review_data, columns=['StoreName', 'Review']) grouped_reviews = df.groupby('StoreName')['Review'].apply(list).reset_index() 店舗名ごとにレビューをリスト化する。 - 文節ごとにレビューを分割し、条件でフィルタリング - 文節ごとにレビューを分割し、2のレビュー加工関数を実行し、レビューの処理を行う for row in output_df.itertuples(index=False): ... sentences = [sentence for sentence in sentences if contains_noun(sentence) and contains_japanese(sentence) and english_word_percentage(sentence) < 0.5] ***6. 最終データの保存[#a0f1a473] 最後に、加工したレビューを以下のコードでcsvに保存する new_df.to_csv(csv_filename, index=False, encoding='cp932', errors='ignore', header=False) 整形されたレビューをCSV形式で保存します。 *カスタマイズ [#zbf80ab0] レビューの取得件数を変更したい場合、以下のコードを変更する for i in range(1, 2): # 何件スクレイピングするか(1~n-1ページまでスクレイピングする) 「(1, 2)」の2の部分を変更することによって取得するレビューの数が変わる。&br; この場合は食べログのレビューの1ページ目の20件を取得している&br; 食べログでは1ページに20件のレビューを表示しているので、数字を1増やすごとにレビューを20件分多く取得することができる&br; *参考文献 [#ddfa4bf2] ↓Python】食べログを例としたWebスクレイピングの基本形 &br; https://webscraper.blog/archives/207