Help us understand the problem. What is going on with this article?

Python の HTTP クライアントは urllib.request で十分

AWS Lambda が Python 3 に対応してからというもの Lambda Functions はだいたい Python 3 で書くようになったが、Lambda では外部モジュールに依存する関数を作ろうとすると一気に面倒臭さが増してしまう。1 そもそも Python は標準モジュールが充実していてよほど複雑なことをしなければ標準モジュールだけで済ませることができるのだから、極力外部モジュールに頼らない書き方ができるとより気軽に Lambda Function を書けるようになる。

例えば Python から HTTP API を利用する場合、何も考えずにすぐ requests などの便利な HTTP クライアントモジュールを入れてしまいがちだが、冷静になって考えると「その程度の用途なら urllib.request で十分では」と思うことは少なくない。

そこで今回は HTTP API を利用する場合の urllib.request の使い方についてまとめる。

GET リクエストを投げる

Request オブジェクトを作成し、urlopen に渡すことでリクエストが送信される。

import urllib.request

url = 'https://example.com/api/v1/resource'

req = urllib.request.Request(url)
with urllib.request.urlopen(req) as res:
    body = res.read()

urlopen で得られるレスポンスは http.client.HTTPResponse オブジェクト なので、レスポンスヘッダやステータスコードなどもこのオブジェクトから取得することができる。ただし HTTP ステータスコードが 4xx と 5xx の場合は urllib.error.HTTPError 例外が投げられるため、例外処理を書く必要がある。(後述)

QueryString でリクエストパラメータを送る

urllib.parse.urlencode を使って URL を組み立てる。

import urllib.request

url = 'https://example.com/api/v1/resource'
params = {
    'foo': 123,
}

req = urllib.request.Request('{}?{}'.format(url, urllib.parse.urlencode(params)))
with urllib.request.urlopen(req) as res:
    body = res.read()

POST リクエストを投げる

Request オブジェクト作成時に data パラメータを指定すると POST メソッドとしてリクエストが投げられる。

以下は Content-Type: application/json でデータを送信する例。

import json
import urllib.request

url = 'https://example.com/api/v1/resource'
data = {
    'foo': 123,
}
headers = {
    'Content-Type': 'application/json',
}

req = urllib.request.Request(url, json.dumps(data).encode(), headers)
with urllib.request.urlopen(req) as res:
    body = res.read()

PUT PATCH DELETE リクエストを投げる

Requestmethod パラメータを渡せば GET POST 以外のメソッドも利用できる。

req = urllib.request.Request(url, json.dumps(data).encode(), headers, method='PUT')

それ以外は「POST リクエストを投げる」と同様。

レスポンスの JSON を parse する

レスポンスオブジェクトをそのまま json.load に投げる。

import json
import urllib.request

url = 'https://example.com/api/v1/resource'

req = urllib.request.Request(url)
with urllib.request.urlopen(req) as res:
    body = json.load(res)

例外処理

urlopen は二種類の例外を投げる。

import urllib.request

url = 'https://example.com/api/v1/resource'

req = urllib.request.Request(url)
try:
    with urllib.request.urlopen(req) as res:
        body = res.read()
except urllib.error.HTTPError as err:
    print(err.code)
except urllib.error.URLError as err:
    print(err.reason)

注意点として HTTPErrorURLError のサブクラスであるため、両方を except したい場合は HTTPError を先に書く必要がある。

セッション (Cookie) を扱う

セッション (Cookie) を扱いたい場合2はかなりやり方が異なる。

import json
import urllib.request

# Cookie を扱える OpenerDirector オブジェクトを作る
opener = urllib.request.build_opener(urllib.request.HTTPCookieProcessor())

# ログインするための Request オブジェクトを組み立てる
url = 'https://example.com/login'
data = {
    'username': 'foo',
    'password': 'deadbeef',
}
headers = {
    'Content-Type': 'application/json',
}
req = urllib.request.Request(url, json.dumps(data).encode(), headers)

# urllib.request.urlopen ではなく opener.open を使ってリクエストを投げる
res = opener.open(req)
body = res.read()
res.close()

# 以降、opener.open を使った場合は Cookie が保持されている

ここまでやるくらいなら requests とかを使ってもいいのでは?と思うが。

補足

HTTP API を叩くための最低限の使い方についてまとめたが、より詳細な使い方については公式ドキュメントを読むと良い。


  1. どうしても外部モジュールを使う必要がある場合はこういうことをする https://qiita.com/hoto17296/items/a579c333a8690c96a56c 

  2. 例えば何らかの Web サービスにログインした上でページの情報を取得したい場合など 

hoto17296
ゆとりデータ分析マン
https://hoto.me/
churadata
沖縄で データ分析 / 機械学習 / Deep Learning をやっている会社です
https://churadata.okinawa/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした