PythonでURLからJSONファイルを読み込んで解析する
PythonでURLからJSONを読み込むと、リモートレスポンスをすぐに使えるデータに変換できます。urllib.requestでレスポンスを取得し、ボディをjson.loadsに渡すことで辞書またはリストを得られます。このパターンはパブリックAPI、ホストされた設定ファイル、コードとは独立して変化するデータセットに適しています。
PythonでURLからJSONを読み込むサンプル
出力:
ここに出力が表示されます...
出力:
Squad: Super Hero Squad
Members: 3
このサンプルの動作説明
urllib.request.urlopen(url)は同期GETを送信してHTTPレスポンスを返します。withブロックが終了後に接続を閉じます。response.read()はボディをraw bytesとして返します。json.loadsはbytesを直接受け付けるため、手動で.decode("utf-8")する必要はありません。- 解析によりJSONオブジェクトがPythonのdictに変換され、
data["squadName"]でインデックスアクセスし、len(data["members"])で件数を取得できます。
このランタイムではurlopenは同期的なので、多くのチュートリアルがネットワーク呼び出しを非同期コードで包んでいますが、awaitもasyncioも必要ありません。
json.load と json.loads の違い
どちらもJSONをPythonオブジェクトに逆シリアル化しますが、読み取り元が異なります。
| 関数 | 入力 | 使用するタイミング |
|---|---|---|
json.loads(...) | strまたはbytesの値 | response.read()のようにコンテンツがすでにメモリにある場合 |
json.load(...) | ファイルまたはストリームオブジェクト | open(path)やレスポンス自体のような開いたハンドルがある場合 |
ここではjson.loads(response.read())とjson.load(response)は同じdictを生成します。よくあるエラーは型の誤り:json.loadに文字列、またはjson.loadsにファイルオブジェクトを渡すとAttributeErrorやTypeErrorが発生します。
Run DetailsでJSONリクエストを確認する
プログラム終了後にRun Detailsを開きます。スクリプトが行ったネットワークリクエストと、実行のためにランタイムが読み込んだパッケージを分けて表示します。
| Run Detailsのシグナル | 意味 |
|---|---|
| Requestsにステータス200でraw.githubusercontent.comへのGETが表示される | JSONファイルがネットワーク経由で正常に取得された |
| リクエストの時間(ms) | 解析とは別に、取得自体にかかった時間 |
| リクエストが403/404、ブロック、または失敗 | URLに到達できないかCORSが無効で、コードに到達しなかった |
| Packagesが空(“No runtime packages”) | jsonとurllibは標準ライブラリのため何もインストールされなかった |
Packagesセクションが空なのは、このアプローチがインストール不要であることの証拠です。beautifulsoup4やpandasをインポートする例では、ウェブスクレイピングの例のようにここにパッケージが表示されます。標準ライブラリでJSONを読む場合は何も表示されません。
ブラウザでURLから読み込む場合、エンドポイントがCORSヘッダーを送信する場合にのみ機能します。上記のfixtureはGitHub rawのCORS対応ファイルです。そのヘッダーのないクロスオリジンURLはコード実行前にブロックされ、JSONDecodeErrorではなく失敗したリクエストとして表示されます。
URLからJSONを読み込む際のよくある間違い
間違い:レスポンスストリームを2回読み込む。
誤り:
raw = response.read()
data = json.loads(response.read())
正しい:
data = json.loads(response.read())
なぜ起きるか:urlopenは一度だけ消費できるストリームを返すため、2回目のread()は空のbytesを返します。
間違い:解析したJSON配列に.get()を呼び出す。
誤り:
data = json.loads(response.read())
first = data.get("name")
正しい:
data = json.loads(response.read())
first = data[0] if isinstance(data, list) else data["name"]
なぜ起きるか:トップレベルのJSON配列はPythonのリストに解析され、.getがないためインデックスアクセスが必要です。
エラー処理と欠損キー
urlopenは4xxや5xxレスポンスに対してHTTPErrorを発生させますが、エラーオブジェクトはまだ読み取り可能なため、try/exceptでキャッチすることでJSONエラーボディを解析できます:
from urllib.error import HTTPError
try:
with urllib.request.urlopen(url) as response:
data = json.loads(response.read())
except HTTPError as err:
data = json.loads(err.read())
省略可能なフィールドにはdata.get("key")を使用してKeyErrorの代わりにNoneを返します。標準ライブラリのjsonモジュールは信頼できない入力を安全に解析するため、JSONの読み込みにeval()を使用しないでください。
FAQ
PythonでJSONファイルを読み込むには?
リモートファイルの場合はurllib.request.urlopen(url)で開き、bytesをjson.loadsに渡します。ディスク上のファイルにはwith open(path) as f: data = json.load(f)を使います。どちらもPythonのdictまたはリストを返します。
json.loadとjson.loadsの違いは?
json.loadはファイルまたはストリームオブジェクトから読み込み、json.loadsはstrまたはbytesの値から読み込みます。末尾の「s」はstringを意味します。コンテンツがすでにメモリにある場合はloadsを使用してください。
PythonでJSONを読み込むにはrequestsライブラリが必要ですか?
いいえ。urllib.requestとjsonはどちらも標準ライブラリなので、インストールなしでJSONの取得と解析ができます。requestsライブラリは.json()ヘルパーやセッション管理などの利便性を追加しますが、サードパーティの依存関係です。
PythonにおけるJSONとは?
JSONは構造化データのテキスト形式です。PythonはJSONオブジェクトをdictに、配列をリストに、プリミティブをstr、int、float、bool、Noneにマップします。これがjson.loadsが解析後に返すものです。