Some links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.
To use the installed curl command from Python, run it with subprocess.run() and a list of arguments. Keep the default shell=False, set a timeout, and choose whether to capture the result or raise an exception when curl fails. If your goal is simply to make an HTTP request, Python’s urllib.request or the Requests library may fit better because they do not require starting a separate program. This guide explains both choices and how to handle their practical trade-offs.
Run cURL from Python with subprocess
Python’s recommended high-level interface for subprocess cases it can handle is subprocess.run(). Pass the executable, each option, and the URL as separate strings in a list. For example, this runs curl, captures the response body as text, reports curl errors on standard error, stops waiting after 20 seconds, and raises an exception for a nonzero exit status:
import subprocess
result = subprocess.run(
["curl", "--fail", "--silent", "--show-error", "https://example.com/"],
capture_output=True,
text=True,
timeout=20,
check=True,
)
print(result.stdout)
The example uses curl command-line options; confirm that the options and behavior suit the curl version and operation in your environment. Python’s subprocess documentation covers run(), argument handling, captured output, timeouts, and return codes.
Do these 3 things before closing this tab:
1Scan for outdated or missing drivers - takes under a minute2Repair Windows errors before they cause bigger problems3Fix the driver behind crashes, sound loss and screen glitchesWhat each subprocess option does
capture_output=Truecollects standard output and standard error for your program to inspect. Without it, output is normally inherited by the parent process instead.text=Trueasks Python to decode captured output into strings. Leave it off when you need raw bytes, such as for an image or other binary response.timeout=20limits how long Python waits for the child process. Pick a limit appropriate to the task rather than letting a request wait indefinitely.check=Trueraisessubprocess.CalledProcessErrorif curl exits with a nonzero status. Omit it if you prefer to inspectresult.returncodeyourself.--silentsuppresses curl’s usual progress display;--show-errorkeeps its error message visible, and--failasks curl to treat an HTTP error response as a failure. These are curl options, not Python subprocess options.
Handle failures explicitly
With check=True, catch CalledProcessError when you want to recover from a failed command rather than stop the program. The exception and the captured result can help you log the exit status and diagnostics. If the timeout expires, Python raises TimeoutExpired. If Python cannot locate the executable, the launch fails; verify that curl is installed and discoverable from the environment running your script.
#1 Best Overall
import subprocess
try:
result = subprocess.run(
["curl", "--fail", "--silent", "--show-error", "https://example.com/"],
capture_output=True,
text=True,
timeout=20,
check=True,
)
except subprocess.TimeoutExpired as exc:
print(f"curl exceeded the time limit: {exc}")
except subprocess.CalledProcessError as exc:
print(f"curl exited with status {exc.returncode}")
print(exc.stderr or "No captured error message")
Choose whether to capture output based on what the application needs. Capturing the response is useful when Python will parse or transform it; if curl is writing directly to a file, capturing the body may be unnecessary. Treat returned data as bytes when it is not text.
Why use an argument list instead of a shell command?
Do not assemble a command string by concatenating a URL or other untrusted value. Passing a sequence to subprocess.run() lets Python pass arguments to the program without asking a system shell to parse that string. Keep the default shell=False unless you have a specific reason to invoke a shell.
When shell=True is used, the application becomes responsible for correctly quoting whitespace and shell metacharacters. Incorrect quoting can create shell-injection vulnerabilities when values include user input. A list of arguments avoids that shell-parsing step for ordinary invocations. See Python’s subprocess security considerations for the documented distinction.
Recommended Free Tools
Rank #2
Keep values as individual arguments
Each option and its value should be its own list item when curl expects separate arguments. A space inside one Python string does not cause Python to split that string into shell-style words. Likewise, do not add shell quotes around a URL merely because it contains punctuation; quotes are shell syntax, and with shell=False they would be passed as literal characters if included in the argument itself.
url = "https://example.com/"
args = ["curl", "--fail", "--silent", "--show-error", url]
result = subprocess.run(args, capture_output=True, text=True, timeout=20, check=True)
Choose between cURL, urllib.request, and Requests
Launching curl is appropriate when your project specifically depends on the curl executable or a curl behavior. If your program only needs to communicate over HTTP, an in-process Python HTTP library avoids managing a child process, its executable, and its exit status. These choices are not interchangeable in every case; compare the features and runtime behavior your application needs.
| Approach | Requires curl executable? | Process handling | Documentation |
|---|---|---|---|
subprocess.run() with curl |
Yes | Python starts a child process; your code chooses timeouts, output handling, and whether to raise on a nonzero exit status. | Python subprocess |
urllib.request |
No | Uses Python’s standard-library URL-opening facilities rather than a separate curl process. | Python urllib.request |
| Requests | No | Uses the separate Requests Python library; consult its current documentation for installation, API, and supported Python versions. | Requests documentation |
Use urllib.request for a standard-library option
urllib.request provides URL-opening functions and classes, with documented support for areas including authentication, redirects, and cookies. It is a reasonable starting point when you want HTTP access without a separately installed curl executable or an additional library. Review its documentation for the particular request pattern you need: urllib.request — Extensible library for opening URLs.
Use Requests when your project uses that library
Requests is a Python HTTP library, not a wrapper that launches the curl command. It introduces its own dependency and API, so check the project’s documentation for installation instructions and the Python versions it supports: Requests: HTTP for Humans.
Keep curl when curl itself is a requirement
If your existing workflow relies on a curl command or behavior, using the executable from Python preserves that boundary: Python starts curl and handles its input, output, timeout, and status. The trade-off is deployment responsibility. The target machine must have a compatible curl executable available, and process lookup can differ between operating systems.
Make the invocation reliable across environments
Confirm which executable Python will run
For maximum reliability, Python recommends using a fully qualified path to the executable. If you want to search the environment’s PATH, use shutil.which() to locate curl and handle a missing result before launching the process. This matters especially when a script runs in a service, scheduled task, container, or other environment whose PATH may differ from your interactive terminal.
import shutil
import subprocess
curl_path = shutil.which("curl")
if curl_path is None:
raise RuntimeError("curl was not found on PATH")
result = subprocess.run(
[curl_path, "--fail", "--silent", "--show-error", "https://example.com/"],
capture_output=True,
text=True,
timeout=20,
check=True,
)
Executable resolution has platform differences. Python specifically documents differences in how Windows resolves an executable when shell=False; test in the same environment where the program will run, and use an explicit executable path if appropriate. The Python subprocess reference provides the platform-specific details.
Set output handling to match the response
For text such as a response body you plan to inspect, capture_output=True with text=True is convenient. For binary output, omit text=True so Python retains bytes. Capturing output also means the child’s output is held for your program; avoid capturing it when you do not need it. The right choice depends on whether Python must parse, log, or otherwise use the response.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
Choose timeout and exit-status behavior deliberately
A timeout bounds how long the parent waits for curl. A value that is too short can interrupt a legitimate slow operation; a value that is too long can leave the application waiting longer than intended. With check=True, failures become exceptions at the call site; with the default check=False, inspect returncode and decide what the program should do. Neither choice substitutes for handling errors deliberately.
Best Value
Common cURL-in-Python problems and fixes
- “No such file” or executable not found: curl may be missing or absent from the Python process’s
PATH. Install or configure the executable for that environment, check it withshutil.which("curl"), or pass its fully qualified path. CalledProcessErroris raised: this is expected withcheck=Truewhen the process exits nonzero. Inspectreturncodeand capturedstderr; confirm the URL, curl arguments, and network conditions relevant to your request.TimeoutExpiredis raised: the process did not finish within the configured limit. Check whether the operation is expected to take longer, then choose an appropriate timeout and decide how the application should recover.- The URL or option is being interpreted incorrectly: verify that every argument is a separate list item and that you have not included shell quoting characters in the values. Avoid building a shell command string.
- Binary output looks corrupted: do not use
text=Truefor binary content. Keep the captured output as bytes or have curl write it to a file, as appropriate for the task. - The script works locally but not on deployment: the executable path or version may differ. Check curl availability and test invocation behavior on the target operating system and runtime.
Or skip the browser setup
If the task is to capture a website screenshot rather than learn or depend on the curl executable, ScreenshotNeo offers a one-request API. This is a different approach from invoking curl through Python: the following command uses curl directly to request a screenshot.
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 API documentation for request options. ScreenshotNeo removes cookie/consent banners, newsletter popups, and chat widgets before capture; bot checks, blank pages, and failed loads are not billed. Its MCP server lets AI agents use screenshot tools. The free plan includes 1,000 shots per month with no card, and paid plans start at $5 for 3,000 shots. Learn about ScreenshotNeo or sign up for 1,000 free screenshots a month with no card.
Performance and cost considerations
Calling curl starts a separate process, so it adds process-launch and executable-management work compared with making an HTTP request inside Python. Whether that matters depends on the application and how often it makes requests; the available references do not establish a universal performance winner. If process startup and exit handling do not serve a requirement, consider an HTTP library instead.
Free tools Windows power users keep installed
One-click scans. No signup required.
For a service or repeated task, consider the operational cost of ensuring curl exists on every machine, handling timeouts and failures, and keeping behavior consistent across platforms. In contrast, urllib.request uses Python’s standard library, while Requests is an additional library dependency. Compare those deployment needs alongside the HTTP capabilities your program requires rather than choosing solely by familiarity.
Frequently Asked Questions
Does Python’s subprocess.run() install cURL for me?
No. It launches an executable available to the Python process. Install curl in the runtime environment or provide its executable path.
Is Requests the same thing as running the cURL command?
No. Requests is a Python HTTP library; using subprocess.run() launches the external curl program.
Can I use cURL from Python without shell=True?
Yes. Pass curl and its arguments as a list to subprocess.run(); this is the normal pattern for avoiding shell parsing.
Quick wins for a faster PC:
Fix the driver behind crashes, sound loss and screen glitchesFind Drivers →Clear out junk files and repair common Windows errorsFree Scan →Scan for outdated or missing drivers - takes under a minuteDriver Scan →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.

