スクレイピングの基本を順を追って解説した。


　こちらの記事をご覧いただきありがとうございます。
　ネットに転がっている情報を使ってなんやかんやしたいな～と思うことはだれしもあると思います。ネットの情報を手作業で書き写すことはできますがすごーく面倒ですね。そんな時に、__パソコンにデータ収集を手伝ってもらう手法__ がスクレイピングです。pythonを使ったスクレイピングの手法を書きます。
　自分で後で見返すために作成しますが、ご覧いただいた皆様にも学びがあれば幸いです。また、まだ勉強して間もないので間違っていることを書いている可能性があります。ご指摘やご意見を頂けますと幸いです。

　※htmlについての解説は基本していませんので、htmlのタグなど調べながら見ていただくと内容がよくわかると思います。

## 参考

　私はこちらの本でスクレイピングの勉強を行いました。この本の中でも基本的なところだけでもスクレイピングできます。

https://www.amazon.co.jp/Python2%E5%B9%B4%E7%94%9F-%E3%82%B9%E3%82%AF%E3%83%AC%E3%82%A4%E3%83%94%E3%83%B3%E3%82%B0%E3%81%AE%E3%81%97%E3%81%8F%E3%81%BF-%E4%BD%93%E9%A8%93%E3%81%97%E3%81%A6%E3%82%8F%E3%81%8B%E3%82%8B%EF%BC%81%E4%BC%9A%E8%A9%B1%E3%81%A7%E3%81%BE%E3%81%AA%E3%81%B9%E3%82%8B%EF%BC%81-%E6%A3%AE-%E5%B7%A7%E5%B0%9A/dp/4798161918/ref=sr_1_1_sspa?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&crid=1LD97EOXAXA7V&keywords=%E3%82%B9%E3%82%AF%E3%83%AC%E3%82%A4%E3%83%94%E3%83%B3%E3%82%B0&qid=1664323015&qu=eyJxc2MiOiI1LjA3IiwicXNhIjoiNC4wNiIsInFzcCI6IjMuNjYifQ%3D%3D&s=books&sprefix=%E3%82%B9%E3%82%AF%E3%83%AC%E3%82%A4%E3%83%94%E3%83%B3%E3%82%B0%2Cstripbooks%2C199&sr=1-1-spons&psc=1&spLa=ZW5jcnlwdGVkUXVhbGlmaWVyPUFJRjJZNTlFRVJZNFcmZW5jcnlwdGVkSWQ9QTAzNTAzMjcyMzVCTVpFWUlGWUZJJmVuY3J5cHRlZEFkSWQ9QVJGQ1RJQ0lBN01VRyZ3aWRnZXROYW1lPXNwX2F0ZiZhY3Rpb249Y2xpY2tSZWRpcmVjdCZkb05vdExvZ0NsaWNrPXRydWU=


# スクレイピングとは？

　前置きにも書きましたが、__パソコンにデータ収集を手伝ってもらう手法__ の一つにスクレイピングがあります。イメージしやすいように具体例を用意します。

　私が練習でyahooを使ったので、具体例もyahooにします。↓のurlを使います。

https://www.yahoo.co.jp/

　yahooトップページの、ニュース記事一覧を取り出すことができます。

__赤枠のニュースの一覧を取り出したい__

<img width=500 alt='yahooの記事一覧.png' src='https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2774344/13cff82c-e46b-1bd6-4ab0-b1fe717c2651.png'>

__取り出した__

<img width=400 alt='スクレイピングニュース一覧.png' src='https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2774344/1902daba-d261-4810-536d-e31f383fbcef.png'>

　私は基本操作に慣れたので、これだけなら数分で出来ました。もっとたくさん情報を集めるならこれより長いコードを書く必要がありますが、それもこの後書く基本をうまく活用すれば実現できると思います。


# スクレイピングの注意

　スクレイピングの方法を書く前に、スクレイピングを実施するうえでの注意を紹介しておきます。

* スクレイピングしたデータは著作物です
　著作権の範囲内で利用しましょう。個人の範囲での利用ならおおよそ問題ないように思いますが、収集したデータを公開するなどは問題になります。
* サーバーに負荷がかからない配慮をしましょう
　アクセスが集中してサーバーがダウンした、なんてニュースはいくらかあると思いますが、スクレイピングのやり方によっては同じようにサーバーに大きな負荷がかかります。特に繰り返しスクレイピングする場合は気をつけましょう。今回記事に書く内容だけならあまり気にしなくてもよいのでこの記事に詳しく書きませんが、より発展的なスクレイピングをするなら対策が必要です。
* スクレイピングを禁止しているサイトがあります
　Amazonなど、スクレイピングを禁止しているサイトがあります。事前によく確認してからスクレイピングしましょう。

