この記事は以下の続きです
今回は、こちらの表のURLを使って各レシピの材料と量を取得していきます。
作りたい表はこちら(どのようなデータ型にしたいか考えるの大切!)
二つの表のindexは対応しています。
買い物リスト作成アプリの概要はこちら
★このページは以下項目で構成されています★
項番 | ページ内リンク |
---|---|
1 | 準備 |
2 | Excel操作 |
3 | 楽天レシピサイトから材料と量を見つける |
4 | Excelに書き込む |
5 | コード全文 |
準備
今回のスクレイピングで使うSeleniumとは、ブラウザを自動的に操作するライブラリです。
requestsライブラリを利用して、WEBサイトからデータを自動的に取得することができます。
そのために、以下が必要です。
・webブラウザ (Google Chrome やFirefoxなど)
・WebDriver (ブラウザの操作を自動化する)
・selenium
WebDriver準備
Google Chromeを使っていましたので、ChromeDriverのインストールを行います。
注意点としては、Chromeのバージョンと合っているChromeDriverをインストールしないといけません。
私は、なぜかバージョンを合わせてインストールしたのに、プログラム動かしたときに動かなくて、動かせるようになるまで半日かかりました・・・。
最終的に、webdriver_managerというライブラリを使用し、ブラウザのバージョンアップを自動化することで解決しました。
まず、コマンドプロンプトなどでwebdriver_managerをインストールします。
pip3 install webdriver-manager
そして、VScodeなどでこちらをインポート
from selenium import webdriver
from webdriver_manager.chrome import ChromeDriverManager
こちらでブラウザ起動が自動でできます。
new_driver = ChromeDriverManager().install()
service = ChromeService(executable_path=new_driver)
browser = webdriver.Chrome(service=service, options=options)
参考文献はこちら
selenium インストール
これをコマンドプロンプトなどで入力。
pip install selenium==4.4.3
そして、VScodeなどでこちらをインポート。
今回は大量のサイトに自動アクセスするのでサーバーに負荷をかけないように「time」モジュールもインポートします。
ついでにExcelも使うので 「openpyxl」インポート。
from selenium import webdriver
import time
import openpyxl
from selenium.webdriver.common.by import By #find_elementsメソッドを使うために用意
これで準備が整いました。次は、Excelを操作していきます。
Excel操作
まず、データを入れるExcelファイルを用意しておきます。
ファイルのA列に index、B列に材料、C列に量のデータを入れたいので、それぞれ1行目に名前を入れておきます。
wb_new = openpyxl.Workbook() #真っ白なExcelファイル作成
ws_new = wb_new.active #シートを選択 active(今触っている)なシートを指定
ws_new.title = "材料データ" #シートにタイトルつける
ws_new['A1'].value = 'index'
ws_new['B1'].value = '材料'
ws_new['C1'].value = '量'
次は、URLが沢山載っているExcelファイルから、indexとURLのリストを作ります。
これは、毎回Excelを読み込んで・・・上から順番にURLにアクセスして・・・情報を取って・・・としていると時間がかかるので、時短のためにリストを作っておきます。
#材料と量を取りたいExcelを読み込む
file = "recipe_all"
wb_read = openpyxl.load_workbook(file + ".xlsx")
#先頭のシートを取得(先頭のインデックス番号は0)
ws_read = wb_read.worksheets[0] #先ほどの「Excelファイル.active」でも良い
#idとurlのリストを作る
id_url_lists=[]
for id_rows,url_rows in zip(ws_read.iter_rows(min_row=2, min_col=1, max_col=1), ws_read.iter_rows(min_row=2, min_col=3, max_col=3)):
id_url=[]
for id_row,url_row in zip(id_rows,url_rows):
id_url.append(id_row.value)#リストにセルのデータを追加
id_url.append(url_row.value)
id_url_lists.append(id_url)#さらにid_url_listに格納
実行するとこんな感じでidとURLが行ごとにセットになって、2重配列となります。
楽天レシピサイトから材料と量を見つける
先ほどのidとURLのリストのはじめから順番にアクセスしていきます。
#ver.を合わせたwebdriverをダウンロードしてChromeブラウザを開く
browser = webdriver.Chrome(ChromeDriverManager().install())
#urlリストから順番にアクセス
for id_url_list in id_url_lists:
browser.get(id_url_list[1]) #driver.get(URL)でそのURLにアクセスできます。
time.sleep(3) #サーバーに負担をかけないように3秒待つ
さて、楽天レシピのページに自動でアクセスできるようになりました。
ここから欲しい情報は、材料と量の情報です。
楽天レシピサイトでは、このように1列に材料と量が格納されており、複数の列で構成されています。
seleniumを使っての要素の検索方法は複数あります。
idやclassなどタグの属性を検索したり、XPathというHTMLの要素を特定する記法も使えます。
一つの要素だけ検索するのであればfind_elementメソッド
、複数の要素であればfind_elementsメソッド
を使います。
今回は、複数の要素が必要なのでfind_elementsを使います。
レシピページで要素の検証を行うと、
材料と量の列は「recipe_material_item」というclassネームで構成されていることが分かります。
#材料と量を見つける
recipe_materials = browser.find_elements(By.CLASS_NAME, "recipe_material__item")
こちらで1列分の情報が取れます。
これだけでは
このようにわけがわからないので、.text を付けると
print(recipe_material.text)
結果
このように材料と量が、改行されて取得できます。
さらに改行で分割すると
recipe_material = recipe_material.text.splitlines() #改行コード[\nで材料と量が分割されているのでsplitlinesで分割
print(recipe_material)
Excelに書き込む
取得した情報をどうやってExcelに書き込むかというところですが、
appendメソッド
でリストをExcelに書き込めるようなので、
[index, 材料, 量] の形を作って1行ずつExcelに書き込んでいくことにします。
さらに、楽天レシピは材料記載はありますが、量の記載がないことがあるので、if文で量が無い時は「none」と入力することにしました。
for recipe_material in recipe_materials:
recipe_material = recipe_material.text.splitlines() #改行コード[\nで材料と量が分割されているのでsplitlinesで分割
list=[]
list.append(id_url_list[0])#listにid入れる
if len(recipe_material) == 2 :
list.append(recipe_material[0]) #recipe_material[0]は材料
list.append(recipe_material[1]) #recipe_material[1]は量
else:
list.append(recipe_material[0])
list.append("none")
ws_new.append(list)
wb_new.save(file + "test.xlsx") #1行書き込んでsaveした方が時間短縮できたのでそうしています
これで
この表ができるわけですが、材料列に★や☆など記号が含まれたりしているので、次でデータ加工していきます。
コード全文
import openpyxl
from selenium import webdriver
from webdriver_manager.chrome import ChromeDriverManager
from selenium.webdriver.chrome.service import Service as ChromeService
import time
from selenium.webdriver.common.by import By
#from selenium.webdriver.common.keys import Keys
#材料と量を入れるexcelファイルをあらかじめ用意しておく
wb_new = openpyxl.Workbook()
ws_new = wb_new.active
ws_new.title = "材料データ"
ws_new['A1'].value = 'index'
ws_new['B1'].value = '材料'
ws_new['C1'].value = '量'
#材料と量を取りたいExcelを読み込む
file = "recipe_index"
wb_read = openpyxl.load_workbook(file + ".xlsx")
#先頭のシートを取得(先頭のインデックス番号は0)
ws_read = wb_read.worksheets[0]
#---------------------IDと一緒にURLリストをつくる。----------------------
id_url_lists=[]
for id_rows,url_rows in zip(ws_read.iter_rows(min_row=2, min_col=1, max_col=1), ws_read.iter_rows(min_row=2, min_col=3, max_col=3)):
id_url=[]
for id_row,url_row in zip(id_rows,url_rows):
id_url.append(id_row.value)#リストにセルのデータを追加
id_url.append(url_row.value)
id_url_lists.append(id_url)#さらにid_url_listに格納
print(id_url_lists)
#---------------------------------seleniumでスクレイピングしていく-----------------------
#ver.を合わせたchromeドライバーをダウンロードしてChromeブラウザを開く
new_driver = ChromeDriverManager().install()
service = ChromeService(executable_path=new_driver)
browser = webdriver.Chrome(service=service)
#urlリストから順番にアクセスして材料と量を取得
for id_url_list in id_url_lists:
browser.get(id_url_list[1])
time.sleep(3)
#材料名を見つける
recipe_materials = browser.find_elements(By.CLASS_NAME, "recipe_material__item")
#材料名をfor文で取得する
for recipe_material in recipe_materials:
recipe_material = recipe_material.text.splitlines() #改行コード[\nで材料と量が分割されているのでsplitlinesで分割
list=[]
list.append(id_url_list[0]) #listにid入れる
if len(recipe_material) == 2 :
list.append(recipe_material[0]) #recipe_material[0]は材料
list.append(recipe_material[1]) ##recipe_material[0]は量
else:
list.append(recipe_material[0])
list.append("none")
ws_new.append(list)
wb_new.save(file + "test.xlsx")
print(id_url_list)
browser.quit()
次回からデータ加工編に行きます!