Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Python does not include GNU Wget. To automate Wget downloads, install the wget executable on the machine that runs your script, then launch it with Python’s built-in subprocess.run(). The three useful patterns are: let Wget choose the URL’s filename, write to a path you choose, and ask Wget to continue a partial transfer.

This article uses GNU Wget as an external command-line program—not the separate PyPI project named wget. If installing an executable is not practical, a standard-library alternative appears later.

Prerequisites and the Wget/PyPI distinction

GNU Wget is a command-line utility for non-interactive web downloads. Python merely starts that utility; it does not provide the executable. Install Wget using the package manager appropriate for your operating system, then verify that the command resolves in the same environment as your script:

wget --version

Common publisher guidance is apt-get on Ubuntu or Debian, Homebrew on macOS, and Chocolatey on Windows. Package names and commands can change, so confirm the current syntax in your system’s package manager documentation. A successful version response confirms that wget is on PATH.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Do not confuse this executable with the PyPI project also named wget. That project exposes python -m wget and a wget.download(url) API; PyPI lists version 3.2 as released on 22 October 2015. Its interface and release history are separate from GNU Wget, so the examples below intentionally invoke the executable.

How subprocess.run() invokes Wget

Pass arguments as a list. The first item is the executable, followed by options and URLs. Avoid shell=True for URL input you do not fully control; a list lets Python pass each argument without shell parsing.

import subprocess

url = "https://getsamplefiles.com/download/zip/sample-1.zip"
result = subprocess.run(["wget", url])

if result.returncode != 0:
    raise RuntimeError(f"Wget failed with exit code {result.returncode}")

Wget writes progress and diagnostics to the terminal by default. Add check=True when a non-zero exit status should immediately raise subprocess.CalledProcessError:

subprocess.run(["wget", url], check=True)

The sample URL is illustrative. Replace it with a URL you are authorized to download; it is not presented as a permanent test endpoint.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Command 1: download using the URL’s default filename

For a single URL, the simplest call is:

import subprocess

url = "https://getsamplefiles.com/download/zip/sample-1.zip"
subprocess.run(["wget", url], check=True)

GNU Wget downloads the URL supplied on its command line and normally derives the local filename from the URL. If the server redirects or supplies a different content-disposition filename, the resulting name can differ from what the URL appears to show. Check the output directory after the process exits.

To capture diagnostics for logging while retaining a useful exception:

import subprocess

try:
    completed = subprocess.run(
        ["wget", url],
        check=True,
        text=True,
        capture_output=True,
    )
except FileNotFoundError as exc:
    raise RuntimeError("GNU Wget is not installed or is not on PATH") from exc
except subprocess.CalledProcessError as exc:
    raise RuntimeError(exc.stderr or "Wget could not download the URL") from exc
else:
    print(completed.stdout)

capture_output=True collects stdout and stderr instead of displaying them live. For long transfers, stream output or leave the default terminal behavior so operators can see progress.

Command 2: choose an output path

Use -O for an exact filename

Wget’s -O (output-document) option selects the complete destination filename. Create the directory in Python before invoking Wget:

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
from pathlib import Path
import subprocess

url = "https://getsamplefiles.com/download/zip/sample-1.zip"
destination = Path("downloads/sample-1.zip")
destination.parent.mkdir(parents=True, exist_ok=True)

subprocess.run(["wget", "-O", str(destination), url], check=True)

-O is appropriate when your program must know the exact path. Be careful with multiple URLs: GNU Wget documents that using one output document for multiple inputs can concatenate document content. Download each URL separately when each should remain an independent file.

Use -P to select a directory

If you want Wget to retain its filename choice but place the result in a directory, use -P:

from pathlib import Path
import subprocess

url = "https://getsamplefiles.com/download/zip/sample-1.zip"
out_dir = Path("downloads")
out_dir.mkdir(parents=True, exist_ok=True)

subprocess.run(["wget", "-P", str(out_dir), url], check=True)

The distinction is simple: -O names the output document; -P names the directory in which Wget stores its normal URL-derived filename. For predictable downstream processing, an explicit -O path is easier to inspect.

Command 3: continue a partial download

Use Wget’s --continue option (commonly abbreviated -c) to request continuation of an existing partial file:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
from pathlib import Path
import subprocess

url = "https://getsamplefiles.com/download/zip/sample-1.zip"
destination = Path("downloads/sample-1.zip")
destination.parent.mkdir(parents=True, exist_ok=True)

subprocess.run(
    ["wget", "--continue", "-O", str(destination), url],
    check=True,
)

Resume is an attempt, not a guarantee. It depends on the server supporting byte-range requests, the existing file representing the same resource, and the response Wget receives. A changed URL, changed remote content, missing range support, or an invalid partial file can cause a restart or failure. Do not treat a zero exit status as proof that the bytes match an expected release: validate size, checksum, archive integrity, or a signature when your application requires that assurance.

