Python › Python for Pentesters
Making your first HTTP request
This is where Python stops being a programming exercise and becomes a security tool. The requests library lets you send any HTTP request from code — and that one capability is the foundation of web testing, API work, recon, and automation. Everything here builds on the fundamentals you already have: requests and responses are objects, headers and JSON are dictionaries, you loop over targets and handle errors.
Install it first: pip install requests.
You'll learn to
- Send a GET request and read the response back
- Inspect the status, body, and headers of a reply
- Understand why this beats a browser for testing
Why requests matters
requests turns “send an HTTP request” into one readable line. It handles sockets, TLS, redirects, cookies, and encoding for you, so you can focus on what you’re testing.
Here’s the difference that matters: a browser and Burp show you one request at a time. requests in a loop sends thousands, with full programmatic control over every header, parameter, and body. That’s exactly what automation, fuzzing, and custom testing need.
Your first request
import requests
r = requests.get("https://example.com") # send a GET, get a Response object back
r.status_code # 200 — the HTTP status
r.text # the body as a string (HTML/text)
r.content # the body as raw bytes (for binary/files)
r.headers # response headers (a dict-like object)
r.headers["Server"] # one header value
r.url # the final URL (after any redirects)
r.cookies # cookies the server set
r.elapsed # how long the request took
A request returns a Response object that holds everything about the reply. Walk through the fields you’ll use most:
status_code— 200 OK, 403 Forbidden, 500 error. This is your first triage signal. A 403 where you expected nothing is interesting.text— the response body as a string, ready to search.headers— a dictionary. InspectServer,Content-Type, and the security headers.url— where you actually ended up after redirects.
Because the response is just an object with attributes, you read it exactly like the data structures you already learned.
The one thing beginners forget
# This can hang forever if the server never responds:
r = requests.get("https://slow.example.com")
# This gives up after 5 seconds — always do this:
r = requests.get("https://slow.example.com", timeout=5)
Why this is the whole game for web testing
# Set ANY header — spoof, forge, tamper:
headers = {"User-Agent": "recon/1.0", "X-Forwarded-For": "127.0.0.1"}
r = requests.get("https://example.com", headers=headers)
Checkpoint
You send a request and r.status_code is 403. What does that tell you, and why might it be worth investigating?
403 means Forbidden — the server knows the resource exists but won't serve it to you. It's interesting because it confirms something is there, and access-control gaps sometimes let you reach it another way (different method, header, or path).
Try it yourself
In a script, send a GET to a site you’re allowed to test (or https://httpbin.org/get). Print the status code, the Server header (if present), and the first 200 characters of r.text. Add a timeout. You’ve just written the core of a recon tool.
Summary
requests makes HTTP one line of Python. A request returns a Response object whose key fields are status_code (your first triage signal), text (the body), headers (a dict), and url (the final location). Always set a timeout. The real power is total control over every header, body, and method — across thousands of requests in a loop — which is exactly what a browser can’t give you.
Key takeaways
requests.get(url)returns a Response object you read by attribute.- Check
status_codefirst — it’s the fastest triage signal. - Always pass
timeout=so one slow host can’t freeze a scan. - Full control over headers, bodies, and methods is what makes this a testing tool.
Quick quiz
Next, you’ll send data with your requests — query parameters, custom headers, POST bodies, and JSON — which is everything you need to start testing APIs.