Python Image Download & Scraping: Tools and Proxy Solutions

Sarah Whitmore

Last edited on May 15, 2025
Last edited on May 15, 2025

Scraping Techniques

Getting Your Image Download Game On with Python

If you've dabbled in web scraping with Python, you're probably familiar with the Requests library for snagging HTML content. But its utility doesn't stop there! Ever needed to grab images programmatically? Turns out, Python has excellent tools for that too.

This guide will walk you through downloading images using Python, focusing on three popular libraries: Requests, urllib3, and wget. We'll also cover the crucial step of using proxies, like those offered by Evomi, to keep your scraping activities smooth and undetected when downloading images at scale.

Downloading Images Smoothly with Requests

Chances are, you might already be using Requests for your HTTP needs in Python. It's a fan favorite for a reason – powerful, intuitive, and widely adopted for interacting with web pages and APIs. While it doesn't have a specific "download image" function, grabbing image data is straightforward.

The process boils down to two simple steps:

  1. Use Requests to fetch the image file via its URL.

  2. Write the binary content received in the response to a local file.

Let's illustrate this. Imagine you want to download a cool book cover from the Books to Scrape sandbox, a great place to practice your scraping skills. Here’s the Python code to do just that.

First, make sure you have Requests imported:

import requests

Next, define the URL of the image you want to grab:

image_url = 'https://books.toscrape.com/media/cache/3e/f4/3ef4792c02b5163d0f95aaf4088cea2e.jpg'  # Example: The Black Maria cover

Now, use requests.get() to fetch the image data:

response = requests.get(image_url)
response.raise_for_status() # Good practice to check for request errors

Finally, open a file in binary write mode ('wb') and save the content:

with open('book_cover.jpg', 'wb') as file:
    file.write(response.content)

One small detail to watch out for: ensure the filename extension you use (like .jpg) matches the actual image format. Saving a PNG as a JPG, for instance, will likely result in a file that image viewers can't open. A neat trick is to extract the filename directly from the URL:

def get_filename_from_url(url):
    # Takes the part after the last '/'
    return url.split('/')[-1]

# Ensure the filename has the correct extension
filename = get_filename_from_url(image_url)
with open(filename, 'wb') as file:
    file.write(response.content)

This helps keep things organized and ensures your saved files are valid images.

Staying Under the Radar: Using Proxies with Requests

Downloading a single image is usually no big deal. But what if you need to scrape an entire gallery or catalog of images? Websites often monitor for high-volume requests from a single IP address, potentially flagging automated activity. This is where proxies become essential.

Proxies serve as intermediaries, routing your requests through different IP addresses. This masks your original IP and makes your scraping activity appear more like organic user traffic. Integrating proxies with Requests is refreshingly simple.

You'll need proxy credentials from a provider like Evomi. We offer various proxy types, including Residential Proxies, which use IPs from real devices, making them highly effective for avoiding detection. Evomi sources proxies ethically and provides reliable service, backed by Swiss quality standards. Plus, our competitive pricing starts as low as $0.49/GB for residential proxies.

To use an Evomi proxy (or any authenticated proxy) with Requests, you typically format the proxy URL like this: protocol://username:password@host:port.

First, set up your proxy details in a dictionary. Replace the placeholders with your actual Evomi credentials and the appropriate endpoint (e.g., rp.evomi.com for residential proxies and port 1000 for HTTP or 1001 for HTTPS):

# Example using Evomi Residential Proxies
evomi_proxies = {
    'http': 'http://your_username:your_password@rp.evomi.com:1000',
    'https': 'http://your_username:your_password@rp.evomi.com:1001',  # Or use HTTPS port if needed
}

Then, simply pass this dictionary to the proxies argument in your requests.get() call:

response = requests.get(image_url, proxies=evomi_proxies)
response.raise_for_status()

Now your image download request goes through the proxy! Want to test the waters? Evomi offers a completely free trial for Residential, Mobile, and Datacenter proxies, letting you experience the benefits firsthand.

Here's the complete script combining image download, filename extraction, and proxy usage with Requests:

import requests


def get_filename_from_url(url):
    # Takes the part after the last '/'
    if url:
        return url.split('/')[-1]
    return 'downloaded_image.jpg' # Fallback name


# --- Evomi Proxy Configuration ---
# Replace with your actual Evomi credentials and chosen proxy type endpoint/port
evomi_proxies = {
    'http': 'http://your_username:your_password@rp.evomi.com:1000',
    'https': 'http://your_username:your_password@rp.evomi.com:1001',
}
# --- End Configuration ---

image_url = 'https://books.toscrape.com/media/cache/3e/f4/3ef4792c02b5163d0f95aaf4088cea2e.jpg'

try:
    print(f"Attempting to download {image_url} via proxy...")
    response = requests.get(
        image_url,
        proxies=evomi_proxies,
        timeout=10 # Good practice to add a timeout
    )
    response.raise_for_status() # Check for HTTP errors
    filename = get_filename_from_url(image_url)
    print(f"Success! Saving image as {filename}...")
    with open(filename, 'wb') as file:
        file.write(response.content)
    print("Download complete.")
