見出し画像

【初心者向け】Pythonでスクレイピングする環境を作る⑥ スクレイピングでの注意事項

Naruhiko です。

前回までに Google 検索した結果のサイトURL一覧を取得できるようになりました。
今度はそのサイト一覧URLを元にそのサイトのデータを取得してみたいと思います。

が、

その前に、スクレイピングをするにあたって注意事項が何点かあります。
これはとても大事なことです。
著作権法や不動産侵入法などに違反してしまう可能性もありますので十分注意してください。

ここでもキーになることを話していきますが、
できるだけスクレイピングに関するしっかりした本などを購入することをおすすめします。

ということで、前回までに作成したコードはこちらです。

import requests
from bs4 import BeautifulSoup

# User-Agent
user_agent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) \
             AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100"

def get_html(url, params=None, headers=None):
    """ get_html
    url: データを取得するサイトのURL
    [params]: 検索サイトのパラメーター {x: param}
    [headers]: カスタムヘッダー情報
    """
    try:
        # データ取得
        resp = requests.get(url, params=params, headers=headers)
        # 要素の抽出
        soup = BeautifulSoup(resp.text, "html.parser")
        return soup
    except Exception as e:
        return None

def get_search_url(word, engine="google"):
    """ get_search_url
    word: 検索するワード
    [engine]: 使用する検索サイト(デフォルトは google)
    """
    try:
        if engine == "google":
            # google 検索
            search_url = "https://www.google.co.jp/search"
            search_params = {"q": word}
            search_headers = {"User-Agent": user_agent}
            # データ取得
            soup = get_html(search_url, search_params, search_headers)
            if soup != None:
                tags = soup.select(".r > a")
                urls = [tag.get("href") for tag in tags]
                return urls
            else:
                return None
        else:
            return None
    except Exception as e:
        return None


try:
    result = get_search_url("python")
    if result != None:
        print(result)
    else:
        print("取得できませんでした")
except Exception as e:
    print("エラーになりました")

Webサイトへアクセスする時の制限を知っておく

何がまずいのか、何がまずくないのか。
それの判断を知っておく必要があります。

主に、取得したデータの活用方法と、取得元への配慮になります。

取得したデータの活用については、この場では詳しく話しません。
ようは、取得したデータの使い方について気をつけてほしいということです。
データを公開してもいいか、公開するならどのような形にするべきか、そもそも取得してもいいか、などなどいろいろと考える必要があります。

取得したデータの管理には十分注意してください。

取得元への配慮

スクレイピングは、時に同じサイトへ何度もリクエストを繰り返すことがあります。
サーバの管理者からすれば短時間で大量のリクエストがあるのはたまったものではありません。
サーバによっては、そのようなことを回避するためにロボットに対しての要望を書いているものが多々あります。
そのようなサーバ側からの要望に対応するのも取得元への配慮になるのです。

リクエストする間隔

ネットでは、リクエストする時によく
「1リクエストするたびに1秒待つ」
というようなことがよく書かれています。

しかし、過去にこの間隔でも警察がきたという判例があります。
ですので、安心するに越したことはありません。
余裕を持って3秒から10秒程度は待機したほうがいいと思います。
そんなに急いで取るものでもないですしね。
あとは、真夜中の時間帯を狙うという方法もありです。

今回は、5秒待ってみましょう。
time という標準ライブラリの sleep 関数を使っていきます。

import time

import requests
from bs4 import BeautifulSoup

PEP8に従うと、標準ライブラリなので import を一番最初に記述します。
スリープする箇所は、requests.get 直前にしましょう。

# 待機
time.sleep(5)
# データ取得
resp = requests.get(url, params=params, headers=headers)

これでどんな状態のリクエスト呼び出しがあっても、
必ず5秒待ってからリクエスト処理を行うようになります。

ちなみに次項で話す robots.txt にも時間間隔が設定してあるものがあります。
この時間を使用するのがスマートかもしれません。

robots.txtファイルの内容に従う

サイトによっては、ロボットやクローラーに対してサイト巡回方法を制御してほしいことが書かれているファイルがあります。
robots.txt というファイルです。

これは、サイトを設置する際の知識にもなりますので
内容を覚えておくことをおすすめします。

robots.txt は基本的にドメインルートに設置しています。

https://www.google.com/robots.txt

google にも設置してあるので例として見ておくと良いでしょう。

robots.txt の内容を取得しチェックするのは
標準ライブラリの urllib.robotparser の RobotFileParser を使うことで可能です。

from urllib.robotparser import RobotFileParser

# robots.txt 用パーサー
rp = RobotFileParser()
# robots.txt 取得
rp.set_url("https://www.google.co.jp/robots.txt")
rp.read()

# 取得していいか確認
print(rp.can_fetch("*", "https://www.google.co.jp/search"))

このコードを実行するとこの企画自体が破綻してします。
Google は基本的に search に対してロボットは禁止しているのです。
ですのでここに来ていまさらですが、自己責任でお願いします。

では、気を取り直してこのコードを関数化しておきましょう。
get_robots_txt() という関数を作成し、url という引数を追加します。

def get_robots_txt(url):
    """ get_robots_txt
    url: robots.txt を確認するサイトURL
    """

