Python | Web / API:requests.post

Python Python
スポンサーリンク

概要(requests.postは「サーバへデータを送る」ための最短ルート)

requests.postは、フォーム送信やJSONの投稿、ファイルアップロードなど「データをサーバへ渡す」場面で使います。重要なのは「ボディの作り方(form か JSON か)」「ヘッダーの指定」「タイムアウトと例外処理」「レスポンスの検証(ステータスと内容)」の4点です。まずは成功可否のチェックを型にし、用途に応じてボディの形式を正しく選べば、初心者でも安全にAPIとやり取りできます。


基本の使い方(ここが重要)

最短のPOSTと成功可否の確認

# pip install requests
import requests

url = "https://httpbin.org/post"
resp = requests.post(url, data={"name": "Taro", "age": "25"}, timeout=5)

print(resp.status_code)  # 200なら成功
resp.raise_for_status()  # 失敗(4xx/5xx)を例外にする
print(resp.text[:200])   # 応答の先頭だけ確認
Python

status_codeでざっくり確認し、raise_for_statusで失敗を見落とさない型にします。timeoutは必ず付けて「待ちすぎ」を防ぎます。

JSONボディの投稿(APIの最頻パターン)

import requests

payload = {"user": "taro", "score": 88}
resp = requests.post("https://httpbin.org/post", json=payload, timeout=5)
resp.raise_for_status()

data = resp.json()  # 応答がJSONなら辞書として受け取れる
print(data["json"])  # サーバ側が受け取ったJSONの確認
Python

json=… を使うと Content-Type: application/json が自動で付き、辞書をそのまま送れます。APIは基本的にこの形式が多いです。

フォーム(x-www-form-urlencoded)投稿

import requests

form = {"username": "taro", "password": "secret"}
resp = requests.post("https://httpbin.org/post", data=form, timeout=5)
resp.raise_for_status()
print(resp.json()["form"])
Python

Webフォームと同じ形式。ブラウザの通常のPOST送信に近い挙動になります。


ファイルアップロード(multipart/form-data)

単一ファイルを送る

import requests

with open("avatar.png", "rb") as f:
    files = {"file": ("avatar.png", f, "image/png")}
    resp = requests.post("https://httpbin.org/post", files=files, timeout=10)
    resp.raise_for_status()
    print(resp.json()["files"])  # サーバ側が受け取ったファイル
Python

files=… を使うと自動で multipart/form-data になります。タプルで(ファイル名, ファイルオブジェクト, MIMEタイプ)を渡すと親切です。

複数ファイル・フォーム値の同時送信

import requests

data = {"user": "taro"}
files = [
    ("docs", ("spec.pdf", open("spec.pdf", "rb"), "application/pdf")),
    ("docs", ("plan.txt", open("plan.txt", "rb"), "text/plain")),
]
resp = requests.post("https://httpbin.org/post", data=data, files=files, timeout=20)
resp.raise_for_status()
print(resp.json()["form"], resp.json()["files"])
Python

同じフィールド名で複数ファイルを送る場合はリストで渡します。ファイルを開いたら、可能ならwith文でクローズを忘れないようにします。


ヘッダー・認証・セッション

ヘッダー指定(認証や内容の宣言)

import requests

headers = {"Authorization": "Bearer YOUR_TOKEN", "Accept": "application/json"}
resp = requests.post("https://httpbin.org/post", json={"x": 1}, headers=headers, timeout=5)
resp.raise_for_status()
print(resp.json())
Python

APIではAuthorizationやAcceptがよく使われます。json=を使うとContent-Typeは自動設定されるので、重複指定は不要です。

セッションで接続・クッキーを使い回す

import requests

with requests.Session() as s:
    s.headers.update({"User-Agent": "MyClient/1.0"})
    s.post("https://httpbin.org/cookies/set/user/taro")
    r = s.post("https://httpbin.org/post", json={"hello": "world"}, timeout=5)
    r.raise_for_status()
    print(r.json())
Python

Sessionは認証とクッキーを維持し、複数回リクエストを効率化します。毎回同じヘッダーを足す手間も減ります。


タイムアウト・エラー・再試行(事故を防ぐ型)

代表的な例外の捕捉

import requests

try:
    r = requests.post("https://httpbin.org/status/500", json={"x": 1}, timeout=5)
    r.raise_for_status()
except requests.Timeout:
    print("タイムアウト")
except requests.ConnectionError:
    print("接続エラー")
except requests.HTTPError as e:
    print("HTTPエラー:", e)
except requests.RequestException as e:
    print("その他のリクエスト例外:", e)
Python

まずはTimeoutとHTTPError、ConnectionErrorを押さえ、最後にRequestExceptionで取りこぼしを防ぐのが基本です。

安全な自動リトライ(サーバ一時不調に備える)

import requests
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry

session = requests.Session()
retry = Retry(total=3, backoff_factor=0.5, status_forcelist=[500, 502, 503, 504])
adapter = HTTPAdapter(max_retries=retry)
session.mount("http://", adapter)
session.mount("https://", adapter)

resp = session.post("https://httpbin.org/status/503", json={"x": 1}, timeout=5)
print(resp.status_code)
Python

