「Python2年生 スクレイピングのしくみ」、職業倫理とクローリング・スクレイピング

「Python2年生 スクレイピングのしくみ」という本で標準ライブラリーのrequest・BeautifulSoupを使ったWEBスクレイピングについて学習してます。今回はクローリング・スクレイピング時の倫理・法務上の注意点、request・BeautifulSoupライブラリーを使ったクローリングとスクレイピングについて紹介します。

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-ebook/dp/B07W2ZNG8Z#:~:text=%E6%A9%9F%E6%A2%B0%E5%AD%A6%E7%BF%92%E3%82%84%E3%83%87%E3%83%BC%E3%82%BF%E5%88%86%E6%9E%90%E3%81%AB%E3%81%AA%E3%81%8F%E3%81%A6%E3%81%AF%E3%81%AA%E3%82%89%E3%81%AA%E3%81%84%E3%80%8C%E3%83%87%E3%83%BC%E3%82%BF%E3%80%8D%E3%80%82%20%E3%81%93%E3%81%AE%E3%82%88%E3%81%86%E3%81%AA%E3%83%87%E3%83%BC%E3%82%BF%E3%81%AF%E3%80%81%E3%82%A4%E3%83%B3%E3%82%BF%E3%83%BC%E3%83%8D%E3%83%83%E3%83%88%E4%B8%8A%E3%81%AB%E8%86%A8%E5%A4%A7%E3%81%AB%E3%81%82%E3%82%8A%E3%81%BE%E3%81%99%E3%81%8C%E3%80%81Python%E3%82%92%E4%BD%BF%E3%81%88%E3%81%B0%E5%8A%B9%E7%8E%87%E3%82%88%E3%81%8F%E3%83%87%E3%83%BC%E3%82%BF%E5%8F%8E%E9%9B%86%E3%81%A7%E3%81%8D%E3%81%BE%E3%81%99%E3%80%82%20%E3%81%93%E3%81%86%E3%81%97%E3%81%9F%E6%89%8B%E6%B3%95%E3%82%92%E3%80%8C%E3%82%B9%E3%82%AF%E3%83%AC%E3%82%A4%E3%83%94%E3%83%B3%E3%82%B0%E3%80%8D%E3%81%A8%E3%81%84%E3%81%84%E3%81%BE%E3%81%99%E3%80%82,%E6%9C%AC%E6%9B%B8%E3%81%AFPython%E3%82%92%E4%B8%80%E9%80%9A%E3%82%8A%E3%81%BE%E3%81%AA%E3%82%93%E3%81%A0%E6%96%B9%E3%81%AB%E5%90%91%E3%81%91%E3%81%A6%E3%80%81%E7%B0%A1%E5%8D%98%E3%81%AA%E3%82%B5%E3%83%B3%E3%83%97%E3%83%AB%E3%82%92%E4%BD%9C%E3%82%8A%E3%81%AA%E3%81%8C%E3%82%89%E3%80%81%E4%BC%9A%E8%A9%B1%E5%BD%A2%E5%BC%8F%E3%81%A7%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%E3%82%92%E3%81%BE%E3%81%AA%E3%81%B6%E6%9B%B8%E7%B1%8D%E3%81%A7%E3%81%99%E3%80%82%20%E5%AF%BE%E8%B1%A1%E8%AA%AD%E8%80%85%E3%81%AFPython%E3%81%AE%E5%9F%BA%E6%9C%AC%E6%96%87%E6%B3%95%E3%81%AF%E7%9F%A5%E3%81%A3%E3%81%A6%E3%81%84%E3%82%8B%E6%96%B9%20%28%E3%80%8EPython1%E5%B9%B4%E7%94%9F%E3%80%8F%E3%82%92%E8%AA%AD%E3%81%BF%E7%B5%82%E3%81%88%E3%81%9F%E6%96%B9%29%E3%80%81%E3%83%87%E3%83%BC%E3%82%BF%E5%8F%8E%E9%9B%86%E3%82%84%E3%83%87%E3%83%BC%E3%82%BF%E5%88%86%E6%9E%90%E3%81%AE%E5%88%9D%E5%BF%83%E8%80%85%E3%80%82

# WEBスクレイピング = ネット上の情報を自動で収集する方法
ネット上には様々な情報が公開されていて、Pythonを用いたWEBアプリケーションを使うとこうした情報を高速かつ自動で収集することができます。**「データを集めること」自体をクローリング**、**「収集したデータを解析して必要なデータに加工すること」をスクレイピング**と呼びます。

## クローリング・スクレイピング時の倫理・法務上の注意点
クローリング・スクレイピングを利用したプロジェクトでは原著者の意思に反してスクレイピング・収集したデータの機械学習が行われたとして著作権・知的財産権をめぐる訴訟が提起されるなどの問題も発生しています。著名な例としては、アーティスト3名がStability AI・Midjourney・DeviantArt等の生成AIを利用しているサイトに対して提起した民事訴訟があります。

https://www.techno-edge.net/article/2023/01/18/724.html

市民として他者の権利を尊重する・法律を守る以外にも、スクレイピング時は以下の職業倫理を守ることが必要です。