ここに先程のコードを少し作り変えて入れます。

    # robots.txt 取得
    rp.set_url("https://www.google.co.jp/robots.txt")
    rp.read()
    # 取得していいか確認
    return rp.can_fetch("*", url))

try/except をいれて、エラーの場合は失敗の False を返しておきます。

def get_robots_txt(url):
    """ get_robots_txt
    url: robots.txt を確認するサイトURL
    """
    try:
        # robots.txt 取得
        rp.set_url("https://www.google.co.jp/robots.txt")
        rp.read()
        # 取得していいか確認
        return rp.can_fetch("*", url)
    except Exception as e:
        return False

robots.txt も url から取得できるようにしましょう。
url をパースする urllib.parse の urlparse を使用します。

from urllib.parse import urlparse

ばらばらにした後、scheme と netloc を使うことで、トップドメインを作ることができます。
それらを使って、url を再構築していくわけです。

parsed_url = urlparse(url)
robots_url = "{0.scheme}://{0.netloc}/robots.txt".format(parsed_url)

そして、その文字列をセットします。

rp.set_url(robots_url)

get_robots_txt() はこうなります。

# robots.txt 用パーサー
rp = RobotFileParser()

def get_robots_txt(url):
    """ get_robots_txt
    url: robots.txt を確認するサイトURL
    """
    try:
        # robots の url 取得
        parsed_url = urlparse(url)
        robots_url = "{0.scheme}://{0.netloc}/robots.txt".format(parsed_url)
        
        # robots.txt 取得
        rp.set_url(robots_url)
        rp.read()
        # 取得していいか確認
        return rp.can_fetch("*", url)
    except Exception as e:
        return False

チェックするときは、こんな感じで使います。

get_robots_txt("https://www.google.co.jp/search/")

nofollow のリンクはクロールしない

nofollowとは、クローラーにページ内のリンクを辿らせず、リンク先にページの評価を渡さないために指定するmeta要素やa要素に指定できる値です。
この値が見つかれば、そのリンクは巡らないようにしたほうがいいですね。

しかし、この連載では、google 検索結果のリンクのみを取得しているに留めるため、この部分はまた機会があれば実装したいと思います。

最後に

今回の最終的なコードはこうなりました。

import time
from urllib.robotparser import RobotFileParser
from urllib.parse import urlparse

import requests
from bs4 import BeautifulSoup

# User-Agent
user_agent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) \
              AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100"

# robots.txt 用パーサー
rp = RobotFileParser()

def get_robots_txt(url):
    """ get_robots_txt
    url: robots.txt を確認するサイトURL
    """
    try:
        # robots の url 取得
        parsed_url = urlparse(url)
        robots_url = "{0.scheme}://{0.netloc}/robots.txt".format(parsed_url)
        print(robots_url)
        # robots.txt 取得
        rp.set_url(robots_url)
        rp.read()
        # 取得していいか確認
        return rp.can_fetch("*", url)
    except Exception as e:
        return False

def get_html(url, params=None, headers=None):
    """ get_html
    url: データを取得するサイトのURL
    [params]: 検索サイトのパラメーター {x: param}
    [headers]: カスタムヘッダー情報
    """
    try:
        # 待機
        time.sleep(5)
        # データ取得
        resp = requests.get(url, params=params, headers=headers)
        # 要素の抽出
        soup = BeautifulSoup(resp.text, "html.parser")
        return soup
    except Exception as e:
        return None

def get_search_url(word, engine="google"):
    """ get_search_url
    word: 検索するワード
    [engine]: 使用する検索サイト(デフォルトは google)
    """
    try:
        if engine == "google":
            # google 検索
            search_url = "https://www.google.co.jp/search"
            search_params = {"q": word}
            search_headers = {"User-Agent": user_agent}
            # データ取得
            soup = get_html(search_url, search_params, search_headers)
            if soup != None:
                tags = soup.select(".r > a")
                urls = [tag.get("href") for tag in tags]
                return urls
            else:
                return None
        else:
            return None
    except Exception as e:
        return None


try:
    result = get_search_url("python")
    if result != None:
        print(result)
    else:
        print("取得できませんでした")
except Exception as e:
    print("エラーになりました")

次回は google 検索で取得した URL 一覧からデータを取得してみようと思います。

---

気に入っていただけたら、フォローや好きをお願いします!

連載目次

【初心者向け】Pythonでスクレイピングする環境を作る① はじめに
【初心者向け】Pythonでスクレイピングする環境を作る② Dockerの使い方
【初心者向け】Pythonでスクレイピングする環境を作る③ VSCodeでDocker環境を構築する
【初心者向け】Pythonでスクレイピングする環境を作る④ requestsでデータを取得してみる
【初心者向け】Pythonでスクレイピングする環境を作る⑤ Google検索をしてみる
【初心者向け】Pythonでスクレイピングする環境を作る⑥ スクレイピングでの注意事項
【初心者向け】Pythonでスクレイピングする環境を作る⑦ 検索結果のページのタイトルを取得する
【初心者向け】Pythonでスクレイピングする環境を作る⑧ クラスにまとめてみる
【初心者向け】Pythonでスクレイピングする環境を作る⑨ テストしてみる
【初心者向け】Pythonでスクレイピングする環境を作る⑩ crawler と scraper を分ける

ここから先は

0字

¥ 100

この記事が気に入ったらサポートをしてみませんか?