- Web API から情報取得したい
requests ライブラリの役割は、HTTP リクエストを行うことです。
つまり Python を使って Web 上から自由に情報取得できるようになるので、プログラムに実装できる機能の幅が一気に広がります。
本記事では、難易度の低い「Web API へのアクセス方法」を解説します。
後日 Beautiful Soup を併用した「スクレイピングの方法」を別記事にしようと思っていますので、記事が完成しましたらこちらでご案内する予定です。
なお、requests ライブラリをさらに深く理解するためには HTTP 通信の理解が必須です。HTTP の理解に不安がある方には、『Real World HTTP』の通読を強くおすすめします。
僕自身もこの本を読んでから、理解が深まりました。
requests ライブラリのざっくりした説明
requests ライブラリの役割
Python を使って HTTP 通信するためのライブラリです。
つまり自分の手元にある PC と遠隔地にあるサーバーとの間で、HTTP というルールに従って情報を送信したり受信したりできるものになります。
ライブラリ名は、サーバーに情報を要求する = “requests” と考えるとわかりやすいかもしれません。
直感的な理解のために、具体例をあげてみます。
普段 Chrome などのブラウザのアドレスバーに「http://~」などと打ち込むことがあると思いますが、その時には裏側で以下のことが行われています。
- URLを入力してEnterを押す
- サーバーにページの内容をリクエストする
- ページの内容が自分のPCに返ってくる
- ブラウザが画面を表示する
この「ページの内容を要求(リクエスト)する」ことと、「ページの内容が返却(レスポンス)される」部分にHTTP通信が利用されているというわけです。
urllib ライブラリとの違い
Python には urllib という標準モジュールがあります。
実は、この urllib.request を使っても HTTP 通信を行うことは可能です。
ただし、特別な理由がない限り requests ライブラリを推奨します。
requests ライブラリは urllib をより使いやすくカスタマイズしたものであり、同じことをするにしても urllib.request を使うと相当コード量が増えてしまうからです。
requests を使った Web API へのアクセス方法
Web APIへのアクセスは、以下の流れで行います。
- 利用する Web API の調査
- ライブラリのインストール
- コードを作成・実行する
今回は、例として「天気予報 API(livedoor 天気互換)」を活用してみます。
気象庁から配信されている日本全国の天気予報を取得できます。
利用する Web API の調査
最初の段階で、以下の内容は調査しておくと良いです。
- API の利用規約を精読する
- 利用料金
- リクエストの制限回数
- 許可されている利用目的
- アクセス先のURL(エンドポイント)を調べる
- 認証系で必要な情報を確認する
API の利用規約を精読する
利用規約には API を使うためのお約束ごとです。必ず確認するようにしてください。
まず、有料・無料を確認します。
サービスの利用は無料ですが、この API を利用したことで何らかの不具合が発生しても責任は負えません。自己責任にてお願いします。
天気予報 API(livedoor 天気互換)
そして必ず確認したいのが、リクエストのレート制限についてです。
過度に Web API に対してリクエストを送ってしまうとサーバーに大きな負担をかけてしまい、最悪の場合はサーバーがダウンしてしまいます。
そのようなことがないよう、通常は API の利用規約内に「リクエストは〇〇秒以上の間隔をあけてアクセスするように」などの決まりが書かれています。
今回の天気予報 API では、以下の記述がありました。
あまり強いサーバーではないので、API に連続してアクセスする場合は最低でも 0.5 秒以上間隔を空けてから行ってください。
天気予報 API(livedoor 天気互換)
仮に書かれていなかった場合には、API 提供者に確認をとってみるのも良いでしょう。
また商用利用する場合には、商用 OK かどうかもチェックしてください。
アクセス先のURL(エンドポイント)を調べる
続いて、アクセス先の URL を確認します。
JSON データをリクエストする際のベースとなる URL は以下になります。
天気予報 API(livedoor 天気互換)
https://weather.tsukumijima.net/api/forecast
この URL に下の表のパラメータを加え、実際にリクエストします。
上記をベースに、city パラメータを加えてリクエストする仕様のようです。
地域別に定義された ID 番号を表します。
天気予報 API(livedoor 天気互換)
リクエストする地域と ID の対応は、livedoor 天気で使われていた 全国の地点定義表 内で「一次細分区域(cityタグ)」の ID をご参照ください。(例・佐賀県 伊万里 = 410020 )
久留米市の天気を取得する場合は以下とするようです。
下記 URL にアクセスして JSON データを取得します。
基本 URL + 久留米の ID (400040)
https://weather.tsukumijima.net/api/forecast/city/400040クエリで取得することもできます。
天気予報 API(livedoor 天気互換)
https://weather.tsukumijima.net/api/forecast?city=400040
今回はエンドポイントが一つでしたが、APIによっては複数のエンドポイントが用意されていることの方が多いです。
欲しい情報にアクセスできるエンドポイントを見つけ出してください。
認証系で必要な情報を確認する
API によっては、以下のような追加の認証情報が必要になることがあります。
- API Key
- Access Token
これらは利用者を識別するためのものです。
必要な場合に requests ライブラリでリクエストを送る際に、これらの認証情報を添付することになります。
ちなみに今回利用する「天気予報 API」では認証情報は要求されないようでした。
ライブラリのインストール
ライブラリ名はrequests
です。
以下のコマンドを実行してインストールを行いましょう。
pip install requests
コードを作成・実行する
最後にコードを作成します。
今回の「天気予報API」ではクエリパラメータとして場所に関する情報を渡す必要があるので、以下のように params をリクエストに含めました。
import requests
endpoint = "https://weather.tsukumijima.net/api/forecast"
params = {
"city": 400040,
}
response = requests.get(endpoint, params=params)
# 結果を表示
print(response.text)
すると print(response.txt) の部分が実行され、以下が表示されるはずです。
{
"publicTime": "2024-01-27T11:00:00+09:00",
"publicTimeFormatted": "2024/01/27 11:00:00",
"publishingOffice": "福岡管区気象台",
"title": "福岡県 久留米 の天気",
"link": "https://www.jma.go.jp/bosai/forecast/#area_type=offices&area_code=400000",
"description": {
"publicTime": "2024-01-27T10:39:00+09:00",
"publicTimeFormatted": "2024/01/27 10:39:00",
"headlineText": "",
"bodyText": " 福岡県は、高気圧に覆われて晴れの所もありますが、気圧の谷や寒気の影響により、おおむね曇りとなっています。\n\n 27日は、高気圧に覆われて晴れる所もありますが、気圧の谷や寒気の影響により、おおむね曇りとなるでしょう。\n\n 28日は、気圧の谷や寒気の影響により曇りで、雨や雪となり雷を伴う所がありますが、高気圧に覆われて次第に晴れとなるでしょう。\n\n<天気変化等の留意点>\n 27日12時から28日12時までに予想される1時間降水量は、多い所で、筑後地方で5ミリ、27日12時から28日12時までに予想される24時間降水量は、多い所で、筑後地方で10ミリの見込みです。",
"text": " 福岡県は、高気圧に覆われて晴れの所もありますが、気圧の谷や寒気の影響により、おおむね曇りとなっています。\n\n 27日は、高気圧に覆われて晴れる所もありますが、気圧の谷や寒気の影響により、おおむね曇りとなるでしょう。\n\n 28日は、気圧の谷や寒気の影響により曇りで、雨や雪となり雷を伴う所がありますが、高気圧に覆われて次第に晴れとなるでしょう。\n\n<天気変化等の留意点>\n 27日12時から28日12時までに予想される1時間降水量は、多い所で、筑後地方で5ミリ、27日12時から28日12時までに予想される24時間降水量は、多い所で、筑後地方で10ミリの見込みです。"
},
"forecasts": [
{
"date": "2024-01-27",
"dateLabel": "今日",
"telop": "晴時々曇",
・・・
// 以下、省略
実装のために知っておくと便利な知識
レスポンスのうち、要素の一部を取得する
上記で response として受け取ったデータは、Response オブジェクトです。
これではちょっと扱いづらいので、以下の流れで辞書にしてから要素を取り出すことが多いと思います。
- Response オブジェクトを辞書に変換する
- 辞書として要素にアクセスする
先ほどのレスポンスを例に、title の値を取得するコード例を示します。
import requests
endpoint = "https://weather.tsukumijima.net/api/forecast"
params = {
"city": 400040,
}
response = requests.get(endpoint, params=params)
# json() メソッドで辞書に変換する
response_dict = response.json()
title = response_dict["title"]
print(title)
すると、title に対応する値のみが出力されました。
福岡県 久留米 の天気
例えば bodyText などのより深い階層にある要素も、一般的な辞書の操作方法で取り出せます。
import requests
endpoint = "https://weather.tsukumijima.net/api/forecast"
params = {
"city": 400040,
}
response = requests.get(endpoint, params=params)
# json() メソッドで辞書に変換する
response_dict = response.json()
# bodyText を取得する
body_text = response_dict["description"]["bodyText"]
print(body_text)
実行結果は以下になります。
福岡県は、高気圧に覆われて晴れの所もありますが、気圧の谷や寒気の影響により、おおむね曇りとなっています。
27日は、高気圧に覆われて晴れる所もありますが、気圧の谷や寒気の影響により、おおむね曇りとなるでしょう。
28日は、気圧の谷や寒気の影響により曇りで、雨や雪となり雷を伴う所がありますが、高気圧に覆われて次第に晴れとなるでしょう。
<天気変化等の留意点>
27日12時から28日12時までに予想される1時間降水量は、多い所で、筑後地方で5ミリ、27日12時から28日12時までに予想される24時間降水量は、多い所で、筑後地方で10ミリの見込みです。
GET 以外の HTTP メソッドを使ってアクセスする方法
先ほどはrequests.get()
としてリクエストを送りました。
これはサーバーに対して「GET メソッドでリクエストを送る」という指示になるのですが、HTTP メソッドには他にもいくつか種類が存在します。
HTTPメソッド | requests のメソッド |
---|---|
GET | get() |
POST | post() |
PUT | put() |
DELETE | delete() |
HEAD | head() |
OPTIONS | options() |
PATCH | patch() |
Web API では、GET または POST を使うことが多いと思います。
別のメソッドが指定されている場合にも、HTTP メソッドと完全に対応する形で requests のメソッドも用意されているのであまり混乱することはないと思います。
リクエスト時に同時に送信できる情報
エンドポイントにアクセスする際に、特定の情報を添付することができます。
添付方法には次のような種類があります。
- クエリパラメータ
- リクエストボディ
- フォームデータ
- HTTP ヘッダー
どの方法でデータを添付するかについては、API ドキュメントなどに書いてあります。
ここではそれぞれ requests ライブラリでどのように情報を送信するかをサクッと解説します。
クエリパラメータ
クエリパラメータをつける場合は、params 引数に辞書を渡します。
# クエリパラメータを定義
params = {
"city": 400040,
}
response = requests.get(endpoint, params=params)
先ほどの天気予報APIでも、クエリパラメータを使ってリクエストを送りました。
リクエストボディ
リクエストボディは、json 引数に辞書を渡します。
# リクエストボディを定義
request_body = {
"key": "value",
}
response = requests.get(endpoint, json=request_body)
フォームデータ
ファイルアップロードやフォーム送信には、フォームデータが使われることがあります。
data 引数に辞書を渡してください。
# フォームデータを定義
form_data = {
"key": "value",
}
response = requests.get(endpoint, data=form_data)
HTTP ヘッダー
HTTP ヘッダーに値を含める場合には、headers 引数に辞書を渡します。
# HTTP ヘッダーを定義
headers = {
"Authorization": "Bearer YOUR_TOKEN"
}
response = requests.get(endpoint, headers=headers)
コメント