　詳しく書かれた記事を見つけましたので、載せておきます。ぜひご一読ください。

https://qiita.com/nezuq/items/c5e827e1827e7cb29011


# スクレイピングの手法

　ここからスクレイピングの手法を書きます。

## requests で html の情報をもらってくる

　requestsという、スクレイピングしやすいモジュールがあります。pipしましょう。

```python:requestsをインストール
pip install requests
```

　スクレイピングしたいサイトのurlを用意します。requestsを使って、そのurlのサイトを構成するhtmlの情報をもらってきます。もらってきた情報はそのままでは読めないので、エンコードします。
　↓でそれを実行できます。
※記事作成時点でのurlから変更された場合に実行できなくなります。その場合はurlの部分を取り換えれば動くはずです。

```python:
import requests
# urlのサイトの情報をもらってくる
url = 'https://www.yahoo.co.jp/'
html = requests.get(url)
# エンコードする
html.encoding = html.apparent_encoding
print(response.text)
```

__出力__
<img width=400 alt='requestsとencode.png' src='https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2774344/e689001f-e04b-41d2-0019-ce95311e7932.png'>

　何やら文字がたくさん出てきましたね。これがyahooのサイトを構成する情報の全てです。ここから必要な情報だけを取り出します。


## BeautifulSoup で必要な情報を取り出す

### BeautifulSoup で情報を取り出せるように変換する

　requests でサイトの情報をもらってきたら、__BeautifulSoup__ で必要な情報を取り出します。__BeautifulSoup__ はこれまたスクレイピングに便利なモジュールです。これもpipしましょう。
```python:BeautifulSoupをインストール
 pip install beautifulsoup4
```


　まずはBeautifulSoupで情報が取り出せる状態に変換します。

```python:BeautifulSoupが使えるように変換
import requests
from bs4 import BeautifulSoup
# urlのサイトの情報をもらってくる
url = 'https://www.yahoo.co.jp/'
html = requests.get(url)
# BeautifulSoupで使えるように変換
soup = BeautifulSoup(html.content, 'html.parser')

print(soup)
```

__出力__
<img width=400 alt='BeautifulSoupに変換.png' src='https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2774344/229d8ef6-53af-b52c-2f7f-e7bf6e71cd47.png'>

　さっきとだいたい同じ出力になりますが、これでOKです。

### findとfind_allで情報を取り出す

　先ほどの出力にはサイトの情報全部が入っているので、ここから必要な情報だけ取り出します。そのために`find`や`find_all`を使います。

　`find`や`find_all`は、htmlのタグを指定して、そのタグで囲まれた情報を取り出すことができます。とりあえずで、よく見出しに使う`<h1>`タグを取り出してみます。

```python:h1を取り出す
# urlのサイトの情報をもらってくる
url = 'https://www.yahoo.co.jp/'
html = requests.get(url)

# BeautifulSoupで使えるように変換
soup = BeautifulSoup(html.content, 'html.parser')

# h1タグを取り出す
h1 = soup.find('h1')

print(h1)
```
__出力__
<img width=400 alt='h1をfind.png' src='https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2774344/f408c9b4-a662-3ae4-c03f-aa49a447e5db.png'>


 `<h1>`で囲まれている情報を取り出すことができました。先ほどのコードの、`find('h1')`の部分で別のタグを指定することで、別の情報を取り出すことができます。

　このままだとタグがうるさいので、タグを消します。`.test`を付けるだけでタグを消すことができます。
```python:タグを消去
import requests
from bs4 import BeautifulSoup

# urlのサイトの情報をもらってくる
url = 'https://www.yahoo.co.jp/'
html = requests.get(url)

# BeautifulSoupで使えるように変換
soup = BeautifulSoup(html.content, 'html.parser')

# h1タグを取り出す
h1 = soup.find('h1')

# タグを消去して表示
print(h1.text)
```
__出力__
<img width=400 alt='タグを消去.png' src='https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2774344/26295dd1-50cc-c4c7-4698-006130a82166.png'>


　Yahoo!JAPANの文字列だけを取り出すことができました。