POSTは「非冪等(同じリクエストを再送すると副作用が重複し得る)」なので、再試行は「サーバが処理していない可能性が高い失敗」に絞るのが安全です。API設計で「idempotency-key」を導入しているサービスでは再試行がより安全になります。


レスポンスの扱い(内容・文字コード・バイナリ)

JSON応答を辞書で扱う

import requests

r = requests.post("https://httpbin.org/post", json={"q": "tokyo"}, timeout=5)
r.raise_for_status()
print(r.json())  # dictやlistで扱える
Python

json()で辞書化すれば、そのままキーアクセスや後続処理に渡せます。JSON以外の応答では例外が出ることがあるため、Content-Typeを確認してから使うと安心です。

テキストと文字化け対策、バイナリ

import requests

r = requests.post("https://httpbin.org/html", timeout=5)
r.encoding = r.apparent_encoding  # 推定文字コードで上書き
print(r.text[:100])               # テキストとして読む

rb = requests.post("https://httpbin.org/anything", data=b"\x00\x01\x02")
print(type(rb.content), len(rb.content))     # バイナリは content
Python

textは文字列、contentはバイナリ。文字化けするならencodingを明示します。


実務の型(OS連携・大きな送信・検証)

応答をファイルへ保存(画像やPDF)

import requests
from pathlib import Path

out = Path("downloads/resp.json")
out.parent.mkdir(parents=True, exist_ok=True)

r = requests.post("https://httpbin.org/post", json={"x": 1}, timeout=5)
r.raise_for_status()
out.write_text(r.text, encoding=r.encoding or "utf-8")
Python

Pathlibで保存先を確保し、テキストならwrite_text、バイナリならwrite_bytesを使います。

大きなファイルを送る(ストリーミング)

import requests

with open("bigdata.bin", "rb") as f:
    r = requests.post("https://httpbin.org/post", data=f, timeout=60)
    r.raise_for_status()
    print(r.status_code)
Python

巨大データはファイルオブジェクトを渡してストリーミング送信できます。サーバの受け入れ上限とタイムアウトを合わせて設定します。

HTTPS検証・プロキシ

import requests

# 証明書検証は基本True(既定のまま)
r = requests.post("https://httpbin.org/post", json={"x": 1}, timeout=5, verify=True)

# 社内プロキシ経由
proxies = {"https": "http://proxy.example:8080"}
r = requests.post("https://httpbin.org/post", json={"x": 1}, proxies=proxies, timeout=5)
Python

verify=Falseはセキュリティが下がるため原則避けます。必要なら信頼できる証明書を事前に設定します。


よくある落とし穴の回避

ボディ形式の取り違え

APIがJSONを要求しているのにdata=で送ると失敗します。JSONならjson=、フォームならdata=を使い分けます。

タイムアウト未指定で固まる

ネットワーク不調で待ち続ける事故を防ぐため、timeoutは常に付けます。通常は数秒、重い処理は長めに。

失敗の見落とし

status_codeだけの確認だと流れてしまうことがあります。raise_for_statusを必ず呼び、例外で検出します。

重複実行の危険(非冪等)

POSTは同じリクエストを再送すると「登録が二重」などになり得ます。再試行は慎重に、可能ならサーバのidempotency-keyや重複防止の仕組みを使います。


例題で身につける(定番から実務まで)

例題1:JSON投稿+応答検証

import requests

resp = requests.post("https://httpbin.org/post", json={"user": "taro", "score": 88}, timeout=5)
resp.raise_for_status()
print("OK:", resp.status_code)
print(resp.json()["json"])  # サーバが受け取ったJSON
Python

例題2:フォーム投稿+ヘッダー指定

import requests

form = {"username": "taro", "password": "secret"}
headers = {"Accept": "application/json"}
resp = requests.post("https://httpbin.org/post", data=form, headers=headers, timeout=5)
resp.raise_for_status()
print(resp.json()["form"])
Python

例題3:ファイルアップロード(multipart/form-data)

import requests

with open("avatar.png", "rb") as f:
    files = {"avatar": ("avatar.png", f, "image/png")}
    r = requests.post("https://httpbin.org/post", files=files, timeout=15)
    r.raise_for_status()
    print(r.json()["files"])
Python

例題4:Session+リトライで安定化

import requests
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry

session = requests.Session()
session.headers.update({"Authorization": "Bearer TOKEN"})
retry = Retry(total=3, backoff_factor=0.5, status_forcelist=[500, 502, 503, 504])
session.mount("https://", HTTPAdapter(max_retries=retry))

resp = session.post("https://httpbin.org/post", json={"ping": "pong"}, timeout=5)
resp.raise_for_status()
print(resp.json())
Python

まとめ

requests.postは「サーバへデータを送る」ための基本メソッドです。json=とdata=でボディ形式を正しく選び、ヘッダーを整え、timeoutとraise_for_statusで壊れない通信にする。ファイルはfilesでmultipartに、Sessionで認証やクッキーを維持、必要に応じて安全な再試行を組み合わせる。これらの型を押さえれば、初心者でも短く、確実なAPI連携が書けます。

タイトルとURLをコピーしました