はじめてのWebスクレイピング

# はじめに
[こちらの記事](https://qiita.com/mine820/items/b7fd46cd1b897eefef1e)でセブンイレブンの商品のカロリー情報を人力で収集したのですが、今後のメンテナンス（笑）を考えると楽したいので、スクレイピングのお勉強もかねてやってみました。

今回は、セブンイレブンの公式サイトから、[カロリーが載っているページ](https://www.sej.co.jp/i/products/anshin/)をスクレイピングしてみました。

今回もPythonで試してみます。

# 使用するモジュール
どうやら「BeautifulSoup」って奴がいいらしいので、そのまま鵜呑みにしてみました。
新しめの技術で、情報がいっぱいあるのがうれしいです。

# コーディング
まずはモジュールを宣言します。

```python
import requests
import pandas as pd
from bs4 import BeautifulSoup
```
取得した情報をDataFrameに登録するのでPandasも使います。

## ソースを眺めてみる
とりあえずここで、目的のページのHTMLの構造を確認してみます。

```python
# 取得したいURL
url = "https://www.sej.co.jp/i/products/anshin/?pagenum=0"

# urlを引数に指定して、HTTPリクエストを送信してHTMLを取得
response = requests.get(url)

# 文字コードを自動でエンコーディング
response.encoding = response.apparent_encoding

# 取得したHTMLを表示
print(response.text)
```

で、出てきたのがこちら。（一部分だけ）

```text
<div class="pagerCtrl">
	<div class="counter">54件中 1-15件表示	</div><div id="filter001" class="filter" ><form id="itemList001"><label class="filterOn" for="filterOn001">表示切替</label><input type="checkbox" id="filterOn001" name="filterOn001" /><div class="panel"><dl><dt>並べ替え</dt><dd><ul><li><a class="button" href="/i/products/anshin/?page=1&amp;sort=n&amp;limit=15">新商品</a></li></ul></dd></dl><dl><dt>表示件数</dt><dd><ul><li><a class="button" href="/i/products/anshin/?page=1&amp;sort=f&amp;limit=50">50件</a></li><li><a class="button" href="/i/products/anshin/?page=1&amp;sort=f&amp;limit=100">100件</a></li></ul></dd></dl></div></form></div><!--filter001--><div class="pager"><b>&nbsp;1&nbsp;</b>|&nbsp;<a href="/i/products/anshin/?pagenum=1&amp;page=1&amp;sort=f&amp;limit=15">2</a>&nbsp;|&nbsp;<a href="/i/products/anshin/?pagenum=2&amp;page=1&amp;sort=f&amp;limit=15">3</a>&nbsp;|&nbsp;<a href="/i/products/anshin/?pagenum=3&amp;page=1&amp;sort=f&amp;limit=15">4</a>&nbsp;&nbsp;<a href="/i/products/anshin/?pagenum=1&amp;page=1&amp;sort=f&amp;limit=15">［次へ］</a></div></div><!--pagerCtrl--><div class="itemArea">
<ul class="itemList"><li class="item">
  <div class="image"><a href="/i/item/KA0000475130.html?category=1085&amp;page=1"><img data-original="//sej.dga.jp/i/dispImage.php?id=92723" alt="商品画像" /></a></div>
  <div class="summary"><div class="itemName"><strong><a href="/i/item/KA0000475130.html?category=1085&amp;page=1">もち麦もっちり！梅ひじきおむすび</a></strong></div><ul class="itemPrice">
<li class="price">115円（税込124円）</li>
<li class="region"><em>販売地域</em>全国（北海道一部除く）</li>
</ul>
<ul class="attribute">
<li class="n1">158kcal　※地域によりカロリーが異なる場合があります。</li>
<li class="n3">047513</li>
</ul>
    <div class="text">もち麦を使ったおむすびです。昆布とかつお節から丁寧に取っただしで炊き込んだもち麦御飯に、ひじき煮を混ぜ込みました。ひじき、食感のよい梅チップ、香りのよい赤しその、素材のうま味が感じられる仕立てです。</div>    <div class="ipr"></div>
  </div>
</li><li class="item">
  <div class="image"><a href="/i/item/KA0000405570.html?category=1085&amp;page=1"><img data-original="//sej.dga.jp/i/dispImage.php?id=94071" alt="商品画像" /></a></div>
  <div class="summary"><div class="itemName"><strong><a href="/i/item/KA0000405570.html?category=1085&amp;page=1">五穀ごはんおむすび 塩こんぶツナ</a></strong></div><ul class="itemPrice">
<li class="price">115円（税込124円）</li>
<li class="region"><em>販売地域</em>北海道、東北、関東、東海、近畿、中国、四国、九州</li>
</ul>
<ul class="attribute">
<li class="n1">180kcal　※地域によりカロリーが異なる場合があります。</li>
<li class="n3">040557</li>
</ul>
    <div class="text">レタス1個分の食物繊維を摂ることができる、五穀ごはんのおむすびです。もち玄米、もち赤米、もち黒米、もちきびで、もちもちとした食感の五穀ごはんに仕上げました。中具には、黒胡椒でアクセントを加えたツナと、相性のよい塩こんぶを組み合わせました。</div>    <div class="ipr"></div>
  </div>
</li><li class="item">
  <div class="image"><a href="/i/item/KA0000475120.html?category=1085&amp;page=1"><img data-original="//sej.dga.jp/i/dispImage.php?id=92722" alt="商品画像" /></a></div>
  <div class="summary"><div class="itemName"><strong><a href="/i/item/KA0000475120.html?category=1085&amp;page=1">もち麦もっちり！塩こんぶ枝豆おむすび</a></strong></div><ul class="itemPrice">
<li class="price">115円（税込124円）</li>
<li class="region"><em>販売地域</em>全国</li>
</ul>
<ul class="attribute">
<li class="n1">160kcal　※地域によりカロリーが異なる場合があります。</li>
<li class="n3">047512</li>
</ul>
    <div class="text">もち麦を使ったおむすびです。昆布とかつお節から丁寧に取っただしを使い、風味のよいもち麦御飯に仕上げました。ミネラル豊富な塩昆布、彩りのよい枝豆、コク深い香りのごま油を混ぜ込んだ、食べ進みのよい仕立てです。</div>    <div class="ipr"></div>
  </div>
</li><li class="item">
  <div class="image"><a href="/i/item/KA0001018120.html?category=1085&amp;page=1"><img data-original="//sej.dga.jp/i/dispImage.php?id=94075" alt="商品画像" /></a></div>
  <div class="summary"><div class="itemName"><strong><a href="/i/item/KA0001018120.html?category=1085&amp;page=1">1／2日分の野菜！だし香る鶏団子鍋</a></strong></div><ul class="itemPrice">
<li class="price">400円（税込432円）</li>
<li class="region"><em>販売地域</em>北海道、東北、関東（埼玉一部除く）、甲信越、北陸、東海、岡山、広島一部、鳥取、島根一部、四国</li>
</ul>
<ul class="attribute">
<li class="n1">150kcal　※地域によりカロリーが異なる場合があります。</li>
<li class="n3">101812</li>
</ul>
    <div class="text">1日に必要な野菜の1/2を摂ることができる、鶏団子鍋です。だしと醤油のうま味が感じられるスープに仕立てました。</div>    <div class="ipr"></div>
  </div>
</li>
```

この中で今回取得したいのは、以下の4つの情報になります。

- 商品名（\<div class="itemName">～\</div>）
- 価格（\<li class="price">～\</li>）
- 販売地域（\<li class="region">～\</li>）
- カロリー（\<li class="n1">～\</li>）

なお、各商品は「\<li class="item">～\</li>」に囲まれています。

## 情報の取得
それぞれをこんな感じで取得します。

```python
# HTML解析
bs = BeautifulSoup(response.text, 'html.parser')
items = bs.find_all("li", attrs={"class", "item"})

for item in items:
  # 商品名
  itemName = item.find("div", attrs={"class", "itemName"})
  item_text = itemName.find("a")

  # 価格
  price = item.find("li", attrs={"class", "price"})
  price_index = price.contents[0].find("円")

  # 販売地域
  region = item.find("li", attrs={"class", "region"})

  # カロリー
  calory = item.find("li", attrs={"class", "n1"})
  calory_index = calory.contents[0].find("kcal")

  # 登録
  addRow = pd.Series([item_text.contents[0],
                     price.contents[0][:price_index],
                     region.contents[1],
                     calory.contents[0][:calory_index]],
                     index=df.columns)
  df = df.append(addRow, ignore_index=True)
```

「BeautifulSoup()」で、取得したHTMLをパースします。
で、タグや属性を指定して、その”ひとかたまり”を取り出します。
最初に見つかった一つだけを取り出す場合は「find()」、条件にあてはまるやつを全部取り出す場合は「find_all()」を使います。
”ひとかたまり”の中から表示している文字列は「contents」に設定されています。（複数設定されている場合あり）

価格は税抜の金額部分（最初の「円」の前）を取り出しています。
カロリーも数字（「kcal」の前）を取り出しています

取得した情報をDataFrameに登録してみましたが、いい感じに取得できているようです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/130771/991626b5-dc50-3e81-75dd-30f06f635f0c.png)

実は1ページだけでなく複数ページにまたがって表示されますので、そこもうまい具合にページ数を取得して、ぐりぐり回して取得しています。

```python
# 取得したいURL
url = "https://www.sej.co.jp/i/products/anshin/?pagenum=0"

# urlを引数に指定して、HTTPリクエストを送信してHTMLを取得
response = requests.get(url)

# 文字コードを自動でエンコーディング
response.encoding = response.apparent_encoding

# HTML解析
bs = BeautifulSoup(response.text, 'html.parser')
pager_tag = bs.find("div", attrs={"class", "pager"})
link_tags = pager_tag.find_all("a")

# 抽出したタグのテキスト部分を出力
num = 0
for link in link_tags:
  if (link.contents[0].isdigit()):
    num = int(link.contents[0])
```

# まとめ
少なくとも、HTMLの構造を確認して、必要な情報がどのタグのどの属性にあるのかを確認するのが大変ですね。
それさえ何とかなれば、あとは簡単だと思います。

また、他のページもこんな感じでスクレイピングすれば、より一層情報収集がはかどりそうです。