　find_allだと指定したタグを全て取り出すことができます。リストの状態で出力されます。
```python:h1を全て取り出す
# urlのサイトの情報をもらってくる
url = 'https://www.yahoo.co.jp/'
html = requests.get(url)

# BeautifulSoupで使えるように変換
soup = BeautifulSoup(html.content, 'html.parser')

# h1タグを全て取り出す
h1 = soup.find_all('h1')

# タグを消去して表示
print(h1)
```
__出力__
※長くなるのでコードの部分は切り落としました。
<img width=400 alt='h1をfind__all.png' src='https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2774344/f44bd536-308a-b20a-0e4d-c458e898dfb7.png'>

　あとはリストの使い方で1個だけ表示したり全部表示させたりできます。
```python:find_allのデータを表示
# urlのサイトの情報をもらってくる
url = 'https://www.yahoo.co.jp/'
html = requests.get(url)

# BeautifulSoupで使えるように変換
soup = BeautifulSoup(html.content, 'html.parser')

# h1タグを全て取り出す
h1 = soup.find_all('h1')

# 最初の1つを表示
print(h1[0].text)
print('\n')

# 全部表示
for element in h1:
    print(element.text)
```
__出力__
<img width=300 alt='h1全部.png' src='https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2774344/d4882b71-4e46-cd7b-43e6-c6e2978c2923.png'>

　`<h1>`に囲まれた文字列を全て取り出せました。

### idやclassを指定して欲しい情報を取り出す

　先ほどの取り出し方でもニュースの見出しっぽいものは取り出せているように見えますが、余計なものが入っていたり、そもそもタグを当て勘で指定して拾いに行くのも面倒ですね。必要な情報を確実に取り出すときに、idやclassの指定が役に立ちます。


##### 欲しい情報がどこにあるのか確認する

　欲しい情報に絞って取り出すときに、まずhtmlのどこに欲しい情報があるのかを確認しましょう。
　情報を取り出すサイトを開いて、デベロッパーツールを開きます。↓はchromeの例です。他のブラウザでも同じような操作になると思います(Edgeはだいたい同じでした)。
※ショートカットキーでctrl+shift+iでも開けます)

__右上点3つのボタン→その他のツール→デベロッパーツール__
<img width=500 alt='デベロッパーツール.png' src='https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2774344/5a8c8ca5-295f-29f3-cc72-dda988a4b492.png'>

　デベロッパーツールを地道にみてもいいですが時間がかかるので、欲しい情報がどこにあるのか教えてくれる機能を使います。

　デベロッパーツールの左上にある矢印のボタンを押します。その後、欲しい情報にカーソルを合わせてクリックします。すると、デベロッパーツールが欲しい情報のある場所を表示してくれます。

__左上の矢印ボタンをクリック__
<img width=500 alt='欲しい情報を探す１.png' src='https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2774344/9e964cc2-d035-7903-df88-51a735ffc46c.png'>

__欲しい情報がある場所をクリック__
<img width=500 alt='欲しい情報を探す２.png' src='https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2774344/aa783567-b61d-6fc4-b725-e2240eb8b4e1.png'>

__デベロッパーツールに欲しい情報がある場所が表示される__
<img width=500 alt='欲しい情報を探す３.png' src='https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2774344/19e1372e-6434-60e3-3bc8-5f2397287cba.png'>

　デベロッパーツールを見ると、`<div class=~ ></div>`の中に欲しい情報があるみたいですね。これを取り出します。`find(class_='~~')`と書くとclassを指定して取り出せます。


```python:classを指定して取り出す
# urlのサイトの情報をもらってくる
url = 'https://www.yahoo.co.jp/'
html = requests.get(url)

# BeautifulSoupで使えるように変換
soup = BeautifulSoup(html.content, 'html.parser')

# classを指定して取り出す
class_ = soup.find(class_='_1XAfHUWtx6tfYZuWDVjNxZ')

# 表示
print(class_.text)
```
__出力__
<img width=600 alt='classを指定.png' src='https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2774344/371f0755-6a18-17c9-af1f-5eb597d7c21a.png'>

　ニュースの見出しっぽい文字列が取り出せました。しかしこの状態だと文字列が繋がっていてるのと、余計な情報も入っているので、データとして扱いづらいです。見出しを1個づつ取り出します。
　ニュースの見出しのような、同じようなものが並んで表示されている場合にはだいたいそれぞれに同じclassが割り当てられているはずなので、そのclassを指定してfind_allでまとめて取り出します。
　デベロッパーツールで先ほどのニュース見出しが全て入っているところから、黒い三角のところをクリックすると中身を細かく表示することができます。これを繰り返すと、いかにも見出しが1個ずつ入っている場所があります。

__▶をクリックしてより細かく表示__
<img width=500 alt='見出しを1個づつ取り出したい.png' src='https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2774344/7b9e2c70-dcea-3f10-6ae7-a224e13ae110.png'>