For a URL whose normal filename is suitable, omit -O and use -c alone. Keep the working directory stable so Wget can find the partial file.

Choosing Wget or Python’s standard library

Consideration GNU Wget via subprocess urllib.request
Runtime requirement External Wget executable installed and discoverable on PATH Included with Python; no Wget executable
Strength Wget command-line features, including its continuation and broader transfer options Python-native response handling and exception flow
Deployment Requires OS packaging and environment configuration Usually simpler in a Python-only deployment
Validation Inspect return codes and, when needed, captured stderr Handle Python exceptions and validate the resulting file yourself

Use Wget when its command-line behavior is already part of your operational environment or you need Wget-specific features. Prefer the standard library when adding an executable complicates containers, serverless deployments, or restricted hosts.

Python-only download with urllib.request

Python 3.13 documents urllib.request.urlretrieve(url, filename=...) for copying a network resource into a local file:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
from pathlib import Path
from urllib.request import urlretrieve
from urllib.error import URLError, HTTPError

url = "https://getsamplefiles.com/download/zip/sample-1.zip"
destination = Path("downloads/sample-1.zip")
destination.parent.mkdir(parents=True, exist_ok=True)

try:
    urlretrieve(url, destination)
except (HTTPError, URLError) as exc:
    raise RuntimeError(f"Download failed: {exc}") from exc

The documentation notes that urlretrieve can raise ContentTooShortError when the response is shorter than the server’s Content-Length. If no Content-Length is provided, Python cannot perform that size check. Production code should also set an appropriate timeout (often by using urlopen directly), restrict redirects and destinations as appropriate for your threat model, and verify the downloaded content.

Reliable automation checklist

  • Resolve the executable explicitly in deployment and test the same PATH used by the scheduler, container, or service.
  • Create destination directories before starting the process.
  • Use check=True or inspect returncode; record stderr for diagnosis.
  • Use a timeout policy around the subprocess so a stalled transfer cannot run forever.
  • Write to a temporary filename, then rename after validation when readers must never see a partial file.
  • For retries, use bounded attempts and backoff rather than an infinite loop.
  • Validate expected size, checksum, archive structure, or signature before handing the file to another job.
  • Treat URLs, output paths, headers, and credentials as untrusted input; avoid shell interpolation.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Troubleshooting common failures

“wget” is not found

Cause: Wget is missing or its installation directory is not on the process PATH. Fix: install GNU Wget with your platform’s supported package manager, run wget --version in the target environment, or pass an absolute executable path in the argument list.

The process exits non-zero

Cause: DNS failure, an HTTP error, TLS problem, permission issue, or another transfer failure. Fix: capture stderr, inspect the URL manually with the same environment, check filesystem permissions, and handle retries only for errors that are plausibly transient.

The destination directory does not exist

Cause: Wget cannot create your intended parent path. Fix: call Path(...).parent.mkdir(parents=True, exist_ok=True) before the subprocess.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Resume starts over or produces an unexpected file

Cause: the server does not support ranges, the partial file belongs to another resource, or the response changed. Fix: retain the same URL and destination, inspect Wget’s diagnostics, and use a checksum or other integrity check before accepting the result.

Python downloads fewer bytes than expected

Cause: a truncated response; without Content-Length, urlretrieve cannot compare the received size with an expected size. Fix: use explicit streaming and validation appropriate to the file, or rely on a trusted checksum.

Or skip the browser setup

If your actual goal is capturing a web page rather than downloading a file, ScreenshotNeo provides a website screenshot API and MCP server. One GET request returns PNG, JPEG, WebP, or PDF. It accepts cookie banners before capture and removes more than 60 known consent platforms, newsletter popups, and chat widgets; bot checks, blank pages, timeouts, failed loads, and cache hits are not billed, and response headers identify the page verdict and billing status.

For a direct capture, see the ScreenshotNeo API documentation:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp

Python and Node.js equivalents:

import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"}, timeout=90)
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);

ScreenshotNeo also offers an MCP server for Claude, Cursor, and other MCP clients, so AI agents can call take_screenshot, get_page_info, and capture_pdf. The free plan includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000. Sign up free for ScreenshotNeo.

Frequently Asked Questions

Can I pass several URLs to one subprocess call?

Yes. Add each URL as another list item, but do not combine multiple URLs with one -O destination when you need separate files; Wget documents concatenation behavior for that case.

Does --continue verify a download’s integrity?

No. It requests continuation when transfer conditions permit. Use a checksum, signature, archive test, or another application-specific validation step afterward.

Should a scheduled job use check=True?

Usually yes when any failed download should fail the job. Catch CalledProcessError when you need custom logging, retry policy, or per-URL handling.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

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.