5
4

More than 1 year has passed since last update.

threadingをやめてasyncio&aiohttpで楽にPythonスクレイピングを行う

Last updated at Posted at 2022-07-21

効率的なスクレイピングを行うにはリクエストとレスポンス間の待ち時間をなくすこと。これを実現するためにはthreadingモジュールでマルチスレッドか、asyncモジュールで並列処理をするかだ。

マルチスレッドは気軽に実装できる反面、デバッグが困難になる。asyncの非同期処理はコード量がやや増えるが、デバッグが楽。

この記事を呼んで我に返った

よし、threading使うのやめて、async使おうってことで試作したコードが以下

やっていることは、リクエストをしてスリープを1秒間を5回実行する(※スリープの理由は逮捕は嫌なので)

ネット環境によるのだろうけど、5回で2秒近くの処理時間の差が生まれる

import aiohttp
import asyncio
import time
import requests

url = 'https://qiita.com/osorezugoing/items/4ea5249c43c0ba8b89aa'
start_time = time.time()
res_list = []
tasks = []
# 計測結果
normal_exec_time = 0
async_exec_time = 0


def normal_request():
    """同期処理を5回実行
    1. リクエスト
    2. レスポンスの到着を待機
    3. 1秒間スリープ
    """
    global normal_exec_time
    print('normal_request')
    for i in range(5):
        res = requests.get(url)
        res_list.append(res)
        print(i, 'request interval')
        time.sleep(1)
    # 経過時間計測
    normal_exec_time = time.time() - start_time
    print("--- %s seconds ---" % (normal_exec_time), '\n')


def async_request():
    """非同期処理を5回実行
    1. リクエスト
    2. 1秒間スリープ
    3. 1と2を5回実行
    3. レスポンスの到着を待機
    """
    global async_exec_time
    print('async_request')

    async def _req(i):
        async with aiohttp.ClientSession() as session:
            async with session.get(url) as response:
                res_list.append(response)
                print(i, 'request interval')
                time.sleep(1)

    async def _run():
        # 非同期オブジェクトをtaskへ追加
        for i in range(5):
            tasks.append(_req(i))
        # taskのすべての処理を待機
        await asyncio.gather(*tasks)

    # この記述は実行環境がwindowsのため
    asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
    # 非同期処理実行
    asyncio.run(_run())
    # 経過時間計測
    async_exec_time = time.time() - start_time
    print("--- %s seconds ---" % (async_exec_time), '\n')


if __name__ == '__main__':
    # 同期処理
    normal_request()
    # 非同期処理
    start_time = time.time()  # 初期化
    async_request()
    # 同期と非同期の処理時間の差
    print('diff: ', normal_exec_time - async_exec_time)

normal_request
0 request interval
1 request interval
2 request interval
3 request interval
4 request interval
--- 7.513632774353027 seconds --- 

async_request
0 request interval
4 request interval
1 request interval
3 request interval
2 request interval
--- 5.4084553718566895 seconds --- 

diff:  2.105177402496338

さあ、これから新しいブランチ切って始めますかー

5
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
4