except requests.exceptions.RequestException as e:
    print(f"An error occurred: {e}")

Tackling Image Downloads with Urllib3

Urllib3 is another powerful HTTP client library for Python. Fun fact: Requests actually uses urllib3 under the hood! While Requests often provides a higher-level, more user-friendly interface, urllib3 gives you fine-grained control and is a solid choice if it's already part of your toolkit.

Downloading an image with urllib3 follows a similar pattern. First, import the library:

import urllib3

Define your image URL:

# Example: It's Only the Himalayas
img_target_url = (
    'http://books.toscrape.com/media/cache/1b/5f/'
    '1b5f5aafc7290a276b193c2e13a7aa0b.jpg'
)

Create a PoolManager instance (standard practice in urllib3) and make the request:

http = urllib3.PoolManager()
res = http.request('GET', img_target_url)
# Check if the request was successful (status code 200)
if res.status == 200:
    # Proceed to save
    pass
else:
    print(f"Failed to download. Status code: {res.status}")

Assuming success, you can extract the filename (using our previous function or a similar one) and save the image data (accessed via res.data):

def get_filename_from_url(url):
    return url.split('/')[-1] if url else 'downloaded_image_urllib.jpg'

if res.status == 200:
    filename = get_filename_from_url(img_target_url)
    with open(filename, 'wb') as f:
        f.write(res.data)
    print(f"Image saved as {filename}")

Here’s the consolidated urllib3 download code:

import urllib3

def get_filename_from_url(url):
    return url.split('/')[-1] if url else 'downloaded_image_urllib.jpg'

img_target_url = 'http://books.toscrape.com/media/cache/1b/5f/1b5f5aafc7290a276b193c2e13a7aa0b.jpg'

try:
    http = urllib3.PoolManager()
    print(f"Attempting to download {img_target_url} with urllib3...")
    res = http.request('GET', img_target_url, preload_content=False) # Use preload_content=False for potentially large files
    if res.status == 200:
        filename = get_filename_from_url(img_target_url)
        print(f"Success! Saving image as {filename}...")
        with open(filename, 'wb') as f:
            # Stream data if needed, or write directly for smaller images
            f.write(res.read()) # Read the data
        print("Download complete.")
    else:
        print(f"Failed to download. Status code: {res.status}")
    res.release_conn() # Important to release connection
except urllib3.exceptions.MaxRetryError as e:
    print(f"Network error: {e}")
except Exception as e:
    print(f"An unexpected error occurred: {e}")

Configuring Proxies with Urllib3

Just like with Requests, large-scale image scraping using urllib3 benefits greatly from proxies. Setting up authenticated proxies in urllib3 requires a slightly more manual approach compared to Requests.

You'll need your proxy credentials from your provider (like Evomi):

  • Proxy host and port (e.g., rp.evomi.com:1000 for Evomi Residential HTTP).

  • Your proxy username.

  • Your proxy password.

You can find these details in your Evomi user dashboard after signing up.

First, create the necessary proxy authorization headers using urllib3.make_headers(). Remember to replace 'your_username:your_password' with your actual credentials.

proxy_auth_headers = urllib3.make_headers(
    proxy_basic_auth='your_username:your_password'
)

Next, instead of a standard PoolManager, create a ProxyManager instance. Pass your proxy URL (e.g., 'http://rp.evomi.com:1000') and the authorization headers.

# Example using Evomi Residential Proxy (HTTP)
proxy_url = 'http://rp.evomi.com:1000'
proxy_manager = urllib3.ProxyManager(
    proxy_url,
    proxy_headers=proxy_auth_headers
)

Now, use this proxy_manager object to make your requests. The rest of the code (making the request, handling the response, saving the file) remains largely the same.

# Make the request through the proxy manager
img_target_url = 'http://books.toscrape.com/media/cache/1b/5f/1b5f5aafc7290a276b193c2e13a7aa0b.jpg'
res = proxy_manager.request('GET', img_target_url)
# ... (rest of the file saving logic as before) ...

Here’s the full script demonstrating urllib3 image download via an authenticated Evomi proxy:

import urllib3

def get_filename_from_url(url):
    return url.split('/')[-1] if url else 'downloaded_image_urllib_proxy.jpg'

# --- Evomi Proxy Configuration ---
# Replace with your actual credentials and chosen proxy endpoint/port
proxy_username = 'your_username'
proxy_password = 'your_password'
proxy_host_port = 'rp.evomi.com:1000' # Example: Residential HTTP endpoint
proxy_url = f'http://{proxy_host_port}'
# --- End Configuration ---

img_target_url = 'http://books.toscrape.com/media/cache/1b/5f/1b5f5aafc7290a276b193c2e13a7aa0b.jpg'

