Downloading an image in Python means making an HTTP request and writing the response body to a file as unchanged bytes. Open the destination in binary write mode (wb), not text mode. For a dependency-free one-off download, use urllib.request; for timeouts, streaming, and a more convenient API, use Requests.
The shortest standard-library solution
Python includes urllib.request, so no package installation is needed:
from urllib.request import urlretrieve
url = "https://example.com/image.jpg"
destination = "image.jpg"
urlretrieve(url, destination)
print(f"Saved {destination}")
urlretrieve() retrieves the URL and writes the result to the filename you provide. The file is still binary image data even though the URL ends in .jpg. A URL suffix does not guarantee that the server returned an image; an error page, redirect target, or another content type can be returned instead.
If fewer bytes arrive than the server’s Content-Length indicated, urlretrieve() can raise ContentTooShortError. Treat that as an incomplete download and retry or inspect the response rather than using the partial file.
#1 Best Overall
- Read Before You Buy — No Video Output: These adapters support charging and USB 2.0 data transfer, but cannot transmit video signals. Except for standard USB webcams (which use USB data only), they are not compatible with HDMI/DisplayPort cables, video-capable USB-C hubs, or docking stations with video output.
- Convert USB-A Ports to USB-C: Designed to connect USB-C earphones, cables, flash drives, card readers, and other USB-C accessories to standard USB-A ports. Plug-and-play with no drivers or software required.
- Aluminum Alloy Housing: Built with a sturdy aluminum alloy shell that aids in heat dissipation and protects against daily wear and scratches. Designed to maintain a stable and secure connection.
- Compact & Travel-Friendly: The ultra-compact design allows the adapter to stay plugged into your device without blocking adjacent ports or adding bulk, reducing wear and tear on your original USB ports.
- 12-Month Warranty: Backed by a 12-month manufacturer warranty for peace of mind. Designed to meet strict quality control standards for reliable everyday performance.
A robust download with Requests
Requests is useful when you need explicit timeouts, status checking, or streaming. Install it in the environment that runs your script:
python -m pip install requests
This example checks the HTTP result before creating the destination and writes the response incrementally:
import requests
url = "https://example.com/image.jpg"
destination = "image.jpg"
with requests.get(url, stream=True, timeout=30) as response:
response.raise_for_status()
with open(destination, "wb") as image_file:
for chunk in response.iter_content(chunk_size=8192):
if chunk:
image_file.write(chunk)
print(f"Saved {destination}")
stream=True prevents Requests from loading the entire body into memory at once. The loop writes each non-empty chunk to disk. The response context manager closes the response after the loop, returning the connection to Requests’ pool. This is the documented preferred pattern for streamed downloads.
Keep TLS certificate verification enabled (the default) unless you have a narrowly understood, controlled reason to change it. The timeout applies to waiting for network activity; it prevents a stalled server from hanging the script indefinitely. It is not a promise that the complete file will arrive within exactly 30 seconds.
Choosing between urllib and Requests
| Approach | Extra package | Best fit | Large responses |
|---|---|---|---|
urllib.request.urlretrieve |
None; included with Python | A compact, one-off download | Simple file retrieval, with less control in the example |
Requests with stream=True |
Requests | Timeouts, status checks, headers, authentication, and a readable request API | Incremental chunk writes |
Use the standard library when avoiding dependencies is important. Use Requests when you need the controls shown above or are downloading files whose size makes incremental writing desirable.
Rank #2
- 5-in-1 USB-C Hub: Experience comprehensive connectivity featuring a Power Delivery input, two USB-A 2.0 ports, a USB-A 3.0 port, and an HDMI port. (Note: The USB-C power delivery input port is only for connecting an external wall charger to power your laptop and cannot power peripheral devices.)
- 90W Pass-Through Charging: Achieve optimal charging with 90W pass-through power to your laptop, supported by a total input of 100W, with the hub reserving 10W for operational efficiency. (Note: Wall charger not included.)
- Quick Data Transfers: Accelerate your productivity with rapid data transfers using a high-speed 5Gbps USB 3.0 port and two 480Mbps USB 2.0 ports.
- 4K HDMI Display: Enhance your visual experience with a hub capable of delivering 4K resolution at 30Hz in both mirror and extend modes. Please note that this hub is compatible with MacBook (macOS 12 and newer), Windows 10 and 11, ChromeOS, and laptops equipped with DP Alt Mode and Power Delivery. Note: This device is not compatible with Linux.
- What You Get: Anker USB-C Hub (5-in-1, 4K HDMI), welcome guide, 18-month warranty, and our friendly customer service.
Saving safely and predictably
Always write bytes with wb
Image formats contain arbitrary byte values. Opening a destination with "w" treats data as text and can alter or reject it. Both examples use open(destination, "wb") so the response bytes are preserved exactly.
Create parent directories when needed
from pathlib import Path
import requests
url = "https://example.com/photo.png"
destination = Path("downloads") / "photo.png"
destination.parent.mkdir(parents=True, exist_ok=True)
with requests.get(url, stream=True, timeout=30) as response:
response.raise_for_status()
with destination.open("wb") as image_file:
for chunk in response.iter_content(8192):
if chunk:
image_file.write(chunk)
Use a temporary name for important files
Writing directly to the final name can leave a partial file if the process stops midway. For a workflow that must never expose an incomplete result, write to a temporary path in the same directory, then rename it only after the loop finishes. The basic recipe does not validate every possible image format or enforce a maximum size, so add those policies when your application accepts untrusted URLs.
Do not trust the URL extension
A server can return an HTML error document at a URL ending in .jpg. You can inspect the response’s Content-Type header as a useful indication of what the server claims to have sent, but a header alone is not complete content validation. If the downloaded data matters, parse it with an image library and handle invalid data.
Opening or processing the downloaded image with Pillow
Pillow is optional: you do not need it merely to save bytes. Install it when the next operation is opening, inspecting, resizing, converting, or otherwise processing the image:
python -m pip install Pillow
from PIL import Image
with Image.open("image.jpg") as image:
print(image.format, image.size, image.mode)
image.thumbnail((1200, 1200))
image.save("image-small.jpg")
Image.open() accepts a filename or path, and it can also accept a file-like object. That means you can process an in-memory stream when appropriate, although saving to disk first is often easier to inspect and retry.
Rank #3
- Sleek 7-in-1 USB-C Hub: Features an HDMI port, two USB-A 3.0 ports, and a USB-C data port, each providing 5Gbps transfer speeds. It also includes a USB-C PD input port for charging up to 100W and dual SD and TF card slots, all in a compact design.
- Flawless 4K@60Hz Video with HDMI: Delivers exceptional clarity and smoothness with its 4K@60Hz HDMI port, making it ideal for high-definition presentations and entertainment. (Note: Only the HDMI port supports video projection; the USB-C port is for data transfer only.)
- Double Up on Efficiency: The two USB-A 3.0 ports and a USB-C port support a fast 5Gbps data rate, significantly boosting your transfer speeds and improving productivity.
- Fast and Reliable 85W Charging: Offers high-capacity, speedy charging for laptops up to 85W, so you spend less time tethered to an outlet and more time being productive.
- What You Get: Anker USB-C Hub (7-in-1), welcome guide, 18-month warranty, and our friendly customer service.
Adding headers, cookies, or authentication
Some servers require a user agent, an authorization token, or a session cookie. Requests lets you pass these explicitly:
import requests
url = "https://example.com/private/image.jpg"
headers = {"User-Agent": "my-image-downloader/1.0"}
with requests.get(
url,
headers=headers,
cookies={"session": "YOUR_SESSION_COOKIE"},
timeout=30,
stream=True,
) as response:
response.raise_for_status()
with open("private-image.jpg", "wb") as image_file:
for chunk in response.iter_content(8192):
if chunk:
image_file.write(chunk)
Keep credentials out of source control and logs. Only download content you are authorized to access, and follow the site’s terms and applicable policies.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
Handling common failures
Timeouts
A timeout usually means the server or network did not respond within the interval. Increase the timeout for legitimately slow transfers, check connectivity, and retry with a bounded strategy rather than removing the timeout entirely.
HTTP errors
response.raise_for_status() turns an unsuccessful HTTP response into an exception before a file is saved. Check the URL, authentication, permissions, and server response. Do not assume that a file was downloaded merely because the request completed.
Incomplete urlretrieve output
ContentTooShortError indicates that fewer bytes arrived than expected from Content-Length. Delete or quarantine the partial file and retry. A server that omits Content-Length cannot be checked by that particular mechanism.
Rank #4
- Dual Converters, Infinite Potential:Includes 2× USB C male to USB A female adapters and 2× USB A male to USB C female adapters. Perfect for a wide range of uses—tablets with Bluetooth keyboards, expand USB ports on macbook, and more. Two different converters for all your daily needs
- Next-Level 10Gbps & 3A Charging: No more slow 480Mbps, this usb to usb c adapter has a transfer speed of up to 10Gbps, allowing you to do more transferring in less time. This usb adapter fits both USB A and USB C charger, supporting up to 3A fast charging
- Upgraded Exquisite Craftsmanship: With an aluminum alloy housing and metal connector, the usbc to usb adapter is extremely durable and sturdy. Rigorously tested to withstand more than 10,000 times of plugging and unplugging, ensuring long-lasting performance
- Broad Compatible: The usb c to usb adapter widely supports all USB C/ USB A devices like laptops, tablets, cellphones, car chargers, and phone chargers. Such as compatible with MacBook Pro/Air 2023/2022, Thunderbolt 4/3 Devices,Apple MagSafe Watch 9/8/7/SE/Ultra, iPad Pro 2022/2021, Samsung Galaxy S23/S20/S10, and iPhone 17/16/15 Pro. Plug and play
- Please Note: To reach 10Gbps speed, keep the cable under 3.3 ft. For USB A Male to USB C adapters, try flipping the USB C connector. USB C Male to USB A adapters support bidirectional 10Gbps transfer within 3.3 ft
SSL certificate errors
Certificate verification failures commonly indicate an outdated local certificate store, a misconfigured proxy, or a server certificate problem. Fix the environment or endpoint; disabling verification removes an important security check.
Permission denied
Choose a directory your process can write to, such as an application-specific downloads directory, and verify that the parent exists. On shared systems, avoid writing into protected system paths.
The saved file will not open
Inspect the HTTP status and Content-Type, then examine the first response bytes or let Pillow attempt to open the file. The server may have returned HTML, JSON, a login page, or truncated data instead of an image.
Performance and reliability considerations
- Stream large files: Requests’
iter_contentloop keeps memory use bounded relative to the response size. - Choose a chunk size: 8,192 bytes is a reasonable general starting point; measure your own workload before tuning it.
- Close every response: Use the context manager, or explicitly close a streamed response, so connections can be reused.
- Retry deliberately: Retry only errors that are plausibly transient, limit attempts, and avoid creating duplicate or partial final files.
- Control destinations: Sanitize names and define a maximum size when URLs or filenames come from users.
- Keep verification on: Retain TLS certificate verification and avoid logging secrets in headers, cookies, or query strings.
These practices improve a downloader, but they do not establish a complete security policy for arbitrary remote files. If your application handles untrusted input, define URL allowlists, size limits, format validation, and storage rules for your own threat model.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Or skip the browser setup
If your actual goal is obtaining a clean image of a web page rather than downloading an image file URL, ScreenshotNeo provides a website screenshot API and MCP server. One GET request returns PNG, JPEG, WebP, or PDF, without running your own browser:
Quick wins for a faster PC:
Scan for outdated or missing drivers - takes under a minuteDriver Scan →Clear out junk files and repair common Windows errorsFree Scan →Best Value
- 5-in-1 Connectivity: Equipped with a 4K HDMI port, a 5 Gbps USB-C data port, two 5 Gbps USB-A ports, and a USB C 100W PD-IN port. Note: The USB C 100W PD-IN port supports only charging and does not support data transfer devices such as headphones or speakers.
- Powerful Pass-Through Charging: Supports up to 85W pass-through charging so you can power up your laptop while you use the hub. Note: Pass-through charging requires a charger (not included). Note: To achieve full power for iPad, we recommend using a 45W wall charger.
- Transfer Files in Seconds: Move files to and from your laptop at speeds of up to 5 Gbps via the USB-C and USB-A data ports. Note: The USB C 5Gbps Data port does not support video output.
- HD Display: Connect to the HDMI port to stream or mirror content to an external monitor in resolutions of up to 4K@30Hz. Note: The USB-C ports do not support video output.
- What You Get: Anker 332 USB-C Hub (5-in-1), welcome guide, our worry-free 18-month warranty, and friendly customer service.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
See the ScreenshotNeo documentation for request options. Before capture, it accepts cookie or consent banners like a visitor and removes more than 60 known consent platforms, newsletter popups, and chat widgets; each cleanup step can be disabled. Bot checks or CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and response headers identify the page verdict and billing result. Its MCP server lets Claude, Cursor, and other MCP clients call take_screenshot, get_page_info, and capture_pdf. The Free plan includes 1,000 shots per month with no card; paid plans start at $5 for 3,000 shots. Create a free ScreenshotNeo account.
FAQ
Can I download an image without installing anything?
Yes. urllib.request is included in Python’s standard library. Install Requests or Pillow only when their additional capabilities are useful.
Should I use read() instead of streaming?
For a small, trusted response, reading all bytes can be simple. Streaming is safer for larger files because it writes incrementally instead of holding the complete body in memory.
Why does my downloaded “image” contain markup?
The URL may have returned an HTML error or login page. Check the status and content type, and validate the file with Pillow before processing it.
Free tools Windows power users keep installed
One-click scans. No signup required.
Does Python automatically know the correct image extension?
No. The destination name is yours to choose. The URL suffix can be misleading; use response metadata and, when necessary, an image parser to determine what was actually returned.
Frequently Asked Questions
Can I download an image without installing anything?
Yes. urllib.request is included in Python’s standard library. Install Requests or Pillow only when their additional capabilities are useful.
Should I use read() instead of streaming?
For a small, trusted response, reading all bytes can be simple. Streaming is safer for larger files because it writes incrementally instead of holding the complete body in memory.
Why does my downloaded “image” contain markup?
The URL may have returned an HTML error or login page. Check the status and content type, and validate the file with Pillow before processing it.
Do these 3 things before closing this tab:
1Clear out junk files and repair common Windows errors2Scan for outdated or missing drivers - takes under a minute3Repair Windows errors before they cause bigger problemsDoes Python automatically know the correct image extension?
No. The destination name is yours to choose. The URL suffix can be misleading; use response metadata and, when necessary, an image parser to determine what was actually returned.
Quick Recap
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.

