How to save an image locally using Python whose URL address I already know?
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
Downloading an image from a known URL in Python is mostly a matter of making an HTTP request and writing the response bytes to disk. The reliable version of that workflow adds three extra concerns: checking the HTTP status, choosing a sensible filename, and streaming the file instead of loading everything into memory at once.
Use requests and Save the Response in Chunks
The requests library is a good default for this task because it makes the HTTP part explicit and easy to debug. A chunked download is usually better than writing response.content directly, especially for larger files.
This example is safe for typical cases because it creates the destination folder, fails fast on HTTP errors, and keeps memory use predictable.
Pick the Filename Deliberately
If the image URL already ends with a usable filename, you can save it directly. If not, derive the name yourself instead of trusting the URL blindly. Query strings, redirects, and CDN URLs often make the original path useless as a filename.
Here is a small helper that uses the last path segment when available:
You can combine that helper with the download code:
That gives you a predictable save location even when the input URL is messy.
Validate the Response Looks Like an Image
If the URL is wrong, some servers return an HTML error page with status 200, which means your code may save a .png file that is actually markup. Checking the Content-Type header can catch that.
This is not perfect because servers can lie about headers, but it prevents a surprising number of bad downloads.
A Minimal Version Without requests
If you want to avoid third-party packages, the standard library can also download a file. The tradeoff is that it gives you less ergonomic HTTP handling than requests.
This version is fine for simple scripts, but for production code requests is usually easier to extend with timeouts, retries, and header checks.
Add a User-Agent or Timeout When Servers Are Picky
Some sites reject requests that look like generic bots or hang longer than you expect. A timeout is almost always worth adding, and a User-Agent header can help with servers that treat anonymous clients differently.
These details matter more in scheduled jobs than in throwaway scripts.
Common Pitfalls
The most common mistake is writing response.content straight to disk without checking raise_for_status, which silently saves error pages when the download fails. Another frequent issue is trusting the URL to contain a good filename even though many image endpoints are query-based or redirect through CDNs. Developers also forget to open the output file in binary mode, which corrupts image data on some systems. Finally, large downloads should not be read all at once when a chunked stream is easy to implement.
Summary
- Use
requests.get(..., stream=True)and write the response in chunks. - Call
raise_for_status()so HTTP failures do not become broken files on disk. - Choose the output filename deliberately instead of assuming the URL path is clean.
- Check
Content-Typeif you want to reject non-image responses early. - The standard library works too, but
requestsis usually the better default for real scripts.

