Use Python’s built-in urllib.request to save a URL without installing anything. If you want a higher-level HTTP interface or need to stream a large response in chunks, the third-party requests library is another practical option. The right choice depends on whether you value a minimal dependency or more HTTP conveniences.
Download a file with Python’s standard library
urllib.request is included with Python. For a straightforward download, urlretrieve saves the resource directly to the filename you provide:
from urllib.request import urlretrieve
url = "https://example.com/report.pdf"
filename, headers = urlretrieve(url, "report.pdf")
print(f"Saved to {filename}")
Replace the example URL and filename with the resource and destination you need. The destination can be a relative or absolute path; make sure the program has permission to write there. See the Python 3.11 urllib.request reference for the documented API.
Use urlopen when you want control over writing
urlopen returns a response that you can read and write to a file opened in binary mode. Using context managers closes both the response and the output file when the block ends:
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
#1 Best Overall
from urllib.request import urlopen
url = "https://example.com/report.pdf"
with urlopen(url) as response:
with open("report.pdf", "wb") as output:
output.write(response.read())
This simple version reads the response body before writing it, so it is not the pattern to choose for a very large file. The URL must identify a resource you are allowed to access. Some sites require authorization or particular request headers; there is no universal workaround for protected or browser-only downloads.
Use Requests for a higher-level HTTP interface
Requests is a third-party library, so install it separately, for example with python -m pip install requests. Its stable documentation reports Requests 2.34.2 and support for Python 3.10 and later. Use a response context manager, check for an unsuccessful HTTP status before saving, and write the response body in binary mode:
Rank #2
import requests
url = "https://example.com/report.pdf"
with requests.get(url, timeout=30) as response:
response.raise_for_status()
with open("report.pdf", "wb") as output:
output.write(response.content)
The timeout shown is an example setting, not a universally correct value. Choose one appropriate to your application and the expected server response. Checking the HTTP status prevents treating an error response as a successful download, but it does not by itself prove that the saved file is complete or valid.
Stream a large download in chunks
For a large response, avoid holding the entire body in memory. Requests documents stream=True and iter_content for reading incrementally; write each non-empty chunk to a binary file:
Windows Errors? Fix Them Before They Spread
Repair common Windows errors and clear accumulated junk for a smoother, more stable PC - no reinstall needed.Free scan · no reinstallOutdated Drivers Are Slowing You Down
One free scan finds every outdated or missing driver and matches the right update for your exact hardware.Free scan · exact hardware matchimport requests
url = "https://example.com/archive.zip"
chunk_size = 8192 # Example size; choose for your application.
with requests.get(url, stream=True, timeout=30) as response:
response.raise_for_status()
with open("archive.zip", "wb") as output:
for chunk in response.iter_content(chunk_size=chunk_size):
if chunk:
output.write(chunk)
The context manager closes the response when the block exits. A streamed response should be fully consumed or closed so its connection can be released; this matters especially if an error or early exit means the loop does not finish. The Requests advanced usage documentation describes streaming and response cleanup.
Choose between urllib.request and Requests
| Method | Dependency | Useful when | Control and caveats |
|---|---|---|---|
urlretrieve |
Python standard library | You want a direct save-to-file call. | Minimal code; may raise ContentTooShortError if the downloaded amount is less than the expected size reported by Content-Length. |
urlopen |
Python standard library | You want to read a response and decide how to write it. | More control than the direct save helper; reading the whole body at once can use substantial memory for a large file. |
Requests with stream=True |
Install Requests separately | You want its higher-level HTTP interface or incremental chunk writes. | Check the response status and consume or close streamed responses to release the connection. |
Handle incomplete downloads and validate the file
HTTP status handling and file validation answer different questions: a successful status does not guarantee that the content is complete or is the file format you expected. Python documents that urlretrieve can raise ContentTooShortError when fewer bytes arrive than the expected size reported by Content-Length. That header is not guaranteed to be present, and matching it alone does not establish file integrity.
If a publisher provides an authoritative checksum, compare the downloaded file against it when correctness matters. Otherwise, use checks suited to the file and task, such as opening it with the expected application or validating its structure. If a transfer fails, do not assume the destination file is usable; remove or replace the partial file before retrying so incomplete bytes are not mistaken for a finished download.
Quick Recap
Best Value
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.




