コピペで始めるPython aiohttp非同期HTTPリクエスト
- Pythonで初めて非同期HTTPリクエストをやろうと思って調べている
- 調べてみると、asyncとかawaitとか、aiohttpを使うの難しそう
- 最初はとにかくコピペで動くシンプルなコードが欲しい
この3点に当てはまる初心者の方へ向けて、コピペするだけ10秒ですぐ動かせるコードを2パターン用意しました。
技術的な解説は他のサイトへ譲ります。
とにかく、まずはシンプルなコードを動かしてイメージを掴むためだけの記事です。
ー もくじ ー
コピペでPython aiohttp非同期HTTPリクエスト
準備:aiohttp ライブラリインストール
まだaiohttpをインストールしていないかたは、pipしておきましょう。
pip install aiohttp
Collecting aiohttp
Obtaining dependency information for aiohttp from https://files.pythonhosted.org/packages/e6/9c/41d1c23c9e2dfc4cc0bd295754539f186fd012460b8b4ec091e42d3dbcc2/aiohttp-3.8.5-cp39-cp39-macosx_10_9_x86_64.whl.metadata
・・・省略・・・
Successfully installed aiohttp-3.8.5 aiosignal-1.3.1 async-timeout-4.0.2 frozenlist-1.4.0 multidict-6.0.4 yarl-1.9.2
Successfully installed...と出ればOK。
コピペで実行1:HTTPステータスコードチェック
以下ソースコードをご自分のエディタへ貼り付け、実行してみてください。
コード内に例示しているURL(https://webscraper.io/test-sites)は、スクレイピング練習用サイトとして提供してくれているので採用しました。
4つめはわざと存在しない(HTTPステータスコード 404が返ってくる)URLを置いています。
aiohttp-sample1.pyimport aiohttp
import asyncio
from bs4 import BeautifulSoup
async def main():
# 対象URLがリスト化されていると仮定(この例では全て同じURL)
url_list = [
'https://webscraper.io/test-sites',
'https://webscraper.io/test-sites',
'https://webscraper.io/test-sites',
'https://webscraper.io/test-sites-not-exists',
'https://webscraper.io/test-sites',
]
async with aiohttp.ClientSession() as session:
# fetch_urlするタスクを対象URLの数だけ生成(5URLなので5タスク)
tasks = [fetch_url(i, session, url) for i, url in enumerate(url_list, start=1)]
# 5タスク全ての完了を待つ。resultにはfetch_urlでreturnした結果がリスト化される
results = await asyncio.gather(*tasks)
# 5タスク完了後、print
print(results)
async def fetch_url(i, session, url):
async with session.get(url) as response:
if response.status == 200:
print(result := f'{i}個目:成功')
return result
else:
print(result := f'{i}個目:失敗...')
return result
if __name__ == "__main__":
asyncio.run(main())
# ↑の代わりに以下のようにしても動く
# loop = asyncio.get_event_loop()
# loop.run_until_complete(main())
▼実行結果
% python aiohttp-sample1.py
2個目:成功
5個目:成功
3個目:成功
1個目:成功
4個目:失敗...
['1個目:成功', '2個目:成功', '3個目:成功', '4個目:失敗...', '5個目:成功']
print結果を見ると、実行中は完了順番がバラバラですが、全タスク完了後にreturnされたresultsを見ると、実行した順番で結果も格納されていることが分かります。
コピペで実行2:要素のスクレイピング
aiohttpで非同期スクレイピング処理をする場合を想定して、HTMLを解析するライブラリBeautifulSoupを組み込む場合の簡単な例です。
未インストールのかたはpipしておきましょう。
pip install beautifulsoup4
そして、以下コピペして実行します。webサイト上のH1タグを取ってくるだけです。
aiohttp-sample2.pyimport aiohttp
import asyncio
from bs4 import BeautifulSoup
async def main():
url_list = [
'https://webscraper.io/test-sites',
'https://webscraper.io/test-sites',
'https://webscraper.io/test-sites',
'https://webscraper.io/test-sites-not-exists',
'https://webscraper.io/test-sites',
]
async with aiohttp.ClientSession() as session:
tasks = [scrape_h1_tag(session, url) for url in url_list]
results = await asyncio.gather(*tasks)
print(results)
async def scrape_h1_tag(session, url):
async with session.get(url) as response:
response_text = await response.text()
soup = BeautifulSoup(response_text, 'html.parser')
h1_tag = soup.select_one('.col-md-12 > h1')
return h1_tag if h1_tag is not None else 'h1取得失敗...'
if __name__ == "__main__":
asyncio.run(main())
▼実行結果
% python aiohttp-sample2.py
[<h1>Test Sites</h1>, <h1>Test Sites</h1>, <h1>Test Sites</h1>, 'h1取得失敗...', <h1>Test Sites</h1>]
22行目で await response.text() とするのがなかなか見慣れないポイントですね。
このawaitを書き忘れると以下「awaitしてないよ」と怒られるので注意。
% python aiohttp-sample2.py
Traceback (most recent call last):
File "/Users/yuki/Desktop/aiohttp-sample2.py", line 29, in <module>
asyncio.run(main())
・・・省略・・・
TypeError: object of type 'coroutine' has no len()
sys:1: RuntimeWarning: coroutine 'ClientResponse.text' was never awaited
・・・
以上、aiohttpで簡単に非同期HTTPリクエストするコードでした。
上記例では5URLしか用意していないので、Python標準のrequestsライブラリで同期リクエストするのと比べて処理速度の速さ実感がありませんが、100個以上用意すれば速度の速さに驚くこと間違いなし。