Introduction

The requests Python package is an HTTP library created by Kenneth Reitz. It's a very well known package in the Python community for making HTTP requests easy to create and call. This tutorial will cover the basics that you will need to know and will want to know when making HTTP requests in Python.

Learning how to send HTTP requests allows you to query websites and API's for data or even a webpage so you can scrape data out with something like Beatifulsoup.

Installation

To install the requests module, first make sure you have pip setup. If not, follow my tutorial on setting up pip. After making sure pip is working, execute pip install requests. When this is successful, open Python IDLE and execute import requests; if no errors occur, the requests module has been installed successfully.

Making a Simple Request

Just like your browser does, you can request a web page using Python. Get the URL of a website and use the following code to download the content of the page.

import requests

r = requests.get('https://nitratine.net/blog/')
print (r.text)

When executing this, a lot of text should be printed. This is the content returned by the site requested, in the case of using the URL demonstrated above, the content will be HTML that renders my blog feed.

In this example, I have called requests.get passing my URL to be fetched. This function then returns a requests.models.Response object. Using the .text attribute, I can look at the data that was returned by the URL I called.

When a browser calls a web page, it initially requests the URL being visited and then calls other URLs that are referenced in the HTML document to render the page with the CSS, JS, image and other files required.

Attributes You Should Know About

The Response object that was returned in the example above contains many useful attributes. Here are some ones you should know about:

  • .content: The raw content of the request
  • .text: The text content of the request
  • .status_code: The status code of the response; e.g. 200 OK, 404 Not Found, 418 Short and Stout...
  • .headers: The headers of the response
  • .cookies: The cookies returned in the response. You can access cookie value like you would use a dict: response.cookies['logged_in'].

To get the value of these attributes, use them as I did in the previous code example.

.json()

If a site returns a JSON response, you can call .json() on the Response object to convert the JSON object in the response to a Python dictionary.

import requests

request = requests.get('https://jsonplaceholder.typicode.com/todos/1')
data = request.json()
print('Title: ' + data['title'])

This saves the effort on deserializing the .text value using the ast module.

Downloading an Image and Other Files

Just like downloading a web page, you can also download other files like images or videos. Simply find the URL of the image/other file (make sure it is the URL of the file, not the URL of the page it's on) and use it like before; but this time put the content into a file.

import requests

file_destination = 'nitratine-logo.png'
url = "https://nitratine.net/static/img/logo.png"
response = requests.get(url)
if response.status_code == 200:
    with open(file_destination, 'wb') as f: # Make sure to use wb are we are writing bytes
        f.write(response.content)

If you expect the file to be large (or just want to use a stream), you can use a stream to write to the output file as you receive the data. This means as the data comes in, it is written to the output file so the data does not have to sit in memory.

import requests

file_destination = 'multi-clipboard.gif'
url = 'https://nitratine.net/posts/multi-clipboard/multi-clipboard.gif'
r = requests.get(url, stream=True)
if r.status_code == 200:
    with open(file_destination, 'wb') as f:
        for chunk in r:
            # print('Writing chunk') # Uncomment this to show that the file is being written chunk-by-chunk when parts of the data is received
            f.write(chunk) # Write each chunk received to a file

These examples have been modified from stackoverflow.com/a/13137873

Different Methods

When making a request to a URL/URI, different 'methods' can be used. These tell the server what sort of action you want to perform. HTTP defines actions like GET, POST, PUT, DELETE and many others.

To use these different methods, simply replace the .get with .post/.put/.delete or whatever method you are using. For example, if I wanted to delete a record in a REST API, I could use:

import requests

r = requests.delete('https://jsonplaceholder.typicode.com/posts/1')
assert r.status_code == 200 # Check for HTTP 200 (OK)

Parameters in URLs

Instead of constructing a URL to add parameters to it, the requests module offers a method to add them automatically for you. Simply create your key-value pairs in a Python dictionary and then pass this to the params argument in the request method. For example:

import requests

parameters = { 'key1' : 'value1', 'key2' : 'value2' }
r = requests.get('https://httpbin.org/get', params=parameters)
print (r.text)

To show that the parameters were added to the url, we can verify it using a PreparedRequest.

import requests

parameters = { 'key1' : 'value1', 'key2' : 'value2' }
req = requests.Request('GET','https://httpbin.org/get', params=parameters)
prepared = req.prepare() # Get a PreparedRequest object
print (prepared.url)

The output of the above script is "https://httpbin.org/get?key1=value1&key2=value2" as expected.

Sending Data in HTTP Body

When making calls to endpoints that require data in the body, we can use form-encoded, JSON or raw bodies.

Form Encoded Body

In cases where you want to send some form-encoded data (like a HTML form would submit), we can pass key-value pairs as we used above to the data parameter. The dictionary of your data will be form-encoded when the request is made. For example:

import requests

body_data = { 'key1' : 'value1', 'key2' : 'value2' }
r = requests.post('https://example.com/create-something', data=body_data)

JSON Body

Today, JSON bodies are becoming more popular over form-encoded key-value pairs; this is due to how much more compact JSON is over XML (XML and JSON are typically used to carry larger payloads). Fortunately, JSON bodies are as easy to create in the request module as form-encoded are.

Instead of passing your dictionary to the data parameter, pass it to json. When the request is made, the Content-Type header will automatically be set to application/json to tell the server that this is a JSON request.

import requests

body_data = { 'key1' : 'value1', 'key2' : 'value2' }
r = requests.post('https://example.com/create-something', json=body_data)

Raw Body

In the cases where you want to specify exactly what is in the body manually, simply provide the string to the body parameter. For example:

import requests

body_data = "This is my body"
r = requests.post('https://example.com/create-something', data=body_data)

Custom headers

Previously I discussed that the Content-Type header will automatically be set to application/json when passing data to json. We can set headers manually is a very similar way to how we have been sending data. Once again, create the header key-value pairs in a Python dictionary and then pass them to the headers parameter.

import requests

header_data = {
    'User-Agent' : 'Python requests',
    'X-My-Header-Key' : 'My header value'
}
r = requests.post('https://example.com/', headers=header_data)

This is Only The Basics

Please know that these are only the basics of the requests library and there is a lot more to offer from this library; this tutorial however, should help you understand what you need to do to request and send data.

If you want to read up more on this library, Google is full of answers but the docs at requests.readthedocs.io is great for reference material.

I Don't Have s Server, How Can I Test These?

webhook.site is an amazing place to test requests. Simply going to the page will create a new webhook for you to use - copy the unique URL at the top of the page (not the URL address bar). Now whenever you make a request to that URL, you will be able to see the content of the request you made.