【Python初心者向け】はじめてのウェブスクレイピング実践

# 本投稿の概要・前提

## 読んで欲しい方
- Pythonはある程度触ったことがあるが、スクレイピングはしたことがない方
- 「スクレイピングとやらをしてみたいが何からすればわからない…」という方
- とりあえず、サクッとスクレイピングを試してみたい方
- データサイエンス分野に興味のある方


## そもそもスクレイピングとは？

Webスクレイピングは、**ウェブサイトから情報を自動で取得するテクニック**です。
プログラム（スクリプト）を使ってウェブページにアクセスし、必要なデータを抽出・保存します。人がウェブブラウザを使って情報を手動で検索・コピーするのとは異なり、Webスクレイピングはこのプロセスを自動化し、大量のデータをすばやく収集できます。

ウェブスクレイピングは、特にデータサイエンティストとして新たなデータを取得したい時などにとても有効です。有用なデータはウェブ上に分散しており、手動で集めるには時間がかかります。そこでウェブスクレイピングの技術を使えば、関連する情報を自動で収集し、分析のためのデータベースを素早く構築できます。

「ウェブスクレイピングとは」を詳しく知りたい方は、以下の方の記事をご覧ください。
とてもわかりやすいです。

https://qiita.com/tarantula426/items/7018815f85721a564b67#:~:text=Web%E3%82%B9%E3%82%AF%E3%83%AC%E3%82%A4%E3%83%94%E3%83%B3%E3%82%B0%E3%81%AF%E3%80%81%E3%82%A6%E3%82%A7%E3%83%96%E3%82%B5%E3%82%A4%E3%83%88,%E3%82%92%E6%8A%BD%E5%87%BA%E3%83%BB%E4%BF%9D%E5%AD%98%E3%81%97%E3%81%BE%E3%81%99%E3%80%82


## 対象のサイト

スクレイピングの対象はこちらのサイトです。

http://quotes.toscrape.com/

海外の方が作成したウェブスクレイピング練習のためのサイトのようです。

このサイトの利用規約を確認しても、ウェブスクレイピングに対して制限が設けられていません。むしろ、スクレイピングの学習と練習のために設計されているようです。

ウェブスクレイピングを実行する際は、そのサイトがウェブスクレイピングを許可しているかの確認が必須です。許可されていないサイトを勝手にスクレイピングすることは違法です。気をつけましょう。

# ウェブスクレイピングを行うPythonコード

## ウェブスクレイピング全体の流れ

1. 必要なライブラリのインストール
1. スクレイピングするページの指定
1. 該当ページの必要な情報を取得
1. csvファイルに保存

## 1.必要なライブラリのインストール

```ruby:
# ライブラリインストール
import requests
from bs4 import BeautifulSoup
import csv
```
requests: ウェブページのHTMLを取得するためのライブラリ
beautifulsoup4: 取得したHTMLを解析するためのライブラリ

この2つがウェブスクレイピングには頻出のライブラリです。
他にも便利なライブラリはいくつかあるようですが、後々調べましょう。

## 2.スクレイピングするページの指定

```ruby:
# ウェブページのHTMLを取得
url ='http://quotes.toscrape.com/'
response = requests.get(url)
soup = BeautifulSoup(response.text, 'html.parser')
```
ウェブページを指定したのち、Request,BeautifulSoupを使ってHTMLを解析します。

## 3.該当ページの必要な情報を取得

```ruby:
# 引用と著者を取得
quotes = soup.find_all('div', class_='quote')
```
今回は、サイト先の「引用文」とその「著者」を抽出します。
（後ほどの応用編で記しますが、この場合スクレイピングできるのは1ページ目のみです）

## 4.csvファイルに保存



```ruby:
# CSVファイルにデータを書き込む
# 'w'で「書き込みモード」を指定
# newline=''は、行末に余分な空行を入れないようにするため
with open('/content/quotes.csv', 'w', newline='') as file:
    writer = csv.writer(file)
    # 最初の行に「Quote」「Author」のヘッダーを書き込み
    writer.writerow(['Quote', 'Author'])
    for quote in quotes:
        text = quote.find('span', class_='text').get_text()
        author = quote.find('small', class_='author').get_text()
        writer.writerow([text, author])

print("Quotes have been written to quotes1.csv")
```

