Pythonでスクレイピングのルール(robots.txt)をチェックするツールを作る

# はじめに

スクレイピングを始めるにあたって、一番に気を付けるべきことは法律やルール（明示的なモノや暗黙的なモノも含む）を遵守することである。スクレイピングは、非常に便利であるがゆえにこのようなルールは割と蔑ろにされがち（**特に初心者**）であると思う。
今回はスクレイピングのルールに関しての記事ではないので、それらについては下記の記事を参考にされたい。

### 参考記事
* [Webスクレイピングの注意事項一覧 - Qiita](https://qiita.com/nezuq/items/c5e827e1827e7cb29011)

# robots.txtについて

ルールについては触れないとは言うものの、記事の題材でもある`robots.txt`については簡単に触れておく。
`robots.txt`とは、スクレイピングを行うプログラムに対しての指示が書いてある文書である。`robots.txt`は慣習的にはURLの直下に置かれるが、これは別に義務ではないので、そもそも配置されていないケースもある。例えば、Qiitaであれば[こちら](https://qiita.com/robots.txt)に配置されている。

```txt:Qiitaのrobots.txt
User-agent: *
Disallow: /*/edit$
Disallow: /api/*
Allow:    /api/*/docs$
```

上記のQiitaの`robots.txt`を参考にして軽く解説をするが、`User-Agent`というのは対象となるクローラーの種類を表す。`*`は全員に対する指示である。次に`Allow / Disallow`は、指定されたパスへのクロールの許可もしくは禁止を表す。上の例であれば、`https://qiita.com/api/*`はクロール禁止だが、`https://qiita.com/api/*/docs$`は許可されていることがわかる。また、サイトによっては`Crawl-delay`が設定されていることもあるが、設定されていない場合でも暗黙の了解として、次のリクエストまで**1秒間空ける**ことが望ましい。
もっと詳細に`robots.txt`についての仕様を知りたい方は、[こちら](https://docs.pyq.jp/column/crawler.html)を参照されるといい。

# プログラム作成

## Step 1. robots.txtの読み取り

pythonの標準ライブラリの`urllib`には、`robots.txt`を読み取るための`urllib.robotparser`が提供されている。今回はこれを利用して、プログラムを作成する。
`urllib.robotparser`については、[こちら](https://docs.python.org/ja/3/library/urllib.robotparser.html)を参照。

```python
import urllib.robotparser

# robots.txtの読み取り
robots_txt_url = 'https://qiita.com/robots.txt'
rp = urllib.robotparser.RobotFileParser()
rp.set_url(robots_txt_url)
rp.read()

# robots.txtの情報から調査したいURL、User-Agentでクロール可能かを調べる
user_agent = '*'
url = 'https://qiita.com/api/*'
result = rp.can_fetch(user_agent, url)
print(result)
```

```terminal:実行結果
False
```

上記のプログラムでは、まず`RobotFileParser`オブジェクトを作り、`set_url`関数で`robots.txt`のURLを指定、それを元に`read`で読み取りを行う。次に、調査したいUser-Agent、URLを`can_fetch`関数に与えることでアクセスが許可されているかどうかが真偽値で取得できる。上記のプログラムでは、先程確認した通り`https://qiita.com/api/*`へのクロールは許可されていないので、Falseが出力されている。

## Step 2. 正規表現を用いたrobots.txtのリンクの取得

プログラムの根幹となる部分は、ほとんどStep1で終了しているが、これではライブラリの機能を利用しただけで、プログラムとして有用なものではない。そこで正規表現を用いて、`robots.txt`のリンクを自動生成したいと思う。とは言っても、あまりイメージが湧かないと思うので、具体的な例を用いて説明する。
例えば、クロールが許可されているか調べたいURLが`https://qiita.com/api/*`であるとすると、このURLを元に`https://qiita.com/robots.txt`というリンクを生成するという事である。これは先程も述べた通り`robots.txt`は慣習的にサイトの直下に配置されているので、`https://qiita.com/api/*`から`https://qiita.com`の部分を抽出できれば、そこに`/robots.txt`の文字を足すだけでリンクを作成することができる。
pythonの正規表現reについては、[こちら](https://qiita.com/luohao0404/items/7135b2b96f9b0b196bf3)を参照されるといい。

```python
import re

# 正規表現によりサイトのURLを取得
def get_root_url(url):
    pattern = r'(?P<root>https?://.*?)\/.*'
    result = re.match(pattern, url)
    if result is not None:
        return result.group('root')

# サイトのURLからrobots.txtのURLを生成
def get_robots_txt_path(root_url):
    return root_url + '/robots.txt'

url = 'https://qiita.com/api/*'
root_url = get_root_url(url)
robots_txt_url = get_robots_txt_path(root_url)
print(f'ROOT URL -> {root_url}')
print(f'ROBOTS.TXT URL -> {robots_txt_url}')
```

```terminal:実行結果
ROOT URL -> https://qiita.com
ROBOTS.TXT URL -> https://qiita.com/robots.txt
```

## Step 3. 機能を追加してまとめる

Step1, Step2を元に`urllib.robotparser`の機能を用いて、Crawl-Delayを取得するなどの機能を追加し、関数などをクラス化してまとめる。ここにコードを置いてもいいのだが、微妙に長いため[GitHub](https://github.com/broccolingual/robots.txt-tester/blob/master/main.py)に置いておく。60行程度なので、内容を確認したい方はどうぞ。
※GitHubのコードでimportされているcoloramaというライブラリは、ターミナルで文字を着色するために使っているものなので、特に機能に重要なものではない。

# 参考記事

* [urllib.robotparser --- robots.txt のためのパーザ](https://docs.python.org/ja/3/library/urllib.robotparser.html)
* [スクレイピング、クローリングする時の注意点](https://docs.pyq.jp/column/crawler.html)
* [Webスクレイピングの注意事項一覧 - Qiita](https://qiita.com/nezuq/items/c5e827e1827e7cb29011)
* [分かりやすいpythonの正規表現の例 - Qiita](https://qiita.com/luohao0404/items/7135b2b96f9b0b196bf3)