try:
    print(f"Configuring proxy manager for {proxy_url}...")
    proxy_auth_headers = urllib3.make_headers(
        proxy_basic_auth=f'{proxy_username}:{proxy_password}'
    )
    proxy_manager = urllib3.ProxyManager(
        proxy_url,
        proxy_headers=proxy_auth_headers
    )

    print(f"Attempting to download {img_target_url} via proxy...")
    # Use preload_content=False for potentially large files
    res = proxy_manager.request(
        'GET',
        img_target_url,
        preload_content=False,
        timeout=urllib3.Timeout(connect=5.0, read=10.0)
    )

    if res.status == 200:
        filename = get_filename_from_url(img_target_url)
        print(f"Success! Saving image as {filename}...")
        with open(filename, 'wb') as f:
            # Stream data if needed
            for chunk in res.stream(1024): # Read in chunks
                 f.write(chunk)
        print("Download complete.")
    else:
        print(f"Failed to download. Status code: {res.status}, Reason: {res.reason}")

    res.release_conn() # Important to release connection

except urllib3.exceptions.MaxRetryError as e:
    # This often indicates proxy connection issues (check credentials, host, port)
    print(f"Network or Proxy error: Could not connect to proxy or target URL. {e}")
except urllib3.exceptions.NewConnectionError as e:
    print(f"Connection error: {e}")
except Exception as e:
    print(f"An unexpected error occurred: {e}")

Simple Downloads with the Wget Library

For those who appreciate simplicity or are familiar with the classic Linux command-line tool, the wget Python library offers a straightforward way to download files, including images.

Using it is incredibly easy. First, install and import it:

# If not installed: pip install wget
import wget

Define the URL of the image:

image_file_url = (
    'https://books.toscrape.com/media/cache/95/84/'
    '95840dfd131104347a29300c3456a690.jpg'
)
# Example: The Light Between Oceans

And call the wget.download() function:

print(f"Downloading {image_file_url} using wget library...")
try:
    filename = wget.download(image_file_url)
    print(f"\nImage downloaded successfully as: {filename}")
except Exception as e:
    print(f"\nDownload failed: {e}")

That's it! The library handles opening the connection, downloading the data, and saving it to a file, usually inferring the filename from the URL automatically.

A Note on Proxies and the Wget Library

Here's a key limitation: the Python wget library itself does not have built-in support for using proxies. It's designed for simpler download tasks.

However, if you need proxy capabilities and like the wget *concept*, you can leverage the original command-line wget tool, which *does* support proxies extensively. You can execute command-line tools from within your Python script using the subprocess module. For details on configuring the command-line `wget` with proxies, check out our tutorial on setting up Wget with proxies. To learn how to call command-line utilities like `wget` from Python, this article provides a good starting point.

Wrapping Up: Choosing Your Image Download Tool

Downloading images with Python is quite manageable using libraries like Requests, urllib3, or wget. Requests often strikes the best balance between ease of use and functionality, especially with its straightforward proxy integration, making it a great starting point.

Urllib3 offers more granular control but requires a bit more setup, particularly for proxies. The wget library provides maximum simplicity for basic downloads but lacks direct proxy support in its Python implementation.

Regardless of the tool, remember that using reliable proxies, like those from Evomi, is crucial when downloading images at scale to avoid IP blocks and ensure your scraping projects run smoothly. Consider exploring options like ethically sourced residential or high-speed datacenter proxies depending on your specific needs.

Want a deeper dive into the Requests library and its capabilities for various web tasks beyond images? Take a look at our comprehensive guide to the Python Requests Library.

Getting Your Image Download Game On with Python

If you've dabbled in web scraping with Python, you're probably familiar with the Requests library for snagging HTML content. But its utility doesn't stop there! Ever needed to grab images programmatically? Turns out, Python has excellent tools for that too.

This guide will walk you through downloading images using Python, focusing on three popular libraries: Requests, urllib3, and wget. We'll also cover the crucial step of using proxies, like those offered by Evomi, to keep your scraping activities smooth and undetected when downloading images at scale.

Downloading Images Smoothly with Requests

Chances are, you might already be using Requests for your HTTP needs in Python. It's a fan favorite for a reason – powerful, intuitive, and widely adopted for interacting with web pages and APIs. While it doesn't have a specific "download image" function, grabbing image data is straightforward.

The process boils down to two simple steps:

  1. Use Requests to fetch the image file via its URL.

  2. Write the binary content received in the response to a local file.

Let's illustrate this. Imagine you want to download a cool book cover from the Books to Scrape sandbox, a great place to practice your scraping skills. Here’s the Python code to do just that.

First, make sure you have Requests imported:

import requests

Next, define the URL of the image you want to grab:

image_url = 'https://books.toscrape.com/media/cache/3e/f4/3ef4792c02b5163d0f95aaf4088cea2e.jpg'  # Example: The Black Maria cover

Now, use requests.get() to fetch the image data:

response = requests.get(image_url)
response.raise_for_status() # Good practice to check for request errors

Finally, open a file in binary write mode ('wb') and save the content:

with open('book_cover.jpg', 'wb') as file:
    file.write(response.content)

One small detail to watch out for: ensure the filename extension you use (like .jpg) matches the actual image format. Saving a PNG as a JPG, for instance, will likely result in a file that image viewers can't open. A neat trick is to extract the filename directly from the URL:

