Getting data out of a response correctly, including encoding and JSON errors, is half of every HTTP task.
A Response gives you the body in three forms:
r.content: rawbytes. Use it for images, archives and any binary data.r.text: the body decoded tostrusingr.encoding, which Requests takes from theContent-Typeheader's charset. If the header has no charset, Requests guesses (fortext/*it defaults to ISO-8859-1 per the old HTTP spec). Setr.encoding = "utf-8"before readingr.textif you know better.r.json(): parses the body as JSON. If the body is not valid JSON (an HTML error page, an empty 204 response), it raisesrequests.exceptions.JSONDecodeError.
Headers live in r.headers, a case-insensitive dict: r.headers["content-type"] and r.headers["Content-Type"] are the same entry.
Other useful attributes:
r.url: the final URL after redirects.r.historylists the redirect responses that led there. Requests follows redirects automatically for all methods exceptHEAD; passallow_redirects=Falseto stop that.r.elapsed: atimedeltafrom sending the request until the response headers arrived.r.request: thePreparedRequestthat was actually sent, with its final URL, headers and body, which is great for debugging.r.reason: the status text, like"Not Found".r.cookies: cookies the server set.
Check the status before trusting the body: an error page parsed with r.json() is a common source of confusing exceptions.
Example
import requests
r = requests.get("https://httpbin.org/redirect/2", timeout=10)
print(r.status_code, r.url) # 200 https://httpbin.org/get
print([h.status_code for h in r.history]) # [302, 302]
print(r.headers["content-type"]) # application/json (case-insensitive)
print(type(r.content).__name__, type(r.text).__name__) # bytes str
print(r.request.method, r.request.url) # GET https://httpbin.org/get
html = requests.get("https://httpbin.org/html", timeout=10)
try:
html.json()
except requests.exceptions.JSONDecodeError:
print("not JSON") # not JSON
r2 = requests.get("https://httpbin.org/redirect/1", allow_redirects=False, timeout=10)
print(r2.status_code, r2.headers["Location"]) # 302 /getRemember
- content is bytes, text is decoded str, json() parses JSON
- headers is case-insensitive; url and history show redirects
- r.request shows exactly what was sent
Watch out for
- Reading r.text for binary data such as images; use r.content.