>１、著作権・知的財産権、個人情報保護法を順守する
２、スクレイピングによる業務妨害（アクセス過多など）をしない
３、クローリング・スクレイピング禁止のサイトにはスクレイピングをしない

スクレイピング禁止のサイトには多くの場合ルートディレクトリにrobots.txtというファイル、もしくはHTMLのメタタグにスクレイピング禁止の意思表示が表明されています。

```
User-agent: *
Disallow: /
```

```
<meta name="robots" content="nofollow">
```
## SSL証明書の発行
Pythonでスクレイピングするには、ネットワーク通信に利用するSSL証明書を発行する必要があります。 SSL証明書の作成に関してはこちらを参考にさせていただきました。

https://self-development.info/%e3%80%90python%e3%80%91ssl%e8%a8%bc%e6%98%8e%e6%9b%b8%e3%81%ae%e6%a4%9c%e8%a8%bc%e3%81%ab%e5%bf%85%e8%a6%81%e3%81%aacertifi%e3%81%ae%e3%82%a4%e3%83%b3%e3%82%b9%e3%83%88%e3%83%bc%e3%83%ab/

## 環境構築
必要なライブラリであるcertifi、requests、BeautifulSoupをpipコマンドで環境下にインストールします。


```
pip install certifi
pip install requests
pip install beautifulsoup4
```

# requestライブラリーを使ったクローリング
https://www.ymori.com/books/python2nen/test1.html からHTMLファイルを読み込むプログラムはこのように記述します。
```
import requests

url = "https://www.ymori.com/books/python2nen/test1.html"
response = requests.get(url)

response.encoding = response.apparent_encoding
print(response.text)
```

# BeautifulSoupを使ったスクレイピング
サイト内の要素を一括で取得する、画像を一括DＬするなどデータ収集の手段としてスクレイピングを用いるプログラムの作成を目指します。まずはBeautifulSoupをpipコマンドでインストールします。

```
#BSをインストール
pip install beautifulsoup4
```
WEBページを取得して解析します。soupというインスタンスにデータが格納されるようにしています。
```
import requests
from bs4 import BeautifulSoup

#WEBページを取得して解析する。soupというインスタンスにデータが格納される
load_url = "https://www.ymori.com/books/python2nen/test1.html"
html = requests.get(load_url)
soup = BeautifulSoup(html.content, "html.parser")

#HTML全体を表示する
print(soup)
```

```
<!DOCTYPE html>

<html>
<head>
<meta charset="utf-8"/>
<title>Python2年生</title>
</head>
<body>
<h2>第1章 Pythonでデータをダウンロード</h2>
<ol>
<li>スクレイピングってなに？</li>
<li>Pythonをインストールしてみよう</li>
<li>requestsでアクセスしてみよう</li>
</ol>
</body>
</html>
```
要素をid・classで抽出できるようにします。`soup.findメソッド`を使うとこのようにBeautifulSoupのインスタンスから必要なデータを引っ張り出すことができます。

```
#WEBページを取得
load_url = "https://www.ymori.com/books/python2nen/test2.html"
html = requests.get(load_url)
soup = BeautifulSoup(html.content, "html.parser")

#IDで要素を検索し表示する
chap2 = soup.find(id = "chap2")
print(chap2)
```

```
<div id="chap2">
<h2>第2章 HTMLを解析しよう</h2>
<ol>
<li>HTMLを解析してみよう</li>
<li>ニュースの最新記事一覧を取得してみよう</li>
<li>リンク一覧をファイルに書き出そう</li>
<li>画像を一括ダウンロードしよう</li>
</ol>
</div>
```

```
#抽出した要素から、さらにすべてのliタグを表示する
for element in chap2.find_all("li"):
    print(element)
```

```
<li>HTMLを解析してみよう</li>
<li>ニュースの最新記事一覧を取得してみよう</li>
<li>リンク一覧をファイルに書き出そう</li>
<li>画像を一括ダウンロードしよう</li>
```

# 画像ファイルのスクレイピング
img要素をすべて取得し、imgタグの絶対URLで画像データを取得・保存することで画像データのスクレイピングを行うことができます。これはresquestとBeautifulSoupのメソッドを組み合わせることで実装できます。
```
import requests
import urllib
import time

from bs4 import BeautifulSoup
from pathlib import Path

#画像保存用のフォルダーを作る
out_folder = Path("download")
out_folder.mkdir(exist_ok = True)

#WEBページを取得して解析
load_url = "https://www.ymori.com/books/python2nen/test2.html"
html = requests.get(load_url)
soup = BeautifulSoup(html.content, "html.parser")

#img要素をすべて取得
for element in soup.find_all("img"):
    src = element.get("src")
    
    #絶対URLで画像データを取得
    image_url = urllib.parse.urljoin(load_url, src)
    imgdata = requests.get(image_url)
    
    #保存フォルダ名を取得する
    filename = image_url.split("/")[-1]
    out_path = out_folder.joinpath(filename)
    
    #画像データをファイルに書き出す
    with open(out_path, mode="wb") as f:
        f.write(imgdata.content)
        
    #連続アクセスを避ける
    time.sleep(1)
```