spanタグでクラスが'text'の要素を探してそのテキスト（引用文）を取得し、text変数に保存します。また、smallタグでクラスが'author'の要素から著者名を取得し、author変数に保存します。
最後のprintは必須ではありませんが、csvファイルに保存できたことをわかりやすくするため追記しました。


## 保存結果

Google Colabで作成されたCSVファイルは、Colabのファイルシステムに保存されます。
Google Colabの左側にあるサイドバーを開くと、作成したquotes.csvファイルが表示されているはずです。ファイルをダウンロードして中身を見てみましょう。



![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3780099/8ce40e60-4d89-f527-f9be-12f9143080d9.png)

上手くCSV形式で保存できていますね。
以上でウェブスクレイピングは終了です。
いかがでしょうか？これだけだと意外と簡単ですね。


# 応用編

上記ではスクレイピングしやすいサイトを扱い、たった2つのデータをCSVにしただけですので簡単にできました。しかい現実では、そんな上手いことばかりいきません。
いくつか応用方法はありますが、冒頭で紹介した下記のQiita投稿は応用編まで解説がありますので、まずはこちらを確認すると良いでしょう。

https://qiita.com/tarantula426/items/7018815f85721a564b67#beautifulsoup%E3%81%AB%E3%82%88%E3%82%8Bhtml%E8%A7%A3%E6%9E%90


また上記で書いたスクレイピングも、実は該当サイトの１ページ分しかスクレイピングできておりません。これはちょっとまずいので、複数ページをスクレイピングするやり方は以下に応用編として記載しておきます。

3点追記・修正しております。

- エラーハンドリング＝複数ページの取得：requests.exceptions.RequestExceptionをキャッチして、ネットワークエラーやHTTPエラーが発生した場合にログを出力し、whileループを終了
- ログ出力：loggingモジュールを使用して、各ページをスクレイピングしている際の進行状況やエラーを記録。これにより、どのページで問題が発生したかを簡単に特定可能に。
- Google Colabでのファイル保存場所：ファイルを/content/ディレクトリに保存することで、Google Colabのファイルブラウザから簡単にアクセス可能に。

```ruby:
import requests
from bs4 import BeautifulSoup
import csv
import logging

# ログの設定
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')

# URLのベース部分
base_url = 'http://quotes.toscrape.com/page/'

# 初期ページ番号
page = 1

# CSVファイルの作成
with open('/content/quotes.csv', 'w', newline='') as file:
    writer = csv.writer(file)
    writer.writerow(['Quote', 'Author'])
    
    while True:
        try:
            # 現在のページのURLを作成
            url = base_url + str(page) + '/'
            logging.info(f'Scraping page {page}: {url}')
            
            response = requests.get(url)
            response.raise_for_status()  # エラーハンドリングのためステータスコードを確認
            
            soup = BeautifulSoup(response.text, 'html.parser')
            
            # クオートのリストを取得
            quotes = soup.find_all('div', class_='quote')
            
            # クオートがなければループを終了
            if not quotes:
                logging.info('No more quotes found, ending scraping.')
                break
            
            # 各クオートの情報を取得してCSVに書き込み
            for quote in quotes:
                text = quote.find('span', class_='text').get_text()
                author = quote.find('small', class_='author').get_text()
                writer.writerow([text, author])
            
            # 次のページへ進む
            page += 1

        except requests.exceptions.RequestException as e:
            logging.error(f'Error occurred while scraping page {page}: {e}')
            break

logging.info('Scraping complete. Quotes have been saved to /content/quotes.csv')

```

出力結果（画面外は省略）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3780099/a95cca29-beaf-1285-57e5-2040b707307f.png)

これでページすべてのデータをCSV形式で保存できます。