def get_filename_from_url(url):
    # Takes the part after the last '/'
    return url.split('/')[-1]

# Ensure the filename has the correct extension
filename = get_filename_from_url(image_url)
with open(filename, 'wb') as file:
    file.write(response.content)

This helps keep things organized and ensures your saved files are valid images.

Staying Under the Radar: Using Proxies with Requests

Downloading a single image is usually no big deal. But what if you need to scrape an entire gallery or catalog of images? Websites often monitor for high-volume requests from a single IP address, potentially flagging automated activity. This is where proxies become essential.

Proxies serve as intermediaries, routing your requests through different IP addresses. This masks your original IP and makes your scraping activity appear more like organic user traffic. Integrating proxies with Requests is refreshingly simple.

You'll need proxy credentials from a provider like Evomi. We offer various proxy types, including Residential Proxies, which use IPs from real devices, making them highly effective for avoiding detection. Evomi sources proxies ethically and provides reliable service, backed by Swiss quality standards. Plus, our competitive pricing starts as low as $0.49/GB for residential proxies.

To use an Evomi proxy (or any authenticated proxy) with Requests, you typically format the proxy URL like this: protocol://username:password@host:port.

First, set up your proxy details in a dictionary. Replace the placeholders with your actual Evomi credentials and the appropriate endpoint (e.g., rp.evomi.com for residential proxies and port 1000 for HTTP or 1001 for HTTPS):

# Example using Evomi Residential Proxies
evomi_proxies = {
    'http': 'http://your_username:your_password@rp.evomi.com:1000',
    'https': 'http://your_username:your_password@rp.evomi.com:1001',  # Or use HTTPS port if needed
}

Then, simply pass this dictionary to the proxies argument in your requests.get() call:

response = requests.get(image_url, proxies=evomi_proxies)
response.raise_for_status()

Now your image download request goes through the proxy! Want to test the waters? Evomi offers a completely free trial for Residential, Mobile, and Datacenter proxies, letting you experience the benefits firsthand.

Here's the complete script combining image download, filename extraction, and proxy usage with Requests:

import requests


def get_filename_from_url(url):
    # Takes the part after the last '/'
    if url:
        return url.split('/')[-1]
    return 'downloaded_image.jpg' # Fallback name


# --- Evomi Proxy Configuration ---
# Replace with your actual Evomi credentials and chosen proxy type endpoint/port
evomi_proxies = {
    'http': 'http://your_username:your_password@rp.evomi.com:1000',
    'https': 'http://your_username:your_password@rp.evomi.com:1001',
}
# --- End Configuration ---

image_url = 'https://books.toscrape.com/media/cache/3e/f4/3ef4792c02b5163d0f95aaf4088cea2e.jpg'

try:
    print(f"Attempting to download {image_url} via proxy...")
    response = requests.get(
        image_url,
        proxies=evomi_proxies,
        timeout=10 # Good practice to add a timeout
    )
    response.raise_for_status() # Check for HTTP errors
    filename = get_filename_from_url(image_url)
    print(f"Success! Saving image as {filename}...")
    with open(filename, 'wb') as file:
        file.write(response.content)
    print("Download complete.")
except requests.exceptions.RequestException as e:
    print(f"An error occurred: {e}")

Tackling Image Downloads with Urllib3

Urllib3 is another powerful HTTP client library for Python. Fun fact: Requests actually uses urllib3 under the hood! While Requests often provides a higher-level, more user-friendly interface, urllib3 gives you fine-grained control and is a solid choice if it's already part of your toolkit.

Downloading an image with urllib3 follows a similar pattern. First, import the library:

import urllib3

Define your image URL:

# Example: It's Only the Himalayas
img_target_url = (
    'http://books.toscrape.com/media/cache/1b/5f/'
    '1b5f5aafc7290a276b193c2e13a7aa0b.jpg'
)

Create a PoolManager instance (standard practice in urllib3) and make the request:

http = urllib3.PoolManager()
res = http.request('GET', img_target_url)
# Check if the request was successful (status code 200)
if res.status == 200:
    # Proceed to save
    pass
else:
    print(f"Failed to download. Status code: {res.status}")

Assuming success, you can extract the filename (using our previous function or a similar one) and save the image data (accessed via res.data):

def get_filename_from_url(url):
    return url.split('/')[-1] if url else 'downloaded_image_urllib.jpg'

if res.status == 200:
    filename = get_filename_from_url(img_target_url)
    with open(filename, 'wb') as f:
        f.write(res.data)
    print(f"Image saved as {filename}")

Here’s the consolidated urllib3 download code:

import urllib3

def get_filename_from_url(url):
    return url.split('/')[-1] if url else 'downloaded_image_urllib.jpg'

img_target_url = 'http://books.toscrape.com/media/cache/1b/5f/1b5f5aafc7290a276b193c2e13a7aa0b.jpg'

