The essentials
Quick reference
One focused task per row. Jump to the related section for complete, working examples.
| Use | Syntax | Examples |
|---|---|---|
| Open a URL | with urlopen(request, timeout=10) as response: body = response.read(1_000_001) | View examples |
| Build a request | request = Request(url, headers={'Accept': 'application/json'}, method='GET') | View examples |
| Inspect a response | status, final_url = response.status, response.geturl() | View examples |
| Decode a response body | text = body.decode(response.headers.get_content_charset() or 'utf-8') | View examples |
| Encode a query string | query = urlencode({'q': 'red fox', 'page': 2}) | View examples |
| Encode repeated parameters | query = urlencode({'tag': ['python', 'web']}, doseq=True) | View examples |
| Build a form POST | request = Request(url, data=urlencode(fields).encode('ascii'), method='POST') | View examples |
| Split a URL | parts = urlsplit(candidate) | View examples |
| Quote a path segment | segment = quote(user_value, safe='') | View examples |
| Resolve a relative URL | next_url = urljoin(base_url, relative_url) | View examples |
| Catch HTTP status errors | except HTTPError as error: status = error.code | View examples |
| Catch transport errors | except URLError as error: reason = error.reason | View examples |
| Create verified TLS settings | context = ssl.create_default_context() | View examples |
| Disable inherited proxies | opener = build_opener(ProxyHandler({})) | View examples |
| Keep a header off redirects | request.add_unredirected_header('Authorization', token) | View examples |
urllib provides a dependency-free HTTP/1.1 client plus URL parsing and encoding tools. Always set a finite timeout, retain certificate and hostname verification, bound response sizes, and treat user-controlled destinations as an SSRF boundary rather than merely checking that a string starts with https.
Step by step
Detailed examples
Create requests and consume bounded responses
Request makes method and headers explicit. urlopen is a context manager, but its timeout covers individual blocking operations rather than imposing a total deadline. A bare read can consume an arbitrarily large body, so enforce an application limit and reject a response when the sentinel byte proves it is too large.
from urllib.request import Request, urlopen
request = Request('data:text/plain;charset=utf-8,ready', headers={'Accept': 'text/plain'})
with urlopen(request, timeout=2) as response:
body = response.read(6)
charset = response.headers.get_content_charset() or 'utf-8'
print(response.geturl())
print(body.decode(charset)) data:text/plain;charset=utf-8,ready
readyEncode query parameters and form bodies
urlencode returns text. Append it after a question mark for a query, or encode it to ASCII bytes for a conventional form body. Use doseq=True for repeated parameters. This is not JSON or multipart encoding; choose the Content-Type and serialization expected by the server.
from urllib.parse import urlencode
query = urlencode({'q': 'red fox', 'tag': ['python', 'web']}, doseq=True)
body = urlencode({'name': 'Ada Lovelace', 'active': 'yes'}).encode('ascii')
print(query)
print(body) q=red+fox&tag=python&tag=web
b'name=Ada+Lovelace&active=yes'Parse URLs before crossing a trust boundary
urlsplit parses rather than validates. Before fetching user input, allowlist schemes, normalize and validate the hostname, reject embedded credentials, resolve DNS, and reject private, loopback, link-local, multicast, and reserved addresses. Revalidate every redirect destination to reduce SSRF and DNS-rebinding exposure. urljoin is unsafe for attacker-controlled references when the origin must remain fixed because //host and absolute URLs replace it.
from urllib.parse import parse_qs, quote, urlsplit
parts = urlsplit('https://example.test/search?q=red+fox&q=kit')
print((parts.scheme, parts.hostname, parts.path))
print(parse_qs(parts.query))
print(quote('reports/May 2026', safe='')) ('https', 'example.test', '/search')
{'q': ['red fox', 'kit']}
reports%2FMay%202026Handle status failures before transport failures
HTTPError subclasses URLError, so catch it first when status codes need separate handling. Keep diagnostics free of authorization data and untrusted response bodies. Define retry policy by method idempotency and failure type; urllib does not provide a complete retry, backoff, connection-pooling, or total-deadline policy for you.
from urllib.error import HTTPError, URLError
print(issubclass(HTTPError, URLError))
try:
raise URLError('offline')
except HTTPError:
print('http status')
except URLError as error:
print(error.reason) True
offlinePreserve TLS verification and control global behavior
HTTPS requests verify certificates and hostnames through a default SSLContext. Do not disable verification or use an unverified context to silence certificate failures; repair trust roots or provide a carefully scoped CA bundle. build_opener composes proxies, cookies, authentication, and redirect handlers. Prefer a local opener over install_opener, which mutates process-wide behavior. Never forward credentials to an untrusted redirect target.
import ssl
from urllib.request import ProxyHandler, build_opener
context = ssl.create_default_context()
opener = build_opener(ProxyHandler({}))
print(context.check_hostname)
print(context.verify_mode == ssl.CERT_REQUIRED)
print(type(opener).__name__) True
True
OpenerDirectorLocal code tester
Build an HTTP request without sending it
Encode a repeated query, construct a request, and inspect its normalized method and headers entirely offline.
Press Run to load Python locally.
Sources and further reading
References
Authoritative documentation used to verify and expand this cheat sheet.
- Python Software Foundationurllib.request — Extensible library for opening URLsdocs.python.org
- Python Software Foundationurllib.parse — Parse URLs into componentsdocs.python.org
- Python Software Foundationurllib.error — Exception classes raised by urllib.requestdocs.python.org
- Python Software Foundationssl — TLS/SSL wrapper for socket objectsdocs.python.org
Help us improve
Found a typo or missing example?
Tell us what would make this cheat sheet clearer, more complete, or more useful.



