【Python】urllibの基本的な使い方

Python における HTTP 接続のための標準ライブラリである urllib の基本的な使い方を解説します。
目次
urllib モジュール
urllib は、HTTP接続に関する機能を提供する Python の標準モジュールです。urllib は、インターネット上のデータを扱うための機能を多く備えており、URL解析やデータのダウンロードなど、HTTP 接続を簡単に行うことができます。
Python の HTTP 通信では requests がデファクトスタンダートの位置づけですが、外部ライブラリに依存しないように開発したい場合には、urllib が使用できます。
この記事では、HTTP リクエストを作成してやり取りする簡単な例を使用して urllib の基本的な使い方を紹介します。
HTTP リクエスト
Web システムで、サーバーとクライアントがやり取りするには、クライアントがサーバーに対して特定の操作を行うための HTTP リクエストを送信します。HTTP リクエストには、いくつかのメソッドがあり、代表的なものは以下です。
| メソッド | 概要 |
|---|---|
GET | リソースの取得をサーバーに要求します。データ取得するための最も一般的に使用されるメソッドで、URL にクエリパラメータを含めてリクエストを送信し、サーバーからの応答を受け取ります。 |
POST | 新しいリソースを作成するためにサーバーにデータを送信します。例えば、フォーム送信や DB へのデータ追加に使用します。POST は、データを HTTP リクエストのボディに含めて送信します。 |
PUT | 指定されたリソースを更新するために使用します。PUT は、既存のリソースを置き換えるために使用され、HTTP リクエストのボディに更新データを含めて送信します。 |
DELETE | 指定されたリソースをサーバーから削除するために使用します。 |
他にも HTTP リクエストで使用できるメソッドはありますが、上記が最も代表的なものです。GET はデータ取得、POST はデータ登録、PUT はデータ更新、DELETEはデータ削除といった操作に使用されます。
テスト用サービス httpbin.org
HTTP リクエストとレスポンスをテストする
HTTP リクエストとレスポンスのテストをするためには、API を提供するサーバーが必要になります。今回は「httpbin.org」を使用します。
httpbin.org は、HTTP リクエストとレスポンスのテストに使用される人気のオンラインサービスで、開発者が HTTP リクエストを送信し、そのレスポンスを確認できるように設計されています。
様々な種類の HTTP リクエストをシミュレートしてレスポンスデータを分析することで、Web 開発者は自分のコードが予期したとおりに動作するかをテストすることが可能です。httpbin.org は、WebAPI の開発や HTTP クライアントのライブラリ、フレームワークのテストなどに広く使用されています。
Docker 環境の利用
httpbin.org は、通信したタイミングによってサービスが不安定であることがあります。httpbin.org のサービスは、Docker 環境が用意されているため、Docker 環境が手元にある場合には、以下のコマンドでローカル実行してテストする方が安定的に動作確認ができます。
docker run --rm -p 8080:80 kennethreitz/httpbin
上記コマンドを実行すると「kennethreitz/httpbin」というコンテナ環境をインストールして起動します。--rm オプションは、サービスを切ったタイミングでコンテナを削除するコマンドで、-p 8080:80 はポートの接続設定であり、ローカル環境からは 8080 ポートを使用してコンテナのサービスにアクセスできます。
なお、httpbin.org にアクセスする場合は、https で SSL 通信ができますが、ローカルの Docker 環境では SSL 通信は対応していないので http でアクセスする必要があります
以降のプログラム例では Docker 環境への接続を使用していますが、httpbin.org への URL もコメントアウトしているため、httpbin.org へ直接つないで試す場合は、コメントアウトを切り替えて試してみてください。
urllib の基本的な使い方
urllib を使用して基本的な GET / POST / PUT / DELETE のHTTPリクエストを作成し、サーバーとやり取りする方法を紹介します。
リソースの取得をサーバーに要求する GET
データを取得する
サーバーからリソースの取得をするには、以下のように GET メソッドの HTTP リクエストを生成し、送信することでデータを取得します。
import json
import urllib.request
# httpbin へアクセスする場合は以下を有効化
# url = "https://httpbin.org/get"
# Docker 環境で実行する場合は以下を有効化
url = "http://localhost:8080/get"
with urllib.request.urlopen(url) as r:
# 応答ボディの取得 (read() は一度しか呼び出せないため注意)
raw_data = r.read()
# ステータスコード
print(f"[status_code]:\n{r.status} {r.reason}\n")
# ヘッダー
print(f"[headers]:\n{r.getheaders()}\n")
# 応答の生データ(バイナリ)
print(f"[content]:\n{raw_data}\n")
# 応答の文字列形式
print(f"[text]:\n{raw_data.decode('utf-8')}\n")
# 応答のJSON形式
print(f"[json]:\n{json.loads(raw_data.decode('utf-8'))}\n")【実行結果】
[status_code]:
200 OK
[headers]:
[('Server', 'gunicorn/19.9.0'), ('Date', 'Fri, 26 Dec 2025 19:58:15 GMT'), ('Connection', 'close'), ('Content-Type', 'application/json'), ('Content-Length', '238'), ('Access-Control-Allow-Origin', '*'), ('Access-Control-Allow-Credentials', 'true')]
[content]:
b'{\n "args": {}, \n "headers": {\n "Accept-Encoding": "identity", \n "Connection": "close", \n "Host": "localhost:8080", \n "User-Agent": "Python-urllib/3.13"\n }, \n "origin": "xxx.xxx.xxx.xxx", \n "url": "http://localhost:8080/get"\n}\n'
[text]:
{
"args": {},
"headers": {
"Accept-Encoding": "identity",
"Connection": "close",
"Host": "localhost:8080",
"User-Agent": "Python-urllib/3.13"
},
"origin": "xxx.xxx.xxx.xxx",
"url": "http://localhost:8080/get"
}
[json]:
{'args': {}, 'headers': {'Accept-Encoding': 'identity', 'Connection': 'close', 'Host': 'localhost:8080', 'User-Agent': 'Python-urllib/3.13'}, 'origin': 'xxx.xxx.xxx.xxx', 'url': 'http://localhost:8080/get'}必要なモジュールとして urllib.request をインポートします。また、JSON 形式で情報のやり取りをするために json モジュールもインポートしておきます。
今回は「http://localhost:8080/get」として Docker のローカル環境を指定しています。直接 httpbin へアクセスする場合は「http://httpbin.org/get」の方のコメントアウトを外して、Docker の方をコメントアウトして切り替えて試してください。(以降の例も同様です。)
URLを開くためには、urllib.request.urlopen の引数として url を指定します。urllib では、通信後にリソースを適切に開放する必要があります。コンテキストマネージャーに対応しているため、with 句を使用することが可能です。
HTTP 通信では、通信結果をレスポンスのステータスコードで確認できます。ステータスコードは status、内容は reason プロパティにより確認できます。サーバーからの応答のヘッダーは getheaders() で取得します。
レスポンスのバイナリデータを取得する際には、read() を用いますが、1 度呼び出すとデータが消費されてしまうため、複数回呼び出すことはできません。そのため、上記 raw_data のように変数に格納して使用するように注意してください。データを利用する際はデコードし、JSON であれば json.loads により変換して使用します。
クエリパラメータを含めてリクエストを送信する
GETリクエスト時にサーバーに対して条件や情報を指定する際は、クエリパラメータを使用します。これらのパラメータは、URLの末尾に追加され、キーと値のペアで構成されます。クエリパラメータを含めてリクエストを送信するには、以下のようにします。
import json
import urllib.parse
import urllib.request
# クエリパラメータを定義
params = {"key1": "value1", "key2": "value2"}
# クエリ文字列を作成する
query_string = urllib.parse.urlencode(params)
# httpbin へアクセスする場合は以下を有効化
# url = f"https://httpbin.org/get?{query_string}"
# Docker 環境で実行する場合は以下を有効化
url = f"http://localhost:8080/get?{query_string}"
with urllib.request.urlopen(url) as r:
# 応答ボディの取得
raw_data = r.read()
# ステータスコード
print(f"[status_code]:\n{r.status} {r.reason}\n")
# ヘッダー
print(f"[headers]:\n{r.getheaders()}\n")
# 応答の生データ(バイナリ)
print(f"[content]:\n{raw_data}\n")
# 応答の文字列形式
print(f"[text]:\n{raw_data.decode('utf-8')}\n")
# 応答のJSON形式
print(f"[json]:\n{json.loads(raw_data.decode('utf-8'))}\n")【実行結果】(text部分のみ表示)
[text]:
{
"args": {
"key1": "value1",
"key2": "value2"
},
"headers": {
"Accept-Encoding": "identity",
"Connection": "close",
"Host": "localhost:8080",
"User-Agent": "Python-urllib/3.13"
},
"origin": "xxx.xxx.xxx.xxx",
"url": "http://localhost:8080/get?key1=value1&key2=value2"
}クエリパラメーターは、{"key1": "value1", "key2": "value2"} のように辞書形式で用意し、urllib.parse.urlencode に指定することでURLを生成できます。
クエリパラメータを含めた URL は「http://localhost:8080/get?key1=value1&key2=value2」のように「?」でクエリパラメータを連結したような形式となります。この URL で GET リクエストを行うことで条件を指定したデータ取得が可能となります。
新しいリソースを作成する POST
サーバーに新しいリソースを作成するには、POST メソッドの HTTP リクエストを送信します。
import json
import urllib.request
# httpbin へアクセスする場合は以下を有効化
# url = "https://httpbin.org/post"
# Docker 環境で実行する場合は以下を有効化
url = "http://localhost:8080/post"
# 登録データの作成
payload = {"name": "Taro", "age": 30}
payload = json.dumps(payload).encode("utf-8")
# ヘッダーの設定
headers = {"Content-Type": "application/json"}
# リクエストの作成
request = urllib.request.Request(
url,
data=payload,
headers=headers,
method="POST",
)
with urllib.request.urlopen(request) as r:
# 応答ボディの取得
raw_data = r.read()
# ステータスコード
print(f"[status_code]:\n{r.status} {r.reason}\n")
# ヘッダー
print(f"[headers]:\n{r.getheaders()}\n")
# 応答の生データ(バイナリ)
print(f"[content]:\n{raw_data}\n")
# 応答の文字列形式
print(f"[text]:\n{raw_data.decode('utf-8')}\n")
# 応答のJSON形式
print(f"[json]:\n{json.loads(raw_data.decode('utf-8'))}\n")【実行結果】(text部分のみ表示)
[text]:
{
"args": {},
"data": "{\"name\": \"Taro\", \"age\": 30}",
"files": {},
"form": {},
"headers": {
"Accept-Encoding": "identity",
"Connection": "close",
"Content-Length": "27",
"Content-Type": "application/json",
"Host": "localhost:8080",
"User-Agent": "Python-urllib/3.13"
},
"json": {
"age": 30,
"name": "Taro"
},
"origin": "xxx.xxx.xxx.xxx",
"url": "http://localhost:8080/post"
}登録したいデータの情報は、辞書で作成します。その後、json.dumps で JSON 形式に変換したうえで UTF-8 にエンコードしておきます。また、JSON 形式でデータを送るのでヘッダーの "Content-Type" に "application/json" を設定して用意します。
リクエストは、urllib.request.Request クラスを使用して必要な情報を設定します。POST のエンドポイントを設定した url、data 引数に登録するデータ、headers にヘッダー、method に "POST" を指定してインスタンスを生成します。
リクエストの送信では、urllib.request.urlopen に生成したリクエストのインスタンスを指定します。返却値のレスポンスからデータを取得する手順については、GET の場合と同様です。
近年のウェブアプリケーションや API では、JSON 形式でのデータのやり取りが一般的ですので、上記の方法が使えれば多くの場合問題ないかと思います。
ただし、HTML フォームからのデータ送信に使用される application/x-www-form-urlencoded 形式としてデータを送信する必要がある場合もあります。このような場合には、以下のようにします。登録データの生成やヘッダーの生成など異なる部分を中心に抜粋して紹介します。
import json
import urllib.request
import urllib.parse
(...途中省略...)
# 登録データの作成
payload = {"name": "Taro", "age": 30}
# URLエンコード形式に変換
payload = urllib.parse.urlencode(payload).encode("utf-8")
# ヘッダーの設定
headers = {"Content-Type": "application/x-www-form-urlencoded"}
# リクエストの作成
request = urllib.request.Request(
url,
data=payload,
headers=headers,
method="POST",
)
(...リクエスト・結果表示部は省略...)【実行結果】(text部分のみ表示)
[text]:
{
"args": {},
"data": "",
"files": {},
"form": {
"age": "30",
"name": "Taro"
},
"headers": {
"Accept-Encoding": "identity",
"Connection": "close",
"Content-Length": "16",
"Content-Type": "application/x-www-form-urlencoded",
"Host": "localhost:8080",
"User-Agent": "Python-urllib/3.13"
},
"json": null,
"origin": "xxx.xxx.xxx.xxx",
"url": "http://localhost:8080/post"
}異なる点は、送信するデータを作る際に urllib.pars.urlencode を使用する点です。ここで生成されるデータは「name=Taro&age=30」というような形式のデータです。また、ヘッダーの Content-Type には、"application/x-www-form-urlencoded"を指定します。なお、リクエストの生成方法は、JSON の場合と変わりません。
結果を見てみると JSON の時は、data や json のところにデータが入っていましたが、今回は form に設定値が入っている点が異なることが分かります。
サーバー側の実装によってどちらの形式も受け入れることがありますが、API のドキュメントで指定された形式に従うのがベストプラクティスです。API のドキュメントを確認し、適切なデータ形式でリクエストを行うようにしましょう。
以降の PUT、DELETE の例でも考え方は同様です。
指定されたリソースを更新する PUT
指定されたリソースを更新するには、PUT メソッドの HTTP リクエストを送信します。
import json
import urllib.request
# httpbin へアクセスする場合は以下を有効化
# url = "https://httpbin.org/put"
# Docker 環境で実行する場合は以下を有効化
url = "http://localhost:8080/put"
# 更新データの作成
data = {"name": "Miki", "age": 25}
data = json.dumps(data).encode("utf-8")
# ヘッダーの設定
headers = {"Content-Type": "application/json"}
# リクエストの作成
request = urllib.request.Request(
url,
data=data,
headers=headers,
method="PUT",
)
with urllib.request.urlopen(request) as r:
# 応答ボディの取得
raw_data = r.read()
# ステータスコード
print(f"[status_code]:\n{r.status} {r.reason}\n")
# ヘッダー
print(f"[headers]:\n{r.getheaders()}\n")
# 応答の生データ(バイナリ)
print(f"[content]:\n{raw_data}\n")
# 応答の文字列形式
print(f"[text]:\n{raw_data.decode('utf-8')}\n")
# 応答のJSON形式
print(f"[json]:\n{json.loads(raw_data.decode('utf-8'))}\n")【実行結果】(text部分のみ表示)
[text]:
{
"args": {},
"data": "{\"name\": \"Miki\", \"age\": 25}",
"files": {},
"form": {},
"headers": {
"Accept-Encoding": "identity",
"Connection": "close",
"Content-Length": "27",
"Content-Type": "application/json",
"Host": "localhost:8080",
"User-Agent": "Python-urllib/3.13"
},
"json": {
"age": 25,
"name": "Miki"
},
"origin": "xxx.xxx.xxx.xxx",
"url": "http://localhost:8080/put"
}PUT リクエストテストのエンドポイントを指定することや、リクエスト生成時の method に PUT を設定することを除いて、POST の場合と同じです。
指定されたリソースをサーバーから削除する DELETE
指定されたリソースをサーバーから削除するには、DELETE メソッドの HTTP リクエストを送信します。
import json
import urllib.request
# httpbin へアクセスする場合は以下を有効化
# url = "https://httpbin.org/delete"
# Docker 環境で実行する場合は以下を有効化
url = "http://localhost:8080/delete"
# 削除データの指定
data = {"id": 123}
data = json.dumps(data).encode("utf-8")
# ヘッダーの設定
headers = {"Content-Type": "application/json"}
# リクエストの作成
request = urllib.request.Request(
url,
data=data,
headers=headers,
method="DELETE",
)
with urllib.request.urlopen(request) as r:
# 応答ボディの取得
raw_data = r.read()
# ステータスコード
print(f"[status_code]:\n{r.status} {r.reason}\n")
# ヘッダー
print(f"[headers]:\n{r.getheaders()}\n")
# 応答の生データ(バイナリ)
print(f"[content]:\n{raw_data}\n")
# 応答の文字列形式
print(f"[text]:\n{raw_data.decode('utf-8')}\n")
# 応答のJSON形式
print(f"[json]:\n{json.loads(raw_data.decode('utf-8'))}\n")【実行結果】(text部分のみ表示)
[text]:
{
"args": {},
"data": "{\"id\": 123}",
"files": {},
"form": {},
"headers": {
"Accept-Encoding": "identity",
"Connection": "close",
"Content-Length": "11",
"Content-Type": "application/json",
"Host": "localhost:8080",
"User-Agent": "Python-urllib/3.13"
},
"json": {
"id": 123
},
"origin": "xxx.xxx.xxx.xxx",
"url": "http://localhost:8080/delete"
}DELETE リクエストテストのエンドポイントを指定することや、リクエスト生成時の method に DELETE を設定することを除いて、POST や PUT の場合と同じです。
今回は、"id" を指定するような例で紹介しましたが、URL パスとして削除対象を指定する API や、DELETE でボディを受け付けないサーバーもありえます。API の仕様をよく確認して使用してください。
まとめ
Python における HTTP 接続のための標準ライブラリである urllib の基本的な使い方を解説します。
urllib を使用して基本的な GET / POST / PUT / DELETE のメソッドの HTTP リクエストを作成しサーバーとやり取りする方法を例を使って紹介しています。
Python では、requests がデファクトスタンダートの位置づけですが、外部ライブラリに依存しないように開発したい場合には、urllib が使用できます。
WEB 関連開発において HTTP リクエストとレスポンスの扱いについては基本的なものですので、使い方の基本をしっかり理解してもらえたらと思います。
上記で紹介しているソースコードについては GitHub にて公開しています。参考にしていただければと思います。

