
Python Requests is a powerful and simple to operate HTTP library that simplifies the process of making HTTP requests in Python. It abstracts away many of the complexities involved in network communications, allowing developers to focus on their application logic rather than low-level networking details.
To get started with Python Requests, you’ll need to install it first. You can do this using pip, the Python package manager:
pip install requests
Once installed, you can import the library in your Python script:
import requests
Python Requests offers several key features that make it a popular choice among developers:
- It provides a clean and intuitive API for making HTTP requests.
- It takes care of connection pooling, content decoding, and SSL verification.
- GET, POST, PUT, DELETE, HEAD, OPTIONS, and more.
- Allows for maintaining cookies and other session data across requests.
- Easily handle JSON responses from APIs.
- Simplifies the process of uploading files in multipart/form-data format.
Here’s a simple example demonstrating how to make a GET request using Python Requests:
response = requests.get('https://api.github.com')
print(response.status_code)
import requests
response = requests.get('https://api.github.com')
print(response.status_code)
print(response.json())
import requests
response = requests.get('https://api.github.com')
print(response.status_code)
print(response.json())
In this example, we’re making a GET request to the GitHub API and printing the status code and JSON response. The requests.get()
function returns a Response object, which we’ll explore in more detail in the following sections.
Python Requests also supports other HTTP methods. Here’s how you can make a POST request with some data:
response = requests.post('https://httpbin.org/post', data=data)
import requests
data = {'key': 'value'}
response = requests.post('https://httpbin.org/post', data=data)
print(response.text)
import requests
data = {'key': 'value'}
response = requests.post('https://httpbin.org/post', data=data)
print(response.text)
Making HTTP Requests
Making HTTP requests with Python Requests is simpler and intuitive. The library supports all common HTTP methods, including GET, POST, PUT, DELETE, HEAD, and OPTIONS. Let’s explore how to use these methods effectively.
GET Requests
GET requests are used to retrieve data from a server. Here’s a simple example:
response = requests.get('https://api.example.com/users')
print(response.status_code)
import requests
response = requests.get('https://api.example.com/users')
print(response.status_code)
print(response.json())
import requests
response = requests.get('https://api.example.com/users')
print(response.status_code)
print(response.json())
You can also include query parameters in your GET request:
params = {'page': 1, 'limit': 10}
response = requests.get('https://api.example.com/users', params=params)
params = {'page': 1, 'limit': 10}
response = requests.get('https://api.example.com/users', params=params)
params = {'page': 1, 'limit': 10}
response = requests.get('https://api.example.com/users', params=params)
POST Requests
POST requests are used to send data to a server to create or update a resource. Here’s how to make a POST request with JSON data:
data = {'username': 'johndoe', 'email': 'johndoe@example.com'}
response = requests.post('https://api.example.com/users', json=data)
print(response.status_code)
import requests
data = {'username': 'johndoe', 'email': 'johndoe@example.com'}
response = requests.post('https://api.example.com/users', json=data)
print(response.status_code)
print(response.json())
import requests
data = {'username': 'johndoe', 'email': 'johndoe@example.com'}
response = requests.post('https://api.example.com/users', json=data)
print(response.status_code)
print(response.json())
For form-encoded data, use the data
parameter instead of json
:
data = {'username': 'johndoe', 'password': 'secret'}
response = requests.post('https://api.example.com/login', data=data)
data = {'username': 'johndoe', 'password': 'secret'}
response = requests.post('https://api.example.com/login', data=data)
data = {'username': 'johndoe', 'password': 'secret'}
response = requests.post('https://api.example.com/login', data=data)
PUT and PATCH Requests
PUT requests are used to update existing resources, while PATCH requests are used for partial updates:
data = {'email': 'newemail@example.com'}
response = requests.put('https://api.example.com/users/1', json=data)
partial_data = {'status': 'active'}
response = requests.patch('https://api.example.com/users/1', json=partial_data)
data = {'email': 'newemail@example.com'}
response = requests.put('https://api.example.com/users/1', json=data)
partial_data = {'status': 'active'}
response = requests.patch('https://api.example.com/users/1', json=partial_data)
data = {'email': 'newemail@example.com'}
response = requests.put('https://api.example.com/users/1', json=data)
partial_data = {'status': 'active'}
response = requests.patch('https://api.example.com/users/1', json=partial_data)
DELETE Requests
DELETE requests are used to remove resources:
response = requests.delete('https://api.example.com/users/1')
print(response.status_code)
response = requests.delete('https://api.example.com/users/1')
print(response.status_code)
response = requests.delete('https://api.example.com/users/1')
print(response.status_code)
Custom Headers
You can include custom headers in your requests:
headers = {'Authorization': 'Bearer your_token_here'}
response = requests.get('https://api.example.com/protected', headers=headers)
headers = {'Authorization': 'Bearer your_token_here'}
response = requests.get('https://api.example.com/protected', headers=headers)
headers = {'Authorization': 'Bearer your_token_here'}
response = requests.get('https://api.example.com/protected', headers=headers)
Handling Authentication
For basic authentication, you can use the auth
parameter:
from requests.auth import HTTPBasicAuth
response = requests.get('https://api.example.com/secure', auth=HTTPBasicAuth('username', 'password'))
from requests.auth import HTTPBasicAuth
response = requests.get('https://api.example.com/secure', auth=HTTPBasicAuth('username', 'password'))
from requests.auth import HTTPBasicAuth
response = requests.get('https://api.example.com/secure', auth=HTTPBasicAuth('username', 'password'))
Session Objects
For multiple requests to the same host, using a Session object can improve performance:
with requests.Session() as session:
session.headers.update({'Authorization': 'Bearer your_token_here'})
response1 = session.get('https://api.example.com/endpoint1')
response2 = session.get('https://api.example.com/endpoint2')
with requests.Session() as session:
session.headers.update({'Authorization': 'Bearer your_token_here'})
response1 = session.get('https://api.example.com/endpoint1')
response2 = session.get('https://api.example.com/endpoint2')
with requests.Session() as session:
session.headers.update({'Authorization': 'Bearer your_token_here'})
response1 = session.get('https://api.example.com/endpoint1')
response2 = session.get('https://api.example.com/endpoint2')
Accessing Response Data
When working with Python Requests, accessing response data is an important part of handling HTTP requests. The Response object returned by a request contains various attributes and methods that allow you to extract and work with the received data.
Let’s explore the different ways to access response data:
1. Accessing the Response Content
The most common way to access the response content is through the text
attribute:
response = requests.get('https://api.github.com')
import requests
response = requests.get('https://api.github.com')
print(response.text)
import requests
response = requests.get('https://api.github.com')
print(response.text)
For binary content, you can use the content
attribute:
response = requests.get('https://example.com/image.jpg')
with open('image.jpg', 'wb') as f:
f.write(response.content)
response = requests.get('https://example.com/image.jpg')
with open('image.jpg', 'wb') as f:
f.write(response.content)
response = requests.get('https://example.com/image.jpg')
with open('image.jpg', 'wb') as f:
f.write(response.content)
2. Parsing JSON Responses
If the response contains JSON data, you can easily parse it using the json()
method:
response = requests.get('https://api.github.com/users/octocat')
print(data['public_repos'])
response = requests.get('https://api.github.com/users/octocat')
data = response.json()
print(data['name'])
print(data['public_repos'])
response = requests.get('https://api.github.com/users/octocat')
data = response.json()
print(data['name'])
print(data['public_repos'])
3. Accessing Headers
You can access response headers using the headers
attribute, which returns a dictionary-like object:
response = requests.get('https://api.github.com')
print(response.headers['Content-Type'])
print(response.headers.get('X-RateLimit-Remaining'))
response = requests.get('https://api.github.com')
print(response.headers['Content-Type'])
print(response.headers.get('X-RateLimit-Remaining'))
response = requests.get('https://api.github.com')
print(response.headers['Content-Type'])
print(response.headers.get('X-RateLimit-Remaining'))
4. Cookies
If the response includes cookies, you can access them through the cookies
attribute:
response = requests.get('https://example.com')
for cookie in response.cookies:
print(f'{cookie.name}: {cookie.value}')
response = requests.get('https://example.com')
for cookie in response.cookies:
print(f'{cookie.name}: {cookie.value}')
response = requests.get('https://example.com')
for cookie in response.cookies:
print(f'{cookie.name}: {cookie.value}')
5. Encoding
You can check the encoding of the response and even change it if needed:
response.encoding = 'ISO-8859-1'
print(response.encoding)
response.encoding = 'ISO-8859-1'
print(response.text)
print(response.encoding)
response.encoding = 'ISO-8859-1'
print(response.text)
6. URL and Request Information
The Response object also provides information about the request:
print(response.url) # Final URL of the response
print(response.request.headers) # Request headers
print(response.elapsed) # Time elapsed for the request
print(response.url) # Final URL of the response
print(response.request.headers) # Request headers
print(response.elapsed) # Time elapsed for the request
print(response.url) # Final URL of the response
print(response.request.headers) # Request headers
print(response.elapsed) # Time elapsed for the request
7. Raw Socket Response
For low-level access to the response, you can use the raw
attribute:
response = requests.get('https://api.github.com', stream=True)
print(response.raw.read(10))
response = requests.get('https://api.github.com', stream=True)
print(response.raw.read(10))
response = requests.get('https://api.github.com', stream=True)
print(response.raw.read(10))
Remember to use stream=True
when working with raw
to avoid downloading the entire response simultaneously.
8. Iterating Over Content
For large responses, you can iterate over the content in chunks:
response = requests.get('https://api.github.com', stream=True)
for chunk in response.iter_content(chunk_size=128):
response = requests.get('https://api.github.com', stream=True)
for chunk in response.iter_content(chunk_size=128):
print(len(chunk))
response = requests.get('https://api.github.com', stream=True)
for chunk in response.iter_content(chunk_size=128):
print(len(chunk))
Manipulating Response Objects
Python Requests provides several methods to manipulate response objects, enabling you to extract, modify, and analyze the data received from HTTP requests. Let’s explore some of the most useful techniques for manipulating response objects:
1. Modifying Headers
You can add or modify headers in the response object:
response = requests.get('https://api.example.com')
response.headers['X-Custom-Header'] = 'My Custom Value'
print(response.headers['X-Custom-Header'])
response = requests.get('https://api.example.com')
response.headers['X-Custom-Header'] = 'My Custom Value'
print(response.headers['X-Custom-Header'])
response = requests.get('https://api.example.com')
response.headers['X-Custom-Header'] = 'My Custom Value'
print(response.headers['X-Custom-Header'])
2. Updating Cookies
You can update or add cookies to the response object:
from requests.cookies import RequestsCookieJar
response = requests.get('https://api.example.com')
cookies = RequestsCookieJar()
cookies.set('my_cookie', 'cookie_value', domain='example.com', path='/')
response.cookies.update(cookies)
print(response.cookies['my_cookie'])
from requests.cookies import RequestsCookieJar
response = requests.get('https://api.example.com')
cookies = RequestsCookieJar()
cookies.set('my_cookie', 'cookie_value', domain='example.com', path='/')
response.cookies.update(cookies)
print(response.cookies['my_cookie'])
from requests.cookies import RequestsCookieJar
response = requests.get('https://api.example.com')
cookies = RequestsCookieJar()
cookies.set('my_cookie', 'cookie_value', domain='example.com', path='/')
response.cookies.update(cookies)
print(response.cookies['my_cookie'])
3. Modifying Content
While you can’t directly modify the content of a response object, you can create a new response with modified content:
from requests.models import Response
original_response = requests.get('https://api.example.com')
new_response = Response()
new_response.status_code = original_response.status_code
new_response.headers = original_response.headers
new_response._content = original_response.content.replace(b'old', b'new')
import requests
from requests.models import Response
original_response = requests.get('https://api.example.com')
new_response = Response()
new_response.status_code = original_response.status_code
new_response.headers = original_response.headers
new_response._content = original_response.content.replace(b'old', b'new')
print(new_response.text)
import requests
from requests.models import Response
original_response = requests.get('https://api.example.com')
new_response = Response()
new_response.status_code = original_response.status_code
new_response.headers = original_response.headers
new_response._content = original_response.content.replace(b'old', b'new')
print(new_response.text)
4. Handling Redirects
You can access and manipulate the redirect history of a response:
response = requests.get('https://github.com', allow_redirects=True)
for resp in response.history:
print(f"Redirect from {resp.url} to {resp.headers['Location']}")
print(f"Final URL: {response.url}")
response = requests.get('https://github.com', allow_redirects=True)
for resp in response.history:
print(f"Redirect from {resp.url} to {resp.headers['Location']}")
print(f"Final URL: {response.url}")
response = requests.get('https://github.com', allow_redirects=True)
for resp in response.history:
print(f"Redirect from {resp.url} to {resp.headers['Location']}")
print(f"Final URL: {response.url}")
5. Streaming Large Responses
For large responses, you can use streaming to process the data in chunks:
with requests.get('https://api.example.com/large-data', stream=True) as response:
response.raise_for_status()
for chunk in response.iter_content(chunk_size=8192):
# Process each chunk of data
with requests.get('https://api.example.com/large-data', stream=True) as response:
response.raise_for_status()
for chunk in response.iter_content(chunk_size=8192):
# Process each chunk of data
process_chunk(chunk)
with requests.get('https://api.example.com/large-data', stream=True) as response:
response.raise_for_status()
for chunk in response.iter_content(chunk_size=8192):
# Process each chunk of data
process_chunk(chunk)
6. Decompressing Content
Requests automatically handles content decompression, but you can manually decompress if needed:
response = requests.get('https://api.example.com/compressed-data')
decompressed_content = zlib.decompress(response.content, 16 + zlib.MAX_WBITS)
print(decompressed_content.decode('utf-8'))
import zlib
response = requests.get('https://api.example.com/compressed-data')
decompressed_content = zlib.decompress(response.content, 16 + zlib.MAX_WBITS)
print(decompressed_content.decode('utf-8'))
import zlib
response = requests.get('https://api.example.com/compressed-data')
decompressed_content = zlib.decompress(response.content, 16 + zlib.MAX_WBITS)
print(decompressed_content.decode('utf-8'))
7. Parsing Different Content Types
You can parse various content types received in the response:
import xml.etree.ElementTree as ET
# JSON parsing (already covered in previous sections)
json_response = requests.get('https://api.example.com/json-data')
json_data = json_response.json()
xml_response = requests.get('https://api.example.com/xml-data')
xml_root = ET.fromstring(xml_response.content)
print(f"{child.tag}: {child.text}")
# HTML parsing (using BeautifulSoup as an example)
from bs4 import BeautifulSoup
html_response = requests.get('https://example.com')
soup = BeautifulSoup(html_response.content, 'html.parser')
title = soup.find('title').text
print(f"Page title: {title}")
import xml.etree.ElementTree as ET
# JSON parsing (already covered in previous sections)
json_response = requests.get('https://api.example.com/json-data')
json_data = json_response.json()
# XML parsing
xml_response = requests.get('https://api.example.com/xml-data')
xml_root = ET.fromstring(xml_response.content)
for child in xml_root:
print(f"{child.tag}: {child.text}")
# HTML parsing (using BeautifulSoup as an example)
from bs4 import BeautifulSoup
html_response = requests.get('https://example.com')
soup = BeautifulSoup(html_response.content, 'html.parser')
title = soup.find('title').text
print(f"Page title: {title}")
import xml.etree.ElementTree as ET
# JSON parsing (already covered in previous sections)
json_response = requests.get('https://api.example.com/json-data')
json_data = json_response.json()
# XML parsing
xml_response = requests.get('https://api.example.com/xml-data')
xml_root = ET.fromstring(xml_response.content)
for child in xml_root:
print(f"{child.tag}: {child.text}")
# HTML parsing (using BeautifulSoup as an example)
from bs4 import BeautifulSoup
html_response = requests.get('https://example.com')
soup = BeautifulSoup(html_response.content, 'html.parser')
title = soup.find('title').text
print(f"Page title: {title}")
8. Timing Requests
You can measure the time taken for a request:
response = requests.get('https://api.example.com')
print(f"Request took {end_time - start_time:.2f} seconds")
print(f"Response time from server: {response.elapsed.total_seconds():.2f} seconds")
import time
start_time = time.time()
response = requests.get('https://api.example.com')
end_time = time.time()
print(f"Request took {end_time - start_time:.2f} seconds")
print(f"Response time from server: {response.elapsed.total_seconds():.2f} seconds")
import time
start_time = time.time()
response = requests.get('https://api.example.com')
end_time = time.time()
print(f"Request took {end_time - start_time:.2f} seconds")
print(f"Response time from server: {response.elapsed.total_seconds():.2f} seconds")
Error Handling and Status Codes
Proper error handling especially important when working with HTTP requests. Python Requests provides several ways to handle errors and check status codes. Let’s explore these methods:
1. Checking Status Codes
You can check the status code of a response using the status_code
attribute:
response = requests.get('https://api.example.com')
print(response.status_code)
if response.status_code == 200:
print("Request was successful")
elif response.status_code == 404:
print("Resource not found")
print(f"An error occurred: {response.status_code}")
response = requests.get('https://api.example.com')
print(response.status_code)
if response.status_code == 200:
print("Request was successful")
elif response.status_code == 404:
print("Resource not found")
else:
print(f"An error occurred: {response.status_code}")
response = requests.get('https://api.example.com')
print(response.status_code)
if response.status_code == 200:
print("Request was successful")
elif response.status_code == 404:
print("Resource not found")
else:
print(f"An error occurred: {response.status_code}")
2. Using raise_for_status()
The raise_for_status()
method raises an HTTPError for bad HTTP status codes:
response = requests.get('https://api.example.com/nonexistent')
response.raise_for_status()
except requests.exceptions.HTTPError as err:
print(f"HTTP error occurred: {err}")
try:
response = requests.get('https://api.example.com/nonexistent')
response.raise_for_status()
except requests.exceptions.HTTPError as err:
print(f"HTTP error occurred: {err}")
try:
response = requests.get('https://api.example.com/nonexistent')
response.raise_for_status()
except requests.exceptions.HTTPError as err:
print(f"HTTP error occurred: {err}")
3. Handling Connection Errors
You can catch various exceptions to handle different types of errors:
from requests.exceptions import RequestException
response = requests.get('https://api.example.com', timeout=3)
response.raise_for_status()
except requests.exceptions.Timeout:
print("The request timed out")
except requests.exceptions.ConnectionError:
print("A connection error occurred")
except requests.exceptions.HTTPError as err:
print(f"HTTP error occurred: {err}")
except RequestException as err:
print(f"An error occurred while handling your request: {err}")
import requests
from requests.exceptions import RequestException
try:
response = requests.get('https://api.example.com', timeout=3)
response.raise_for_status()
except requests.exceptions.Timeout:
print("The request timed out")
except requests.exceptions.ConnectionError:
print("A connection error occurred")
except requests.exceptions.HTTPError as err:
print(f"HTTP error occurred: {err}")
except RequestException as err:
print(f"An error occurred while handling your request: {err}")
import requests
from requests.exceptions import RequestException
try:
response = requests.get('https://api.example.com', timeout=3)
response.raise_for_status()
except requests.exceptions.Timeout:
print("The request timed out")
except requests.exceptions.ConnectionError:
print("A connection error occurred")
except requests.exceptions.HTTPError as err:
print(f"HTTP error occurred: {err}")
except RequestException as err:
print(f"An error occurred while handling your request: {err}")
4. Custom Error Handling
You can create custom error handling based on specific status codes or response content:
def handle_api_error(response):
if response.status_code == 400:
print("Bad request: The server couldn't understand the request")
elif response.status_code == 401:
print("Unauthorized: Authentication is required")
elif response.status_code == 403:
print("Forbidden: You don't have permission to access this resource")
elif response.status_code == 429:
print("Too Many Requests: You've exceeded the rate limit")
elif 500 <= response.status_code < 600:
print(f"Server Error: Something went wrong on the server side ({response.status_code})")
print(f"An unexpected error occurred: {response.status_code}")
response = requests.get('https://api.example.com')
if response.status_code != 200:
handle_api_error(response)
print("Request successful")
def handle_api_error(response):
if response.status_code == 400:
print("Bad request: The server couldn't understand the request")
elif response.status_code == 401:
print("Unauthorized: Authentication is required")
elif response.status_code == 403:
print("Forbidden: You don't have permission to access this resource")
elif response.status_code == 429:
print("Too Many Requests: You've exceeded the rate limit")
elif 500 <= response.status_code < 600:
print(f"Server Error: Something went wrong on the server side ({response.status_code})")
else:
print(f"An unexpected error occurred: {response.status_code}")
response = requests.get('https://api.example.com')
if response.status_code != 200:
handle_api_error(response)
else:
print("Request successful")
def handle_api_error(response):
if response.status_code == 400:
print("Bad request: The server couldn't understand the request")
elif response.status_code == 401:
print("Unauthorized: Authentication is required")
elif response.status_code == 403:
print("Forbidden: You don't have permission to access this resource")
elif response.status_code == 429:
print("Too Many Requests: You've exceeded the rate limit")
elif 500 <= response.status_code < 600:
print(f"Server Error: Something went wrong on the server side ({response.status_code})")
else:
print(f"An unexpected error occurred: {response.status_code}")
response = requests.get('https://api.example.com')
if response.status_code != 200:
handle_api_error(response)
else:
print("Request successful")
5. Retrying Failed Requests
You can implement a retry mechanism for failed requests:
from requests.exceptions import RequestException
def make_request_with_retry(url, max_retries=3, delay=1):
for attempt in range(max_retries):
response = requests.get(url)
response.raise_for_status()
except RequestException as err:
print(f"Attempt {attempt + 1} failed: {err}")
if attempt + 1 == max_retries:
response = make_request_with_retry('https://api.example.com')
print("Request successful")
except RequestException as err:
print(f"All retry attempts failed: {err}")
import time
from requests.exceptions import RequestException
def make_request_with_retry(url, max_retries=3, delay=1):
for attempt in range(max_retries):
try:
response = requests.get(url)
response.raise_for_status()
return response
except RequestException as err:
print(f"Attempt {attempt + 1} failed: {err}")
if attempt + 1 == max_retries:
raise
time.sleep(delay)
try:
response = make_request_with_retry('https://api.example.com')
print("Request successful")
except RequestException as err:
print(f"All retry attempts failed: {err}")
import time
from requests.exceptions import RequestException
def make_request_with_retry(url, max_retries=3, delay=1):
for attempt in range(max_retries):
try:
response = requests.get(url)
response.raise_for_status()
return response
except RequestException as err:
print(f"Attempt {attempt + 1} failed: {err}")
if attempt + 1 == max_retries:
raise
time.sleep(delay)
try:
response = make_request_with_retry('https://api.example.com')
print("Request successful")
except RequestException as err:
print(f"All retry attempts failed: {err}")
6. Logging Errors
Implement logging to keep track of errors:
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
response = requests.get('https://api.example.com')
response.raise_for_status()
except requests.exceptions.HTTPError as err:
logger.error(f"HTTP error occurred: {err}")
except RequestException as err:
logger.error(f"An error occurred while handling your request: {err}")
logger.info("Request successful")
import logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
try:
response = requests.get('https://api.example.com')
response.raise_for_status()
except requests.exceptions.HTTPError as err:
logger.error(f"HTTP error occurred: {err}")
except RequestException as err:
logger.error(f"An error occurred while handling your request: {err}")
else:
logger.info("Request successful")
import logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
try:
response = requests.get('https://api.example.com')
response.raise_for_status()
except requests.exceptions.HTTPError as err:
logger.error(f"HTTP error occurred: {err}")
except RequestException as err:
logger.error(f"An error occurred while handling your request: {err}")
else:
logger.info("Request successful")