Requests is a popular and elegant Python HTTP library. It allows you to send HTTP requests (like GET, POST, PUT, DELETE, etc.) easily and efficiently. It handles the complexities of making HTTP requests, such as encoding data, handling headers, and managing cookies, making it much simpler than using Python’s built-in urllib
library. It’s designed to be user-friendly and intuitive, letting you focus on the application logic rather than the low-level details of HTTP communication.
Requests offers several key advantages over lower-level alternatives:
Requests is easily installed using pip, the Python package installer:
pip install requests
This command will download and install the Requests library and its dependencies. No further configuration is usually required.
The simplest way to make a GET request is:
import requests
= requests.get('https://www.example.com')
response
# Check the status code (200 means success)
print(response.status_code)
# Access the content of the response
print(response.text) #Get the response body as text
print(response.json()) #Get the response body as a json object (if applicable)
This code snippet first imports the requests
library. Then, it makes a GET request to https://www.example.com
. The response
object contains the server’s response, including the status code (e.g., 200 for OK) and the content. The example then prints the status code and the response text. If the response is JSON, you can use response.json()
for convenient parsing. Remember to handle potential exceptions (like requests.exceptions.RequestException
) in production code.
The most basic GET request is made using the requests.get()
function, passing the URL as an argument:
import requests
= requests.get('https://www.example.com')
response
print(response.status_code) # Check the status code (e.g., 200)
print(response.text) # Access the response content as text
This sends a GET request to the specified URL. The response object contains details about the request, including the status code and the response content. Always check the status code to ensure the request was successful (200 OK is a common success code).
Query parameters are appended to the URL after a question mark (?
). They are used to pass additional information to the server. Requests handles these easily:
import requests
= {'key1': 'value1', 'key2': 'value2'}
params = requests.get('https://api.example.com/data', params=params)
response
print(response.url) # Print the full URL with query parameters
print(response.json()) # Parse JSON response if applicable
The params
dictionary is automatically converted into a query string.
HTTP headers provide additional information about the request. You can set custom headers using the headers
parameter:
import requests
= {'User-Agent': 'My Custom User Agent', 'Accept': 'application/json'}
headers = requests.get('https://api.example.com/data', headers=headers)
response
print(response.headers) # Access response headers
print(response.json()) # Parse JSON response if applicable
This example sets a custom User-Agent header, which helps identify your application to the server. Setting the Accept
header specifies the desired response content type.
The response object provides several ways to access the data:
response.text
: Returns the response content as a Unicode string. Useful for HTML or text-based responses.response.content
: Returns the response content as bytes. Useful for binary data like images.response.json()
: Parses the response content as JSON and returns a Python dictionary or list. Raises a requests.exceptions.JSONDecodeError
if the content isn’t valid JSON.response.headers
: A dictionary containing response headers.response.status_code
: The HTTP status code (e.g., 200, 404, 500).Requests automatically handles various content types. However, you might need to specify the expected content type using the headers
parameter’s Accept
header or handle the response accordingly (e.g. by checking the Content-Type
header in the response). For example, to ensure you get JSON back:
import requests
= {'Accept': 'application/json'}
headers = requests.get('https://api.example.com/data', headers=headers)
response
try:
= response.json()
data print(data)
except requests.exceptions.JSONDecodeError:
print("Response is not valid JSON")
Always check the response.status_code
to ensure the request was successful. Non-2xx status codes indicate errors. You can use try...except
blocks to handle potential exceptions:
import requests
try:
= requests.get('https://api.example.com/data')
response # Raise an exception for bad status codes (4xx or 5xx)
response.raise_for_status() print(response.json())
except requests.exceptions.RequestException as e:
print(f"An error occurred: {e}")
response.raise_for_status()
conveniently raises an exception for bad status codes, simplifying error handling. The requests.exceptions.RequestException
handles various network and HTTP errors.
POST requests are used to send data to the server. The data is typically sent in the request body. The basic structure is similar to GET requests, but using requests.post()
:
import requests
= {'key1': 'value1', 'key2': 'value2'}
data = requests.post('https://api.example.com/submit', data=data)
response
print(response.status_code)
print(response.text)
This sends a POST request with the data provided in the data
dictionary. The server will process this data.
Requests supports different ways to encode the data sent in the request body.
data
(for form-encoded data): This is used for simple key-value pairs, often used in HTML forms. It automatically URL-encodes the data.
json
(for JSON data): For sending JSON data, use the json
parameter:
import requests
= {'key1': 'value1', 'key2': 'value2'}
data = requests.post('https://api.example.com/submit', json=data)
response
print(response.status_code)
print(response.json()) #Parse the JSON response.
This sends the data as a JSON object. The server should expect JSON data.
Handling POST responses is similar to GET requests. Check the response.status_code
to verify success. Access the response content using response.text
, response.content
, or response.json()
depending on the expected content type. Remember to handle potential errors using try...except
blocks. For example:
import requests
try:
= requests.post('https://api.example.com/submit', json={'key': 'value'})
response # Raise HTTPError for bad responses (4xx or 5xx)
response.raise_for_status() print(response.json())
except requests.exceptions.RequestException as e:
print(f"An error occurred: {e}")
To upload files, use the files
parameter with a dictionary where keys are the field names and values are file-like objects (e.g., opened files or file paths):
import requests
= {'file': open('my_file.txt', 'rb')} # 'rb' for binary read mode
files = requests.post('https://api.example.com/upload', files=files)
response
print(response.status_code)
print(response.text)
This uploads my_file.txt
. Remember to close the file after the request using files['file'].close()
. Alternatively, you can use with open(...) as f:
to manage file closing automatically. The server-side needs to be configured to handle file uploads. You might also need to adjust the Content-Type
header appropriately, depending on the server’s requirements. For example, a multipart/form-data content type is common for file uploads. Requests usually handles this automatically when using the files
parameter.
HTTP status codes indicate the outcome of a request. The response.status_code
attribute provides this information. Codes in the 2xx range generally indicate success, while 4xx codes represent client-side errors (like 404 Not Found), and 5xx codes indicate server-side errors (like 500 Internal Server Error). Always check the status code to ensure your request was successful. For example:
import requests
= requests.get('https://www.example.com')
response
if response.status_code == 200:
print("Request successful!")
elif response.status_code == 404:
print("Not Found")
else:
print(f"Request failed with status code: {response.status_code}")
Response headers provide additional information about the response. Access them using response.headers
, which is a dictionary-like object:
import requests
= requests.get('https://www.example.com')
response
= response.headers.get('Content-Type')
content_type print(f"Content-Type: {content_type}")
= response.headers.get('Server')
server print(f"Server: {server}")
response.headers.get('Header-Name')
is used to safely access a header, returning None
if the header isn’t present.
The response content can be accessed in several ways:
response.text
: Returns the content as a Unicode string. Suitable for text-based responses like HTML.response.content
: Returns the content as bytes. Suitable for binary data like images or PDFs.response.json()
: Parses the content as JSON and returns a Python dictionary or list. Raises a requests.exceptions.JSONDecodeError
if the content is not valid JSON. This is the most convenient way to work with JSON APIs.import requests
= requests.get('https://api.example.com/data')
response
if response.status_code == 200:
try:
= response.json()
data print(data)
except requests.exceptions.JSONDecodeError:
print("Invalid JSON response")
Requests raises exceptions for various errors, including network issues and HTTP errors. Use try...except
blocks to handle these:
import requests
try:
= requests.get('https://api.example.com/data')
response #Raises HTTPError for bad responses (4xx or 5xx)
response.raise_for_status() #Process the successful response here
except requests.exceptions.RequestException as e:
print(f"An error occurred: {e}")
except requests.exceptions.HTTPError as e:
print(f"HTTP Error: {e}")
except requests.exceptions.ConnectionError as e:
print(f"Connection Error: {e}")
except requests.exceptions.Timeout as e:
print(f"Timeout Error: {e}")
response.raise_for_status()
is helpful for explicitly raising exceptions for bad status codes.
Requests automatically handles redirects (3xx status codes). To access information about redirects:
import requests
= requests.get('https://shorturl.at/somelink', allow_redirects=True) #allow_redirects is True by default
response
print(response.url) #The final URL after redirects
print(response.history) #List of intermediate responses during redirects.
Setting allow_redirects=False
will prevent automatic redirection and allow handling redirects manually.
Requests handles cookies automatically. To access or manipulate cookies:
import requests
= requests.Session() # Use a session for managing cookies across requests.
session
= session.get('https://www.example.com/login', data={'username':'user', 'password':'pass'})
response = session.cookies
cookies
= session.get('https://www.example.com/profile') #Cookies from the login will be sent automatically
response2 #access cookies using cookies.get_dict() etc.
print(response2.text)
Using a requests.Session()
object is recommended for managing cookies across multiple requests. You can directly access and modify cookies through the session.cookies
attribute for more advanced control.
Requests supports various authentication methods.
auth
parameter with a tuple containing the username and password:import requests
= requests.get('https://api.example.com/data', auth=('username', 'password'))
response print(response.text)
Bearer
token):import requests
= "YOUR_ACCESS_TOKEN" #Obtain this through the OAuth flow.
access_token = {'Authorization': f'Bearer {access_token}'}
headers = requests.get('https://api.example.com/data', headers=headers)
response print(response.text)
The specific implementation depends on the OAuth provider.
To use a proxy server, use the proxies
parameter with a dictionary specifying the proxy for each protocol (HTTP and HTTPS):
import requests
= {
proxies 'http': 'http://user:password@proxy.example.com:8080',
'https': 'http://user:password@proxy.example.com:8080',
}
= requests.get('https://www.example.com', proxies=proxies)
response print(response.text)
Replace placeholders with your proxy server details. If you don’t need authentication, omit the user:password@
part.
To prevent requests from hanging indefinitely, set timeouts using the timeout
parameter (in seconds):
import requests
try:
= requests.get('https://www.example.com', timeout=5) # 5-second timeout
response print(response.text)
except requests.exceptions.Timeout:
print("Request timed out")
except requests.exceptions.RequestException as e:
print(f"An error occurred: {e}")
You can specify a tuple for separate connect and read timeouts: timeout=(connect_timeout, read_timeout)
.
For self-signed or untrusted certificates, you may need to disable SSL verification or provide a custom certificate bundle:
import requests
# Disable SSL verification (INSECURE - ONLY FOR DEVELOPMENT/TESTING!)
= requests.get('https://selfsigned.example.com', verify=False)
response
#Use a custom CA bundle (more secure than verify=False)
= requests.get('https://selfsigned.example.com', verify='/path/to/my/ca.pem')
response
print(response.text)
Warning: Disabling SSL verification (verify=False
) is highly discouraged in production environments as it compromises security. Use a custom CA bundle whenever possible for secure handling of self-signed certificates.
requests.Session()
objects persist cookies, headers, and other settings across multiple requests, making them efficient for interacting with websites or APIs that require authentication or state management.
import requests
= requests.Session()
session = ('username', 'password')
session.auth
= session.get('https://api.example.com/login')
response1 = session.get('https://api.example.com/data') # Authentication from response1 is reused.
response2
print(response2.text)
The session automatically handles cookies and other persistent data.
Requests uses adapters to handle connections. You can create custom adapters for special needs (e.g., handling specific protocols or proxies):
import requests
class MyAdapter(requests.adapters.HTTPAdapter):
def send(self, request, **kwargs):
# Add custom logic here (e.g., modify the request before sending)
return super().send(request, **kwargs)
= requests.Session()
session 'http://', MyAdapter()) #Mount the adapter for http:// URLs
session.mount('https://', MyAdapter())#Mount the adapter for https:// URLs
session.mount(
= session.get('https://www.example.com')
response print(response.text)
Custom adapters provide powerful control over the underlying HTTP connection handling. This is advanced usage and requires a good understanding of HTTP and Requests’ internals.
verify=True
). Avoid disabling SSL verification (verify=False
) except for explicit testing purposes in controlled environments.try...except
blocks to catch potential exceptions (requests.exceptions.RequestException
, requests.exceptions.HTTPError
, etc.). Log errors for debugging and monitoring.logging
module. Include relevant details like timestamps, URLs, status codes, and error messages.Example using Python’s logging
module:
import logging
import requests
=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
logging.basicConfig(level
try:
= requests.get('https://api.example.com/data')
response
response.raise_for_status()f"Request successful. Status code: {response.status_code}")
logging.info(#Process successful response
except requests.exceptions.RequestException as e:
f"Request failed: {e}") logging.error(
requests.Session()
) for multiple requests to the same server. Sessions reuse connections and manage cookies efficiently, reducing overhead.Many APIs implement rate limiting to prevent abuse. If you exceed the rate limit, your requests might be temporarily blocked.
time.sleep()
, using a queue to manage requests, or using a dedicated rate-limiting library.Example of adding a delay to handle rate limiting:
import time
import requests
= 1 # requests per second
rate_limit = 1/rate_limit
time_between_requests
for i in range(10):
= requests.get('https://api.example.com/data')
response if response.status_code == 200:
#Process the response
pass
else:
print(f"Request failed with status code: {response.status_code}")
time.sleep(time_between_requests)
RESTful APIs are the most common type of web API. They use standard HTTP methods (GET, POST, PUT, DELETE) to interact with resources. Requests is well-suited for working with RESTful APIs.
Example: Fetching data from a REST API using a GET request:
import requests
= "https://api.example.com/users/123"
url = requests.get(url)
response
if response.status_code == 200:
= response.json()
data print(data)
else:
print(f"Error: {response.status_code}")
This example makes a GET request to retrieve user data. The response is assumed to be JSON. Error handling is essential; always check the status code. For POST, PUT, and DELETE requests, use the appropriate requests
method (requests.post
, requests.put
, requests.delete
), providing the data in the request body as needed (often as JSON using the json
parameter). Remember to handle different response status codes and potential errors. The specific details depend on the API’s documentation.
GraphQL APIs use a query language to specify exactly the data needed. Requests can be used with GraphQL by sending a POST request with the query in the request body. You’ll typically need to handle the JSON response appropriately.
Example: Making a GraphQL query:
import requests
= "https://api.example.com/graphql"
url = """
query query GetUser($id: ID!) {
user(id: $id) {
id
name
email
}
}
"""
= {"id": "123"}
variables
= requests.post(url, json={"query": query, "variables": variables})
response
if response.status_code == 200:
= response.json()
data print(data['data']['user'])
else:
print(f"Error: {response.status_code}")
This example sends a GraphQL query to fetch user data. The query
and variables
are sent as JSON. The response contains the data in the data
field. Error handling and checking the response structure are vital. Always consult the GraphQL API’s documentation for specific query structures and response formats.
Requests can be used with other API types as well, though the specifics will depend on the API’s communication protocol and data format. This might include:
zeep
build upon Requests to simplify interaction with SOAP APIs.grpcio
) are generally preferred for working with gRPC services.For any API type beyond the most common RESTful APIs, referring to the API’s specific documentation is crucial to understand the correct request format (headers, body, authentication, etc.) and how to correctly parse the response. Requests provides the fundamental HTTP capabilities, but often, additional libraries or techniques are needed for seamless interaction with more specialized APIs.
requests.exceptions.RequestException
: This is a base exception for all requests exceptions. Check the specific exception type (e.g., requests.exceptions.ConnectionError
, requests.exceptions.Timeout
, requests.exceptions.HTTPError
) for more detail. Solutions depend on the specific error; common causes include network problems, server issues, incorrect URLs, or timeouts.requests.exceptions.ConnectionError
: A connection problem. Check your network connection, the server’s availability, and the URL for typos.requests.exceptions.Timeout
: The request timed out. Increase the timeout
parameter in your request or investigate potential server-side performance issues.requests.exceptions.HTTPError
: The server returned an HTTP error status code (4xx or 5xx). Examine the response status code and details (e.g., response.text
, response.json()
) for more information. Address the underlying issue reported by the server (e.g., incorrect authentication, missing data).requests.exceptions.SSLError
: An SSL/TLS error. Ensure the SSL certificate is valid. If it’s self-signed, you might need to disable verification (verify=False
– use with extreme caution!) or provide a custom certificate authority bundle.requests.exceptions.JSONDecodeError
: The server returned invalid JSON. Check the server’s response and the API documentation. Ensure the server is sending valid JSON data.