Python 初学者が楽天APIを使って買い物リスト作成アプリを作った（データ収集編:3）

**この記事は以下の続きです**

https://qiita.com/yuuauuy1/items/c7b544eda29f90ee12e5

今回は、こちらの表のURLを使って各レシピの材料と量を取得していきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2983287/8a8552e1-dce6-d661-b891-36066cbec841.png)

作りたい表はこちら（どのようなデータ型にしたいか考えるの大切！）
二つの表のindexは対応しています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2983287/6ac2fc6f-90f6-d55f-035f-407b24631297.png)

**買い物リスト作成アプリの概要はこちら**

https://qiita.com/yuuauuy1/items/5bb4a53ab15bde354297

**★このページは以下項目で構成されています★**

| 項番 | ページ内リンク |
|:----:|:-------------|
| 1 | [準備](#準備) |
| 2 | [Excel操作](#excel操作) |
| 3 | [楽天レシピサイトから材料と量を見つける](#楽天レシピサイトから材料と量を見つける) |
| 4 | [Excelに書き込む](#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などでこちらをインポート
```python:Python
from selenium import webdriver
from webdriver_manager.chrome import ChromeDriverManager
```
こちらでブラウザ起動が自動でできます。
```python:Python
new_driver = ChromeDriverManager().install()
service = ChromeService(executable_path=new_driver)
browser = webdriver.Chrome(service=service, options=options)
```
**参考文献はこちら**

https://qiita.com/Brutus/items/1998249c0a38c334be8e

## selenium インストール
これをコマンドプロンプトなどで入力。
```
pip install selenium==4.4.3
```
そして、VScodeなどでこちらをインポート。
今回は大量のサイトに自動アクセスするのでサーバーに負荷をかけないように「time」モジュールもインポートします。
ついでにExcelも使うので 「openpyxl」インポート。
```python:Python
from selenium import webdriver
import time
import openpyxl
from selenium.webdriver.common.by import By #find_elementsメソッドを使うために用意
```
これで準備が整いました。次は、Excelを操作していきます。

# Excel操作
まず、データを入れるExcelファイルを用意しておきます。
ファイルのA列に index、B列に材料、C列に量のデータを入れたいので、それぞれ１行目に名前を入れておきます。
```python:Python
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にアクセスして・・・情報を取って・・・としていると時間がかかるので、時短のためにリストを作っておきます。

```python:Python
#材料と量を取りたい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が行ごとにセットになって、２重配列となります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2983287/b9a6b788-db0c-677b-1f97-eda039622423.png)

# 楽天レシピサイトから材料と量を見つける

先ほどのidとURLのリストのはじめから順番にアクセスしていきます。
```python:Python
#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)  #サーバーに負担をかけないように３秒待つ
```
さて、楽天レシピのページに自動でアクセスできるようになりました。

ここから欲しい情報は、材料と量の情報です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2983287/2de39e6e-4699-70d6-d497-b02ee2e11931.png)
楽天レシピサイトでは、このように１列に材料と量が格納されており、複数の列で構成されています。

seleniumを使っての要素の検索方法は複数あります。
idやclassなどタグの属性を検索したり、XPathというHTMLの要素を特定する記法も使えます。
一つの要素だけ検索するのであれば`find_elementメソッド`、複数の要素であれば`find_elementsメソッド`を使います。

今回は、複数の要素が必要なのでfind_elementsを使います。

レシピページで要素の検証を行うと、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2983287/50dc9f02-5a2b-f2ee-909c-09793f51c9fa.png)
材料と量の列は「recipe_material_item」というclassネームで構成されていることが分かります。
```python:Python
#材料と量を見つける
recipe_materials = browser.find_elements(By.CLASS_NAME, "recipe_material__item")
```
こちらで１列分の情報が取れます。
これだけでは
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2983287/d059cd20-4dca-5d4b-09ea-88480413fe39.png)
このようにわけがわからないので、.text を付けると
```python:Python
print(recipe_material.text)
```
結果
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2983287/d8d60681-86f1-98c6-0b59-0d257cce2a21.png)
このように材料と量が、改行されて取得できます。
さらに改行で分割すると
```python:Python
recipe_material = recipe_material.text.splitlines() #改行コード[\nで材料と量が分割されているのでsplitlinesで分割
print(recipe_material)
```
このように材料と量のリストで返されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2983287/7bfe4553-ba58-5534-2025-14d74bc95c2d.png)

# Excelに書き込む
取得した情報をどうやってExcelに書き込むかというところですが、
`appendメソッド`でリストをExcelに書き込めるようなので、
[index, 材料, 量]　の形を作って１行ずつExcelに書き込んでいくことにします。

さらに、楽天レシピは材料記載はありますが、量の記載がないことがあるので、if文で量が無い時は「none」と入力することにしました。
```python:Python
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した方が時間短縮できたのでそうしています
```
これで
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2983287/d25e5dfd-87db-cd25-f155-e5853f85ea1e.png)
この表ができるわけですが、材料列に★や☆など記号が含まれたりしているので、次でデータ加工していきます。

# コード全文
```python:Python
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()
```

次回からデータ加工編に行きます！

https://qiita.com/yuuauuy1/items/3448c41c0b684db76edb