仕事の依頼はこちらから 依頼フォーム

【Python】requests.getからBeautifulSoupのインスタンス化までの流れを自作モジュール化

私はPythonでrequestとbeautifulsoup4モジュールを組み合わせてWebスクレイピングをすることが多いのですが、コーディング量を減らしたいということでrequests.getからBeautifulSoupのインスタンス化までの流れを自作モジュール化しました。

本記事では作成した自作モジュールを共有したいと思います。

目次

背景

これまでBeautifulSoupのインスタンス化を行う際におまじないような感じでこのようなコードを何も考えずに書いていました。

# モジュールのインポート
from time import sleep

from bs4 import BeautifulSoup
import requests


def main():
    r = requests.get('https://webscraper.blog/', timeout=30)  # レスポンスの取得
    r.raise_for_status()  # 例外送出

    sleep(1)  # 待機処理

    soup = BeautifulSoup(r.content, 'lxml')  # BeautifulSoupのインスタンス化

if __name__ == '__main__':
    main()

このコードでは1リクエストのみで待機処理は不要ですが、実際にはほとんどが複数リクエストを行うコードなのでこの後に別のリクエストを行うことを想定して待機処理を記載しています。複数リクエストとなるとrequest.getからBeautifulSoupのインスタンス化のコードを再度入力が必要となります。

複数リクエストとなるとrequest.getからBeautifulSoupのインスタンス化のコードを再度入力が必要となります。

はっきり言って定型コードなのに毎回このコードを入力するのはめんどくさいですよね?そう思い自作モジュール化しようと考えました。

作成した自作モジュール

コードの詳細は割愛しますが、作成した自作モジュールのコードは以下のとおりです。

import random
from time import sleep
import traceback

from bs4 import BeautifulSoup
import requests
from tenacity import retry, stop_after_attempt, wait_fixed


class MyBeautifulSoup(BeautifulSoup):
    """BeautifulSoupクラスを継承し、リクエスト失敗時のリトライ機能とリクエスト後の待機処理を追加

    最大リトライ2回
    """
    def __init__(
        self,
        url: str,
        *,
        headers: dict[str, str] = None,
        sleep_time: int | float | tuple[int | float, int | float] = 1,
    ) -> None:
        """
        Args:
            url (str): リクエストURL
            headers (dict[str, str], optional): リクエストヘッダ、初期値None
            sleep_time (int | float | tuple[int | float, int | float], optional): リクエスト後の待機時間、タプルで範囲指定した場合は範囲内でランダム、初期値1
        """
        self._url = url
        self._headers = headers

        if isinstance(sleep_time, tuple) and len(sleep_time) != 2:
            raise ValueError('When sleep_time is a tuple, 2 arguments must be specified')

        self._response = self._fetch_url()

        if isinstance(sleep_time, tuple):
            wait_time = random.uniform(sleep_time[0], sleep_time[1])
        else:
            wait_time = sleep_time

        sleep(wait_time)
        super().__init__(self.response.content, 'lxml')

    @retry(stop=stop_after_attempt(3), wait=wait_fixed(60))
    def _fetch_url(self):
        try:
            response = requests.get(self._url, headers=self.headers, timeout=30)
            response.raise_for_status()
        except requests.RequestException:
            print(traceback.format_exc())
            raise

        return response

    @property
    def url(self):
        return self._url

    @property
    def headers(self):
        return self._headers

    @property
    def response(self):
        return self._response
ポイント
  • tenacityモジュールを使用してrequests.get失敗時に最大2回のリトライ機能を追加
    (stop_after_attemptの引数を変更することで最大リトライ回数、wait_fixedの引数を変更することで失敗後の待機時間を変更可)
  • requests.get後の待機時間を指定可能
    (int、floatで指定時はその時間待機、tupleで指定時はその範囲内でランダムの時間待機)

この自作モジュールをインポートして書くことでこのようにスッキリとしたコードでBeautifulSoupのインスタンス化を行うことが可能となります。ぜひ使用してみてください。

from mybeautifulsoup import MyBeautifulSoup


def main():
    soup = MyBeautifulSoup('https://webscraper.blog/')

if __name__ == '__main__':
    main()

この記事が気に入ったら
フォローしてね!

シェアしていただけると嬉しいです!
  • URLをコピーしました!

コメント

コメントする

目次