try:
    http = urllib3.PoolManager()
    print(f"Attempting to download {img_target_url} with urllib3...")
    res = http.request('GET', img_target_url, preload_content=False) # Use preload_content=False for potentially large files
    if res.status == 200:
        filename = get_filename_from_url(img_target_url)
        print(f"Success! Saving image as {filename}...")
        with open(filename, 'wb') as f:
            # Stream data if needed, or write directly for smaller images
            f.write(res.read()) # Read the data
        print("Download complete.")
    else:
        print(f"Failed to download. Status code: {res.status}")
    res.release_conn() # Important to release connection
except urllib3.exceptions.MaxRetryError as e:
    print(f"Network error: {e}")
except Exception as e:
    print(f"An unexpected error occurred: {e}")

Configuring Proxies with Urllib3

Just like with Requests, large-scale image scraping using urllib3 benefits greatly from proxies. Setting up authenticated proxies in urllib3 requires a slightly more manual approach compared to Requests.

You'll need your proxy credentials from your provider (like Evomi):

  • Proxy host and port (e.g., rp.evomi.com:1000 for Evomi Residential HTTP).

  • Your proxy username.

  • Your proxy password.

You can find these details in your Evomi user dashboard after signing up.

First, create the necessary proxy authorization headers using urllib3.make_headers(). Remember to replace 'your_username:your_password' with your actual credentials.

proxy_auth_headers = urllib3.make_headers(
    proxy_basic_auth='your_username:your_password'
)

Next, instead of a standard PoolManager, create a ProxyManager instance. Pass your proxy URL (e.g., 'http://rp.evomi.com:1000') and the authorization headers.

# Example using Evomi Residential Proxy (HTTP)
proxy_url = 'http://rp.evomi.com:1000'
proxy_manager = urllib3.ProxyManager(
    proxy_url,
    proxy_headers=proxy_auth_headers
)

Now, use this proxy_manager object to make your requests. The rest of the code (making the request, handling the response, saving the file) remains largely the same.

# Make the request through the proxy manager
img_target_url = 'http://books.toscrape.com/media/cache/1b/5f/1b5f5aafc7290a276b193c2e13a7aa0b.jpg'
res = proxy_manager.request('GET', img_target_url)
# ... (rest of the file saving logic as before) ...

Here’s the full script demonstrating urllib3 image download via an authenticated Evomi proxy:

import urllib3

def get_filename_from_url(url):
    return url.split('/')[-1] if url else 'downloaded_image_urllib_proxy.jpg'

# --- Evomi Proxy Configuration ---
# Replace with your actual credentials and chosen proxy endpoint/port
proxy_username = 'your_username'
proxy_password = 'your_password'
proxy_host_port = 'rp.evomi.com:1000' # Example: Residential HTTP endpoint
proxy_url = f'http://{proxy_host_port}'
# --- End Configuration ---

img_target_url = 'http://books.toscrape.com/media/cache/1b/5f/1b5f5aafc7290a276b193c2e13a7aa0b.jpg'

try:
    print(f"Configuring proxy manager for {proxy_url}...")
    proxy_auth_headers = urllib3.make_headers(
        proxy_basic_auth=f'{proxy_username}:{proxy_password}'
    )
    proxy_manager = urllib3.ProxyManager(
        proxy_url,
        proxy_headers=proxy_auth_headers
    )

    print(f"Attempting to download {img_target_url} via proxy...")
    # Use preload_content=False for potentially large files
    res = proxy_manager.request(
        'GET',
        img_target_url,
        preload_content=False,
        timeout=urllib3.Timeout(connect=5.0, read=10.0)
    )

    if res.status == 200:
        filename = get_filename_from_url(img_target_url)
        print(f"Success! Saving image as {filename}...")
        with open(filename, 'wb') as f:
            # Stream data if needed
            for chunk in res.stream(1024): # Read in chunks
                 f.write(chunk)
        print("Download complete.")
    else:
        print(f"Failed to download. Status code: {res.status}, Reason: {res.reason}")

    res.release_conn() # Important to release connection

except urllib3.exceptions.MaxRetryError as e:
    # This often indicates proxy connection issues (check credentials, host, port)
    print(f"Network or Proxy error: Could not connect to proxy or target URL. {e}")
except urllib3.exceptions.NewConnectionError as e:
    print(f"Connection error: {e}")
except Exception as e:
    print(f"An unexpected error occurred: {e}")

Simple Downloads with the Wget Library

For those who appreciate simplicity or are familiar with the classic Linux command-line tool, the wget Python library offers a straightforward way to download files, including images.

Using it is incredibly easy. First, install and import it:

# If not installed: pip install wget
import wget

Define the URL of the image:

image_file_url = (
    'https://books.toscrape.com/media/cache/95/84/'
    '95840dfd131104347a29300c3456a690.jpg'
)
# Example: The Light Between Oceans

And call the wget.download() function:

print(f"Downloading {image_file_url} using wget library...")
try:
    filename = wget.download(image_file_url)
    print(f"\nImage downloaded successfully as: {filename}")
except Exception as e:
    print(f"\nDownload failed: {e}")

That's it! The library handles opening the connection, downloading the data, and saving it to a file, usually inferring the filename from the URL automatically.

A Note on Proxies and the Wget Library

Here's a key limitation: the Python wget library itself does not have built-in support for using proxies. It's designed for simpler download tasks.

