はじめに
こんにちは、TechCommitの友季子です(^^) この記事では、PythonとSeleniumを使用して、Webスクレイピングを行い、取得したデータを処理する方法をステップバイステップで超初心者向けに解説します!
1.クローラー開発のサンプル
今回は、GoogleビジネスプロフィールのData抽出を例にあげて説明します。電話番号を基点にしたデータ取得を行います。
import timeimport reimport randomimport pandas as pdfrom selenium import webdriverfrom selenium.webdriver.common.by import Byfrom selenium.webdriver.chrome.service import Servicefrom selenium.webdriver.common.keys import Keysfrom webdriver_manager.chrome import ChromeDriverManagerfrom bs4 import BeautifulSoup# 入力ファイルと出力ファイルのパスを定義しますinput_file = "C:\\Users\\USER\\Desktop\\PhoneNumberList.csv"output_file = "C:\\Users\\USER\\Desktop\\matuosantestgbp0706.csv"# CSVファイルから電話番号を読み取る関数を定義しますdef read_csv(file_path): df = pd.read_csv(file_path) phone_numbers = df['phone_number'].dropna().tolist() print(f"{len(phone_numbers)}件の電話番号の読み込みができたにゃ(=^・^=)!") return phone_numbers# Google検索からビジネス情報を取得する関数を定義しますdef fetch_business_info(driver, phone_number): driver.get("https://www.google.co.jp/") time.sleep(random.uniform(0.005, 0.006)) # ランダムな待機時間 search_box = driver.find_element(By.NAME, 'q') # 検索ボックスを取得 search_box.click() time.sleep(random.uniform(0.008, 0.004)) # ランダムな待機時間 search_box.send_keys(phone_number) time.sleep(random.uniform(0.01, 0.018)) # ランダムな待機時間 search_box.send_keys(Keys.ENTER) time.sleep(random.uniform(1, 2)) # ランダムな待機時間 business_info = {} try: # Nameの取得のために複数の方法を試します business_info['Name'] = driver.find_element(By.XPATH, '//*[@id="Sva75c"]/div[2]/div[2]/div/div[2]/c-wiz/div/c-wiz[1]/c-wiz/c-wiz/c-wiz[1]/div/div/div[2]/div[1]/div/div/h3').text except Exception as e: print(f"Name not found via XPath method 1 for {phone_number}: {e}") try: business_info['Name'] = driver.find_element(By.XPATH, '/html/body/div[8]/div/div/div/div/div/div/c-wiz/div/div[2]/div[2]/div/div[2]/c-wiz/div/c-wiz[1]/c-wiz/c-wiz/c-wiz[1]/div/div/div[2]/div[1]/div/div/h3').text except Exception as e: print(f"Name not found via XPath method 2 for {phone_number}: {e}") try: business_info['Name'] = driver.find_element(By.CSS_SELECTOR, 'h3').text except Exception as e: print(f"Name not found for {phone_number}: {e}") business_info['Name'] = '' try: business_info['Rating'] = driver.find_element(By.CSS_SELECTOR, 'span.Aq14fc').text except Exception as e: print(f"Rating not found for {phone_number}: {e}") business_info['Rating'] = '' try: business_info['Reviews Count'] = driver.find_element(By.CSS_SELECTOR, '.hqzQac span span').text except Exception as e: print(f"Reviews Count not found for {phone_number}: {e}") business_info['Reviews Count'] = '' try: business_info['Address'] = driver.find_element(By.CSS_SELECTOR, 'span.LrzXr').text except Exception as e: print(f"Address not found for {phone_number}: {e}") business_info['Address'] = '' try: business_info['Phone'] = driver.find_element(By.CSS_SELECTOR, 'span.LrzXr.zdqRlf.kno-fv').text except Exception as e: print(f"Phone not found for {phone_number}: {e}") business_info['Phone'] = '' try: # BeautifulSoupでページを解析 soup = BeautifulSoup(driver.page_source, 'html.parser') hours_table = soup.find('table', {'class': 'WgFkxc'}) # 営業時間の表を見つける hours = "\n".join([row.text for row in hours_table.find_all('tr')]) # 営業時間を取得 business_info['Hours'] = hours except Exception as e: print(f"Hours not found for {phone_number}: {e}") business_info['Hours'] = '' try: business_info['Website'] = driver.find_element(By.CSS_SELECTOR, 'a.ab_button').get_attribute('href') except Exception as e: print(f"Website not found for {phone_number}: {e}") business_info['Website'] = '' # 予算情報を取得する処理 try: # 検索結果のHTMLを解析するためにBeautifulSoupを使用 soup = BeautifulSoup(driver.page_source, 'html.parser') # 予算情報を含む可能性のある要素を見つける budget_element = soup.find('span', text=re.compile(r'¥\d+~¥\d+')) business_info['Budget'] = budget_element.text if budget_element else '' except Exception as e: print(f"Budget not found for {phone_number}: {e}") business_info['Budget'] = '' # 業種情報を取得する処理 try: business_info['Category'] = driver.find_element(By.CSS_SELECTOR, 'span.YhemCb').text except Exception as e: print(f"Category not found for {phone_number}: {e}") business_info['Category'] = '' # 正確な業種情報を抽出 try: category_info = driver.find_element(By.XPATH, '//*[@id="yDmH0d"]/c-wiz[3]/div/div/div[2]/div/div[1]/div[3]/div[1]/span[3]/span[3]').text business_info['Category'] = category_info except Exception as e: print(f"Category (XPath specific) not found for {phone_number}: {e}") # Categoryに予算と業種を連結 if business_info['Budget'] and business_info['Category']: business_info['Category'] = f"{business_info['Category']} ({business_info['Budget']})" elif business_info['Budget']: business_info['Category'] = business_info['Budget'] # 業種をさらに判定する処理を追加 categories = ["ファーストフード", "花屋", "居酒屋", "整体", "パン屋", "ラーメン", "焼肉", "コーヒーショップ", "ハンバーガー", "カフェ", "理容", "美容","小売り","フラワーショップ"] detected_category = None try: category_elements = driver.find_elements(By.CSS_SELECTOR, 'div.yuRUbf a h3') for element in category_elements: for category in categories: if category in element.text: detected_category = category break if detected_category: break except: pass # 見つかった業種を追加 if detected_category: business_info['Category'] = detected_category return business_info# 住所から郵便番号と都道府県を削除する関数を定義しますdef remove_post_code_and_prefecture(address): address = re.sub(r'〒?\d{3}-\d{4}', '', address).strip() # 都道府県のリスト prefectures = [ "北海道", "青森県", "岩手県", "宮城県", "秋田県", "山形県", "福島県", "茨城県", "栃木県", "群馬県", "埼玉県", "千葉県", "東京都", "神奈川県", "新潟県", "富山県", "石川県", "福井県", "山梨県", "長野県", "岐阜県", "静岡県", "愛知県", "三重県", "滋賀県", "京都府", "大阪府", "兵庫県", "奈良県", "和歌山県", "鳥取県", "島根県", "岡山県", "広島県", "山口県", "徳島県", "香川県", "愛媛県", "高知県", "福岡県", "佐賀県", "長崎県", "熊本県", "大分県", "宮崎県", "鹿児島県", "沖縄県" ] # 都道府県の抽出 for prefecture in prefectures: if address.startswith(prefecture): return prefecture, address[len(prefecture):].strip() return "", address# CSVファイルにデータを書き込む関数を定義しますdef write_to_csv(output_path, headers, data): df = pd.DataFrame(data, columns=headers) df.to_csv(output_path, index=False, encoding='utf-8-sig')# メイン関数を定義しますdef main(): phone_numbers = read_csv(input_file) options = webdriver.ChromeOptions() driver = webdriver.Chrome(service=Service(ChromeDriverManager().install()), options=options) headers = ["Name", "Address", "Phone", "県", "Hours", "Website", "Category", "Rating", "Reviews Count"] extracted_data = [] for phone_number in phone_numbers: retries = 3 # 再試行回数を定義 business_info = {} for attempt in range(retries): business_info = fetch_business_info(driver, phone_number) if business_info.get("Name"): break # 名前が取得できた場合、ループを抜ける print(f"Retry {attempt + 1} for {phone_number}") time.sleep(random.uniform(2, 5)) # 再試行前にランダムな待機時間 address = business_info.get("Address", "") prefecture, address = remove_post_code_and_prefecture(address) # 住所から郵便番号と都道府県を削除 extracted_data.append([ business_info.get("Name", ""), address, business_info.get("Phone", ""), prefecture, # 県情報を追加 business_info.get("Hours", ""), business_info.get("Website", ""), business_info.get("Category", ""), business_info.get("Rating", ""), business_info.get("Reviews Count", "") ]) write_to_csv(output_file, headers, extracted_data) driver.quit()# メイン関数を実行if __name__ == "__main__": main()print("CSVファイルに抽出結果が出力されたにゃー(=^・^=)。") #Googleビジネスプロフィールのクローラー _8/13_植竹さんが欲しい仕様にヘッダーと電話番号ハイフンなし以外実現、早い※遅いときとデータ欠損件数同じくらい
2.スクレイピングのサンプル
※GoogleビジネスプロフィールのData抽出を例にあげて説明します。
import timefrom selenium import webdriverfrom selenium.webdriver.common.by import Byfrom selenium.webdriver.chrome.service import Servicefrom webdriver_manager.chrome import ChromeDriverManager# セレニウムの設定options = webdriver.ChromeOptions()options.add_argument("--headless") # ヘッドレスモードで実行します。driver = webdriver.Chrome(service=Service(ChromeDriverManager().install()), options=options)# Google検索結果のURL※無くてもOKurl = "https://www.google.com/search?q=%E3%83%9E%E3%82%AF%E3%83%89%E3%83%8A%E3%83%AB%E3%83%89+%E8%95%A8%E6%9D%B1%E5%8F%A3%E5%BA%97&oq=%E3%83%9E%E3%82%AF%E3%83%89%E3%83%8A%E3%83%AB%E3%83%89+%E8%95%A8%E6%9D%B1%E5%8F%A3%E5%BA%97&gs_lcrp=EgZjaHJvbWUqCQgAEEUYOxiABDIJCAAQRRg7GIAEMgcIARAAGIAEMgcIAhAAGIAEMgoIAxAAGIAEGKIEMgoIBBAAGIAEGKIEMgoIBRAAGIAEGKIEMgoIBhAAGIAEGKIEMgYIBxBFGD3SAQc5MDBqMGo3qAIIsAIB&sourceid=chrome&ie=UTF-8#ip=1"# ページを開くdriver.get(urlxxx)# ページの読み込み待機 5秒待機time.sleep(5)# Google My Businessの情報を取得business_info = {}try:business_info['namexx'] = driver.find_element(By.CSS_SELECTOR, '#rhs > div.kp-wholepage-osrp > div > div > div > div:nth-child(2) > div > div > div.nwVKo > div.loJjTe > div').textexcept:passtry:business_info['rating'] = driver.find_element(By.CSS_SELECTOR, 'div.Aq14fc').textexcept:passtry:business_info['reviews_count'] = driver.find_element(By.CSS_SELECTOR, 'span.EymY4b').textexcept:passtry:business_info['address'] = driver.find_element(By.CSS_SELECTOR, 'span.LrzXr').textexcept:passtry:business_info['phone'] = driver.find_element(By.CSS_SELECTOR, 'span.LrzXr.zdqRlf.kno-fv').textexcept:passtry:business_info['hours'] = driver.find_element(By.CSS_SELECTOR, 'div.VkpGBb span.OYb90e').textexcept:passtry:business_info['website'] = driver.find_element(By.CSS_SELECTOR, 'a.ab_button').get_attribute('href')except:pass# Google My Business情報の表示print("Google My Business Infoの情報です♪:")info_list = []for key, value in business_info.items():if value:info_list.append(f"{key.capitalize()}: {value}")print("\n".join(info_list))# 検索結果の情報を取得results = driver.find_elements(By.CSS_SELECTOR, 'div.g')print("\nGoogle Search Results(^^♪:")seen_links = set()for result in results:try:title = result.find_element(By.CSS_SELECTOR, 'h3').textlink = result.find_element(By.CSS_SELECTOR, 'a').get_attribute('href')snippet = result.find_element(By.CSS_SELECTOR, 'div.IsZvec').text# 重複するリンクを避けるif link in seen_links:continueseen_links.add(link)# Snippetを分割formatted_snippet = snippet.replace(' Map ', '\nMap\n').replace('. ', '.\n').replace(' 平日', '\n平日')print(f"Title: {title}\nLink: {link}\nSnippet:\n{formatted_snippet}\n")except:continue# ブラウザを閉じる#大事driver.quit()
3. 環境構築と準備
まず、スクレイピングを行うために必要なツールとライブラリをインストールします。
VSCodeのインストール
VSCodeは、Python開発に非常に適したエディタです。全ての作業をPCで完結できるように、まずはVSCodeをインストールしましょう。
Pythonファイルの実行
Pythonファイルをターミナルから実行するには、次のコマンドを使用します。
bash
コードをコピーする
py スペース ファイル名.py
必要なライブラリ等のインストール
Pandasなどのライブラリは、Pythonでデータ処理を行う際に非常に便利です。次のコマンドを使用してインストールします。
py -m pip install pandas
4. ダウンロードしたファイルの配置と実行
次に、ダウンロードしたプログラムを正しいフォルダに配置し、実行します。
ファイルの配置
ダウンロードしたプログラムファイルは、デスクトップでは動作しないことがあるため、Pythonフォルダに移動しましょう。
ファイルの実行
ファイルを実行して問題が発生した場合、多くはファイルパスやChromeDriverのバージョンの問題です。特に、ChromeDriverのバージョンがブラウザと一致していることを確認してください。
5. コードの編集と修正
コードを自分の環境に合わせて編集しましょう。
サイトの決定
スクレイピングするサイトを決定し、そのURLをコードの28行目に貼り付けます。
ページ訪問の設定
51~80行目では、XPathを使用してページの特定要素を訪問するように設定します。XPathは、ブラウザの検証ツールを使って取得し、適切に配置します。
データの抜き取り
店名などのデータをXPathを使って抜き取ります。XPathが正しく設定されていることを確認し、必要に応じて調整します。
コードの構成
最後に、コード全体の構成を整え、効率的かつ読みやすくなるようにしましょう。特に、インデントやコメントを適切に配置して、後で見直しやすいようにします。
6. プログラムの実行とデバッグ
プログラムを実行し、必要に応じてデバッグを行います。
プログラムの実行
作成したコードを実行して、データが正しく取得できるか確認します。
問題解決
問題が発生した場合は、コードの各部分を再確認し、適切な修正を行います。多くの場合、XPathの設定やChromeDriverのバージョンが原因で問題が発生します。トラブルを解決すると達成感があります、トラブル解決にむけて色々トライしていきましょう!別記事でトラブルシューティングのTipsをまとめていますので、よかったらチェックしてくださいね!
スクレイピングでデータが取得できるようになったら、クローラー開発のステップにいきましょう~
まとめ
今回の記事では、PythonとSeleniumを使用してWebスクレイピングを行い、データを効率的に取得する方法について解説しました。スクレイピングする際は、対象サイトの利用規約を必ず確認し、適切に行ってくださいね。
参考リンク
あなたのお役に立てば嬉しいです!一緒に頑張りましょうー