__見出しが1個づつ入ってそうなところを表示__
<img width=500 alt='見出しを1つずつ取り出す.png' src='https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2774344/87505aa5-6ed2-ffa4-465b-eb3782f50993.png'>

　見出しが1個づつ入っていそうなところをよく見ると、classが同じ文字列だと気づくと思います。これを指定してfind_allすれば、見出しを1個づつ取り出せそうです。

```python:見出しを1個づつ取り出したい
# urlのサイトの情報をもらってくる
url = 'https://www.yahoo.co.jp/'
html = requests.get(url)

# BeautifulSoupで使えるように変換
soup = BeautifulSoup(html.content, 'html.parser')

# classを指定して取り出す
class_ = soup.find_all(class_='_2j0udhv5jERZtYzddeDwcv')

# 表示
for element in class_:
    print(element.text)
```
__1個づつ取り出せたが…？__
<img width=400 alt='取り出せましたか…？.png' src='https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2774344/5d13ff72-cd40-76eb-3a82-593e33523bf4.png'>

　見出しを1個づつ取り出せました。しかし、新着情報を表すnewが邪魔ですね…。`str.replace()`とかで取り除いてもいいのですが、newもない状態で取り出すことを考えます。
　たぶんニュースの見出しとnewで別々にclassの指定があると思うので、デベロッパーツールでもう少し詳しく表示します。

__細かいところまで表示__
<img width=500 alt='かなり細かく見る.png' src='https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2774344/a09b9d5c-4733-c023-bc78-b4c9638bc42e.png'>

　見出しの文字が入っているところまで細かく表示しました。最初から文字列が入っているclass指定すればよくね？と一瞬思いましたが、案外そうでもなかったりします。すぐにわかります。
　classを指定して取り出してみましょう。
```python:文字列が入っているclassを指定
# urlのサイトの情報をもらってくる
url = 'https://www.yahoo.co.jp/'
html = requests.get(url)

# BeautifulSoupで使えるように変換
soup = BeautifulSoup(html.content, 'html.parser')

# classを指定して取り出す
class_ = soup.find_all(class_='fQMqQTGJTbIMxjQwZA2zk _1alzSpTqJzvSVUWqpx82d4')

# 表示
for element in class_:
    print(element.text)
```

__また余計なものが…？__
<img width=350 alt='細かいclass指定.png' src='https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2774344/b42bd35a-26d8-8113-6f01-d1434db970cc.png'>

　newはなくなりましたが、「もっと見る」などの関係ない情報が出てきました。文字列を直接囲むタグのclassを指定すれば全部解決ってわけではなさそうです。
　情報を使う上ではいらない情報を捨てればよいのですが、ちょうどよいclass指定がどこにあるのかいろいろ試して探します。1つ上の`<h1>`にあるclass指定ならどうでしょうか？
※ほぼ同じコードなので省略します。

__きれいに取り出せました__
<img width=350 alt='h1のclassを指定.png' src='https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2774344/dd39e1d6-6114-5417-1263-a8c778f78f16.png'>

　余計なものがない状態で取り出せました。
※時間がたってyahooのニュースが入れ替わったようですね。やりたいことは出来ていますので、中身が違いますが気にしないでください。


### デベロッパーツールを使わずに必要な情報を探す

　デベロッパーツールがなくても指定するclassを探す手段があるので、それも書いておきます。
　いったんhtmlの情報が全部入っているものを表示させます。そのあと、取り出したい文字列を検索します。検索の仕方はデベロッパーツールを開くときと同じで、右上の点３つのボタンから検索が使えます。
※ショートカットキーでctrl+fでも使えます。

__取り出したい文字列を検索__
<img width=400 alt='デベロッパーなしで探す.png' src='https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2774344/43ffc78e-1a7c-1155-0b50-b4e6b1de7707.png'>

　検索した文字列はデベロッパーツールと同様にタグで囲まれているので、検索した文字列の少し前を見てclassの情報を探します。これで、デベロッパーツールでclassを探すときと同じような作業ができます。


# 終わり。

　ここまでに書いた手法で、ネット上の文字列データはだいたい収集することができるような気がします。画像やurlなどの情報は＋で専用のやり方が必要ですが簡単です。そこまで出来ればおおよそ欲しい情報は集められるのではないでしょうか。
　私はこの後不動産情報とかを収集して機械学習してみようと思っています。ていうかデータのスクレイピングは完了しました。それについての記事もいずれ書くかもしれません。