スクレイピング2　スクレイピングのやり方

[Aidemy](https://aidemy.net/)　2020/9/30
#はじめに
　こんにちは、んがょぺです！バリバリの文系ですが、AIの可能性に興味を持ったのがきっかけで、AI特化型スクール「Aidemy」に通い、勉強しています。ここで得られた知識を皆さんと共有したいと思い、Qiitaでまとめています。以前のまとめ記事も多くの方に読んでいただけてとても嬉しいです。ありがとうございます！
　今回は、スクレイピングの2つめの投稿になります。どうぞよろしくお願いします。

＊本記事は「Aidemy」での学習内容を「自分の言葉で」まとめたものになります。表現の間違いや勘違いを含む可能性があります。ご了承ください。

今回学ぶこと
・スクレイピングの方法（前準備であるクローリングはスクレイピング1を参照）
・複数ページをスクレイピングする

#スクレイピングする
##スクレイピングの方法
・（復習）スクレイピングとは、Webページを取得し、そこから必要なデータを抜き出すことである。
・スクレイピングの方法は「正規表現（reモジュール）」を使う、または「サードパーティ製のライブラリを使う」の2種類があるが、今回はメジャーな方法である__「サードパーティ製のライブラリを使う」__方法でスクレイピングを行う。

##HTML、XMLについて
・XMLはHTMLと同じWebページを直接構築する__マークアップ言語__である。HTMLよりも拡張性に優れる。
・HTML,XMLでは、**\<title><\title>**のような感じで囲まれたテキストがあり、このうち全体を__要素__と言い、< title>のことを__タグ__と言う。
・また\<html lang="ja">のような表記もあり、これは__lang属性がjaである__、すなわち、言語は日本語であると言う意味である。
・今回スクレイピングで使う「BeautifulSoup」ライブラリでは、この要素名からタイトルなどを取得する。

##BeautifulSoupでスクレイピング（解析準備）
・__BeautifulSoup(デコードしたWebページ,"パーサー")__メソッドを使うことで、簡単にスクレイピングできる。
・__パーサー__とは、文字列の解析（パース）を行うプログラムのことであり、特徴別に何種類かあり、そこから一つを指定する。例として、追加のライブラリが必要ない「html.parser」、高速に処理ができる「lxml」、XMLに対応する「xml」などがある。

```python
#クローリングするrequestsとスクレイピングするBeautifulSoupをインポート
from bs4 import BeautifulSoup
import requests
#urlの取得
url=requests.get("https://www.google.co.jp")
#スクレイピング（デコードはrequestモジュールのurl.textで行う、パーサーは"xml"に指定）
soup=BeautifulSoup(url.text,"xml")
```

##BeautifulSoupでスクレイピング（必要なデータを抜き出す）
・前項で行ったパースをしたデータからは、必要なデータを抜き出すことができる。方法は以下の二種類である。
・パース済みデータを変数soupに入れたとすると__soup.find("タグ名or属性名")__でそのタグか属性を持つ要素を最初の一つだけ抜き出す。またfindの部分を__find_all__とすれば指定した要素を全てリスト化して抜き出す。
・また、クラス属性からスクレイピングしたい時は、引数に__class_="クラス属性名"__を加える。

・パース済みデータを変数soupに入れたとすると__soup.selected_one("CSSセレクタ")__で、これを満たす要素を最初の一つだけ抜き出す。またselected_oneの部分を__select__とすれば指定した要素を全てリスト化して抜き出す。
・__CSSセレクタとは、要素をCSSの表現で示す方法である。__これを使えば、要素の中の要素を指定することもできる（ex)body要素の中のh1要素は"body > h1"）。

・また、裏技ではあるが、Chromeの開発者ツールで要素やCSSセレクタをコピーできる。そのため、わざわざデコードしたデータを出力することなく、視覚的にわかりやすく欲しいデータを抜き出せる。

```python
Google_title = soup.find("title") #<title>Google</title>
Google_h1 = soup.select("body > h1") #[] (body要素のh1要素がないので空リストが出力)
```

・上記のままだとGoogle_titleはtitleタグがついたまま出力されてしまうが、__text__を使うことで、このうちのテキストのみを取得できる。

```python
print(Google_title.text) #Google
```

##複数ページをスクレイピングする
・ここまでの方法だと1ページずつしかスクレイピングできない。複数ページをスクレイピングしたい時は、トップページなどにある__他ページへのリンクから他ページのURLを取得__し、繰り返し処理で全てのURLに対してスクレイピングを行えば良い。
・他ページのURLは__トップページのURL ＋ <a>要素のhref属性(各ページのリンク)__で取得できる。

```python
top="http://scraping.aidemy.net"
r=requests.get(top)
soup=BeautifulSoup(r.text,"lxml")
url_lists=[]
#他ページのURLをリンクから取得
#（方法は、まずaタグを全て取得し、そのそれぞれについてgetを使ってhref属性を文字コード化し、topURLとつなげることでURLとする）
urls = soup.find_all("a")
for url in urls:
    url = top + url.get("href")
    url_lists.append(url)
```

・他ページのURLが取得できたら、実際にスクレイピングする。先述の通り、繰り返し処理で全てのURLに対してスクレイピングを行えば良い。
・以下では、前項で取得した全ページから写真のタイトル(h3タグに記載されている)をスクレイピングして全て取得し、リストとして表示する。

```python
photo_lists=[]
#前項で取得したページをエンコードしてから写真のタイトルをBeautifulSoupでスクレイピング
for url in url_lists:
    r2=requests.get(url)
    soup=BeautifulSoup(r2.text,"lxml")
    photos=soup.find_all("h3")
#スクレイピングして取得した写真のタイトルを、h3タグを抜いてリストに追加
    for photo in photos:
        photo_text=photo.text
        photo_lists.append(photo_text)

print(photo_lists) #['Minim incididunt pariatur', 'Voluptate',...(略)]
```

#まとめ
・クローリングしたページをスクレイピングするときは、まず__BeautifulSoup__メソッドでパースする。
・パースしたデータからは任意のデータを抜き出せる。抜き出すには__find()__あるいは__selected_one()__を使う。
・抜き出したデータに__text__をつけると、タグなどが省略され、要素のみ抽出できる。
・複数のページをまとめてスクレイピングする時は、__トップページなどからリンクを抜き取り、ベースのURLとつなげることでクローリングできる__ので、それを個別にスクレイピングする。

今回は以上です。ここまで読んでくださりありがとうございました。