However, if you need proxy capabilities and like the wget *concept*, you can leverage the original command-line wget tool, which *does* support proxies extensively. You can execute command-line tools from within your Python script using the subprocess module. For details on configuring the command-line `wget` with proxies, check out our tutorial on setting up Wget with proxies. To learn how to call command-line utilities like `wget` from Python, this article provides a good starting point.

Wrapping Up: Choosing Your Image Download Tool

Downloading images with Python is quite manageable using libraries like Requests, urllib3, or wget. Requests often strikes the best balance between ease of use and functionality, especially with its straightforward proxy integration, making it a great starting point.

Urllib3 offers more granular control but requires a bit more setup, particularly for proxies. The wget library provides maximum simplicity for basic downloads but lacks direct proxy support in its Python implementation.

Regardless of the tool, remember that using reliable proxies, like those from Evomi, is crucial when downloading images at scale to avoid IP blocks and ensure your scraping projects run smoothly. Consider exploring options like ethically sourced residential or high-speed datacenter proxies depending on your specific needs.

Want a deeper dive into the Requests library and its capabilities for various web tasks beyond images? Take a look at our comprehensive guide to the Python Requests Library.

Getting Your Image Download Game On with Python

If you've dabbled in web scraping with Python, you're probably familiar with the Requests library for snagging HTML content. But its utility doesn't stop there! Ever needed to grab images programmatically? Turns out, Python has excellent tools for that too.

This guide will walk you through downloading images using Python, focusing on three popular libraries: Requests, urllib3, and wget. We'll also cover the crucial step of using proxies, like those offered by Evomi, to keep your scraping activities smooth and undetected when downloading images at scale.

Downloading Images Smoothly with Requests

Chances are, you might already be using Requests for your HTTP needs in Python. It's a fan favorite for a reason – powerful, intuitive, and widely adopted for interacting with web pages and APIs. While it doesn't have a specific "download image" function, grabbing image data is straightforward.

The process boils down to two simple steps:

  1. Use Requests to fetch the image file via its URL.

  2. Write the binary content received in the response to a local file.

Let's illustrate this. Imagine you want to download a cool book cover from the Books to Scrape sandbox, a great place to practice your scraping skills. Here’s the Python code to do just that.

First, make sure you have Requests imported:

import requests

Next, define the URL of the image you want to grab:

image_url = 'https://books.toscrape.com/media/cache/3e/f4/3ef4792c02b5163d0f95aaf4088cea2e.jpg'  # Example: The Black Maria cover

Now, use requests.get() to fetch the image data:

response = requests.get(image_url)
response.raise_for_status() # Good practice to check for request errors

Finally, open a file in binary write mode ('wb') and save the content:

with open('book_cover.jpg', 'wb') as file:
    file.write(response.content)

One small detail to watch out for: ensure the filename extension you use (like .jpg) matches the actual image format. Saving a PNG as a JPG, for instance, will likely result in a file that image viewers can't open. A neat trick is to extract the filename directly from the URL:

def get_filename_from_url(url):
    # Takes the part after the last '/'
    return url.split('/')[-1]

# Ensure the filename has the correct extension
filename = get_filename_from_url(image_url)
with open(filename, 'wb') as file:
    file.write(response.content)

This helps keep things organized and ensures your saved files are valid images.

Staying Under the Radar: Using Proxies with Requests

Downloading a single image is usually no big deal. But what if you need to scrape an entire gallery or catalog of images? Websites often monitor for high-volume requests from a single IP address, potentially flagging automated activity. This is where proxies become essential.

Proxies serve as intermediaries, routing your requests through different IP addresses. This masks your original IP and makes your scraping activity appear more like organic user traffic. Integrating proxies with Requests is refreshingly simple.

You'll need proxy credentials from a provider like Evomi. We offer various proxy types, including Residential Proxies, which use IPs from real devices, making them highly effective for avoiding detection. Evomi sources proxies ethically and provides reliable service, backed by Swiss quality standards. Plus, our competitive pricing starts as low as $0.49/GB for residential proxies.

To use an Evomi proxy (or any authenticated proxy) with Requests, you typically format the proxy URL like this: protocol://username:password@host:port.

First, set up your proxy details in a dictionary. Replace the placeholders with your actual Evomi credentials and the appropriate endpoint (e.g., rp.evomi.com for residential proxies and port 1000 for HTTP or 1001 for HTTPS):

# Example using Evomi Residential Proxies
evomi_proxies = {
    'http': 'http://your_username:your_password@rp.evomi.com:1000',
    'https': 'http://your_username:your_password@rp.evomi.com:1001',  # Or use HTTPS port if needed
}

Then, simply pass this dictionary to the proxies argument in your requests.get() call:

response = requests.get(image_url, proxies=evomi_proxies)
response.raise_for_status()

Now your image download request goes through the proxy! Want to test the waters? Evomi offers a completely free trial for Residential, Mobile, and Datacenter proxies, letting you experience the benefits firsthand.

Here's the complete script combining image download, filename extraction, and proxy usage with Requests:

import requests


