The de-facto HTTP client for Python — a clean, high-level API for talking to web servers and REST APIs during testing and automation.
requests wraps the messy urllib stack behind a simple, readable interface for GET/POST/PUT/DELETE, sessions, cookies, headers, and TLS. It is the workhorse of most web-security tooling: fuzzers, API clients, login scripts, and reconnaissance helpers are almost always built on top of it. For any authorized web-application assessment, it lets you script requests exactly the way a browser or client would.
pip install requestsimport requests
response = requests.get("https://httpbin.org/get", timeout=10)
print(response.status_code) # 200
print(response.headers["Content-Type"])
print(response.json()) # parsed JSON body
print(response.text[:40]) # raw body as strEvery call takes a timeout. Without one, a request can block forever.
| API | Purpose |
|---|---|
requests.get/post/put/delete(url, ...) |
One-off requests |
requests.Session() |
Connection pooling, persistent cookies and headers |
response.status_code |
HTTP status as an int |
response.text / .content |
Body as str / bytes |
response.json() |
Parsed JSON; raises on invalid JSON |
response.headers |
Case-insensitive header mapping |
response.raise_for_status() |
Raise HTTPError on 4xx/5xx |
response.history |
Redirect chain that led here |
timeout=, allow_redirects=, verify=, proxies= |
Per-request controls |
requests.RequestException |
Base class for every error this library raises |
Simple GET with custom headers and a timeout:
import requests
resp = requests.get(
"https://httpbin.org/get",
headers={"User-Agent": "recon-scanner/1.0"},
timeout=10,
)
print(resp.status_code)
print(resp.headers.get("Server"))
print(resp.json()["headers"]["User-Agent"])200
gunicorn/19.9.0
recon-scanner/1.0
Persisting cookies and auth across requests with a Session:
import requests
session = requests.Session()
session.headers.update({"User-Agent": "authorized-test/1.0"})
# Authenticate once; the session keeps the cookie for later calls.
session.post("https://httpbin.org/cookies/set/token/abc123")
resp = session.get("https://httpbin.org/cookies")
print(resp.json()){'cookies': {'token': 'abc123'}}
Probing a list of paths on an authorized target and reporting live endpoints:
import requests
BASE = "https://httpbin.org"
paths = ["/get", "/status/404", "/status/500", "/headers"]
for path in paths:
try:
r = requests.get(BASE + path, timeout=5)
print(f"{r.status_code} {path}")
except requests.RequestException as exc:
print(f"ERR {path} ({exc})")200 /get
404 /status/404
500 /status/500
200 /headers
- Web-application testing — script logins, replay requests, and manipulate parameters/headers to test for IDOR, auth bypass, and injection on systems you are authorized to assess.
- API assessment — build lightweight clients that send crafted JSON bodies and inspect responses, status codes, and rate-limit headers.
- Directory / endpoint discovery — iterate a wordlist of paths and flag
200/302/403responses to map an application's surface. - OSINT & data collection — pull public pages, JSON feeds, and certificate-transparency or WHOIS APIs for passive recon.
- Health / regression monitoring — verify that hardening changes (security headers, redirects to HTTPS) actually took effect.
Warning
Only send automated traffic to hosts you own or have written authorization to test. High request rates against third-party services can constitute abuse.
- Omitting
timeout=— the single most common mistake; a request without one can hang a scanner indefinitely. - Setting
verify=Falseto silence a certificate error, which disables the protection TLS provides. - Catching bare
Exceptioninstead ofrequests.RequestException. - Assuming
response.json()succeeds — an HTML error page raisesjson.JSONDecodeError. - Not checking the status code —
requestsdoes not raise on 404 or 500 unless you callraise_for_status(). - Creating a new
Sessionper request, losing connection pooling entirely. - Retrying a 401 or 400 — those will never succeed.
- Logging the
Authorizationheader, leaking the token.
[!warning] Authorized use only Only send automated traffic to hosts you own or have written authorization to test. High request rates against third-party services can constitute abuse.
- Never disable certificate verification.
verify=Falsemakes credentials and data readable to anyone who can intercept the connection. If a lab uses a private CA, pass its bundle viaverify="/path/to/ca.pem". - Redirects can leak credentials. By default
requestsfollows redirects; a redirect to another host can forward headers. Setallow_redirects=Falsewhen sending secrets, and inspectresponse.history. - Treat every response as untrusted input. Never
eval()a body or pass it unescaped into a shell, SQL query, or HTML template. - Keep
requestsandurllib3current — both ship security fixes. - Set an identifying
User-Agentduring an authorized test so the target's operators can attribute the traffic. - Rate-limit deliberately. Concurrency multiplies load; an unthrottled loop is indistinguishable from an attack.
- Always set an explicit
timeout=— a missing timeout can hang a scanner indefinitely. - Reuse a
Sessionfor many requests to the same host to benefit from connection pooling and shared cookies. - Catch
requests.RequestException(the base class) rather than individual errors. - Never disable TLS verification (
verify=False) against real targets; if a lab requires it, scope it narrowly and expect theInsecureRequestWarning. - Read
resp.raise_for_status()when you want non-2xx responses to become exceptions.
- [[BeautifulSoup]] — parse the HTML that
requestsfetches - [[Selenium]] — when a target needs a full JavaScript-rendering browser
- [[Readme|Python for Security Professionals]] — course home