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.
#1 Best Overall
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.
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.
Rank #2
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.
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:
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 problemsfrom 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:
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
PATHused by the scheduler, container, or service. - Create destination directories before starting the process.
- Use
check=Trueor inspectreturncode; 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.
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.
The Tool Desk
Outbyte Driver Updater FREEScan for outdated or missing drivers - takes under a minuteDriver Scan →Outbyte PC Repair FREEClear out junk files and repair common Windows errorsFree Scan →Best Value
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:
Outdated 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 matchWindows 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 reinstallcurl -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.
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.