def get_filename_from_url(url):
    # Takes the part after the last '/'
    if url:
        return url.split('/')[-1]
    return 'downloaded_image.jpg' # Fallback name


# --- Evomi Proxy Configuration ---
# Replace with your actual Evomi credentials and chosen proxy type endpoint/port
evomi_proxies = {
    'http': 'http://your_username:your_password@rp.evomi.com:1000',
    'https': 'http://your_username:your_password@rp.evomi.com:1001',
}
# --- End Configuration ---

image_url = 'https://books.toscrape.com/media/cache/3e/f4/3ef4792c02b5163d0f95aaf4088cea2e.jpg'

try:
    print(f"Attempting to download {image_url} via proxy...")
    response = requests.get(
        image_url,
        proxies=evomi_proxies,
        timeout=10 # Good practice to add a timeout
    )
    response.raise_for_status() # Check for HTTP errors
    filename = get_filename_from_url(image_url)
    print(f"Success! Saving image as {filename}...")
    with open(filename, 'wb') as file:
        file.write(response.content)
    print("Download complete.")
except requests.exceptions.RequestException as e:
    print(f"An error occurred: {e}")

Tackling Image Downloads with Urllib3

Urllib3 is another powerful HTTP client library for Python. Fun fact: Requests actually uses urllib3 under the hood! While Requests often provides a higher-level, more user-friendly interface, urllib3 gives you fine-grained control and is a solid choice if it's already part of your toolkit.

Downloading an image with urllib3 follows a similar pattern. First, import the library:

import urllib3

Define your image URL:

# Example: It's Only the Himalayas
img_target_url = (
    'http://books.toscrape.com/media/cache/1b/5f/'
    '1b5f5aafc7290a276b193c2e13a7aa0b.jpg'
)

Create a PoolManager instance (standard practice in urllib3) and make the request:

http = urllib3.PoolManager()
res = http.request('GET', img_target_url)
# Check if the request was successful (status code 200)
if res.status == 200:
    # Proceed to save
    pass
else:
    print(f"Failed to download. Status code: {res.status}")

Assuming success, you can extract the filename (using our previous function or a similar one) and save the image data (accessed via res.data):

def get_filename_from_url(url):
    return url.split('/')[-1] if url else 'downloaded_image_urllib.jpg'

if res.status == 200:
    filename = get_filename_from_url(img_target_url)
    with open(filename, 'wb') as f:
        f.write(res.data)
    print(f"Image saved as {filename}")

Here’s the consolidated urllib3 download code:

import urllib3

def get_filename_from_url(url):
    return url.split('/')[-1] if url else 'downloaded_image_urllib.jpg'

img_target_url = 'http://books.toscrape.com/media/cache/1b/5f/1b5f5aafc7290a276b193c2e13a7aa0b.jpg'

try:
    http = urllib3.PoolManager()
    print(f"Attempting to download {img_target_url} with urllib3...")
    res = http.request('GET', img_target_url, preload_content=False) # Use preload_content=False for potentially large files
    if res.status == 200:
        filename = get_filename_from_url(img_target_url)
        print(f"Success! Saving image as {filename}...")
        with open(filename, 'wb') as f:
            # Stream data if needed, or write directly for smaller images
            f.write(res.read()) # Read the data
        print("Download complete.")
    else:
        print(f"Failed to download. Status code: {res.status}")
    res.release_conn() # Important to release connection
except urllib3.exceptions.MaxRetryError as e:
    print(f"Network error: {e}")
except Exception as e:
    print(f"An unexpected error occurred: {e}")

Configuring Proxies with Urllib3

Just like with Requests, large-scale image scraping using urllib3 benefits greatly from proxies. Setting up authenticated proxies in urllib3 requires a slightly more manual approach compared to Requests.

You'll need your proxy credentials from your provider (like Evomi):

  • Proxy host and port (e.g., rp.evomi.com:1000 for Evomi Residential HTTP).

  • Your proxy username.

  • Your proxy password.

You can find these details in your Evomi user dashboard after signing up.

First, create the necessary proxy authorization headers using urllib3.make_headers(). Remember to replace 'your_username:your_password' with your actual credentials.

proxy_auth_headers = urllib3.make_headers(
    proxy_basic_auth='your_username:your_password'
)

Next, instead of a standard PoolManager, create a ProxyManager instance. Pass your proxy URL (e.g., 'http://rp.evomi.com:1000') and the authorization headers.

# Example using Evomi Residential Proxy (HTTP)
proxy_url = 'http://rp.evomi.com:1000'
proxy_manager = urllib3.ProxyManager(
    proxy_url,
    proxy_headers=proxy_auth_headers
)

Now, use this proxy_manager object to make your requests. The rest of the code (making the request, handling the response, saving the file) remains largely the same.

# Make the request through the proxy manager
img_target_url = 'http://books.toscrape.com/media/cache/1b/5f/1b5f5aafc7290a276b193c2e13a7aa0b.jpg'
res = proxy_manager.request('GET', img_target_url)
# ... (rest of the file saving logic as before) ...

Here’s the full script demonstrating urllib3 image download via an authenticated Evomi proxy:

import urllib3

def get_filename_from_url(url):
    return url.split('/')[-1] if url else 'downloaded_image_urllib_proxy.jpg'

# --- Evomi Proxy Configuration ---
# Replace with your actual credentials and chosen proxy endpoint/port
proxy_username = 'your_username'
proxy_password = 'your_password'
proxy_host_port = 'rp.evomi.com:1000' # Example: Residential HTTP endpoint
proxy_url = f'http://{proxy_host_port}'
# --- End Configuration ---

img_target_url = 'http://books.toscrape.com/media/cache/1b/5f/1b5f5aafc7290a276b193c2e13a7aa0b.jpg'

try:
    print(f"Configuring proxy manager for {proxy_url}...")
    proxy_auth_headers = urllib3.make_headers(
        proxy_basic_auth=f'{proxy_username}:{proxy_password}'
    )
    proxy_manager = urllib3.ProxyManager(
        proxy_url,
        proxy_headers=proxy_auth_headers
    )

    print(f"Attempting to download {img_target_url} via proxy...")
    # Use preload_content=False for potentially large files
    res = proxy_manager.request(
        'GET',
        img_target_url,
        preload_content=False,
        timeout=urllib3.Timeout(connect=5.0, read=10.0)
    )

    if res.status == 200:
        filename = get_filename_from_url(img_target_url)
        print(f"Success! Saving image as {filename}...")
        with open(filename, 'wb') as f:
            # Stream data if needed
            for chunk in res.stream(1024): # Read in chunks
                 f.write(chunk)
        print("Download complete.")
    else:
        print(f"Failed to download. Status code: {res.status}, Reason: {res.reason}")

    res.release_conn() # Important to release connection

except urllib3.exceptions.MaxRetryError as e:
    # This often indicates proxy connection issues (check credentials, host, port)
    print(f"Network or Proxy error: Could not connect to proxy or target URL. {e}")
except urllib3.exceptions.NewConnectionError as e:
    print(f"Connection error: {e}")
except Exception as e:
    print(f"An unexpected error occurred: {e}")

Simple Downloads with the Wget Library

For those who appreciate simplicity or are familiar with the classic Linux command-line tool, the wget Python library offers a straightforward way to download files, including images.

Using it is incredibly easy. First, install and import it:

# If not installed: pip install wget
import wget

Define the URL of the image:

image_file_url = (
    'https://books.toscrape.com/media/cache/95/84/'
    '95840dfd131104347a29300c3456a690.jpg'
)
# Example: The Light Between Oceans

And call the wget.download() function:

print(f"Downloading {image_file_url} using wget library...")
try:
    filename = wget.download(image_file_url)
    print(f"\nImage downloaded successfully as: {filename}")
except Exception as e:
    print(f"\nDownload failed: {e}")

That's it! The library handles opening the connection, downloading the data, and saving it to a file, usually inferring the filename from the URL automatically.

A Note on Proxies and the Wget Library

Here's a key limitation: the Python wget library itself does not have built-in support for using proxies. It's designed for simpler download tasks.

However, if you need proxy capabilities and like the wget *concept*, you can leverage the original command-line wget tool, which *does* support proxies extensively. You can execute command-line tools from within your Python script using the subprocess module. For details on configuring the command-line `wget` with proxies, check out our tutorial on setting up Wget with proxies. To learn how to call command-line utilities like `wget` from Python, this article provides a good starting point.

Wrapping Up: Choosing Your Image Download Tool

Downloading images with Python is quite manageable using libraries like Requests, urllib3, or wget. Requests often strikes the best balance between ease of use and functionality, especially with its straightforward proxy integration, making it a great starting point.

Urllib3 offers more granular control but requires a bit more setup, particularly for proxies. The wget library provides maximum simplicity for basic downloads but lacks direct proxy support in its Python implementation.

Regardless of the tool, remember that using reliable proxies, like those from Evomi, is crucial when downloading images at scale to avoid IP blocks and ensure your scraping projects run smoothly. Consider exploring options like ethically sourced residential or high-speed datacenter proxies depending on your specific needs.

Want a deeper dive into the Requests library and its capabilities for various web tasks beyond images? Take a look at our comprehensive guide to the Python Requests Library.

Author

Sarah Whitmore

Digital Privacy & Cybersecurity Consultant

About Author

Sarah is a cybersecurity strategist with a passion for online privacy and digital security. She explores how proxies, VPNs, and encryption tools protect users from tracking, cyber threats, and data breaches. With years of experience in cybersecurity consulting, she provides practical insights into safeguarding sensitive data in an increasingly digital world.

Like this article? Share it.
You asked, we answer - Users questions:
Is it legal to scrape and download images from any website using Python?+
How can I efficiently download very large image files in Python without running out of memory?+
What if the image URLs I need are loaded by JavaScript and not visible in the initial HTML source?+
How can I automatically rotate through different proxy IPs when downloading hundreds or thousands of images?+
Besides checking HTTP status codes, how can I programmatically verify that a downloaded file is actually a valid image?+

In This Article