Guide to Sending HTTP Requests in Python With Urllib3-1
Guide to Sending HTTP Requests in Python With Urllib3-1
Home Articles
ADVERTISEMENT ADVERTISEMENT
Introduction
Resources on the Web are located under some kind of web-address (even if they're not accessible), oftentimes
referred to as a URL (Uniform Resource Locator). These resources are, most of the time, manipulated by an
end-user (retrieved, updated, deleted, etc.) using the HTTP protocol through respective HTTP Methods.
In this guide, we'll be taking a look at how to leverage the urllib3 library, which allows us to send HTTP
Requests through Python, programmatically.
Note: The urllib3 module can only be used with Python 3.x.
What is HTTP?
HTTP (HyperText Transfer Protocol) is a data transfer protocol used for, typically, transmitting hypermedia
documents, such as HTML, but can also be used to transfer JSON, XML or similar formats. It's applied in the
Application Layer of the OSI Model, alongside other protocols such as FTP (File Transfer Protocol) and IN THIS ARTICLE
SMTP (Simple Mail Transfer Protocol).
Introduction
HTTP is the backbone of the World Wide Web as we know it today and it's main task is to enable a What is HTTP?
communication channel between web browsers and web servers, through a life cycle of HTTP Requests and The urllib3 Module
HTTP Responses - the fundamental communication components of HTTP. HTTP Status Codes
It's based on the client-server model where a client requests a resource, and the server responds with the The Pool Manager
resource - or a lack thereof. How to Send HTTP Requests in Python with urllib3
If the server finds the resource, the HTTP Response's header will contain data on how the request/response
cycle fared:
Project
HTTP/1.1 200 OK
Date: Thu, 22 Jul 2021 18:16:38 GMT
Building Your First Convolutional
Content-Type: text/html; charset=utf-8 Neural Network With Keras
Transfer-Encoding: chunked #python #artificial intelligence #machine learning
Connection: keep-alive
#tensorflow
...
And the response body will contain the actual resource - which in this case is an HTML page: importing and finish at validation. There's much more to
know. Why was a class predicted? Where was...
<!DOCTYPE html>
<html lang="en">
David Landup Details
<head>
<meta name="twitter:title" content="Stack Abuse"/>
<meta name="twitter:description" content="Learn Python, Java, JavaScript/Node, Machine Learning, and Web De
<meta name="twitter:url" content="https://stackabuse.com"/>
<meta name="twitter:site" content="@StackAbuse"/> ADVERTISEMENT
You can check your version of urllib3 by accessing the __version__ of the module:
import urllib3
Alternatively, you can use the Requests module, which is built on top of urllib3 . It's more intuitive and
human-centered, and allows for a wider range of HTTP requests. If you'd like to read more about it - read
our Guide to the Requests Module in Python.
Course
Is there a problem? If so, is it due to the request, the server or me?
Data Visualization in Python with
There are five different groups of response codes: Matplotlib and Pandas
#python #pandas #matplotlib
All responses to these requests are packed into an HTTPResponse instance, which, naturally, contains the status
of that response:
ADVERTISEMENT
import urllib3
http = urllib3.PoolManager()
You can use these statuses to alter the logic of the code - if the result is 200 OK , not much probably needs to be
done further. However, if the result is a 405 Method Not Allowed response - your request was probably badly
constructed.
However, if a website responds with a 418 I'm a teapot status code, albeit rare - it's letting you know that
you can't brew coffee with a teapot. In practice, this typically means that the server doesn't want to respond
to the request, and never will. If it were a temporary halt for certain requests - a 503 Service Unavailable
Note: The 418 I'm a teapot status code is a real but playful status code, added as an April Fools joke.
urllib3 keeps track of requests and their connections through the ConnectionPool and HTTPConnection classes.
Since making these by hand leads to a lot of boilerplate code - we can delegate the entirety of the logic to the
PoolManager , which automatically creates connections and adds them to the pool. By adjusting the num_pools
http = urllib3.PoolManager(num_pools=3)
Only through the PoolManager , can we send a request() , passing in the HTTP Verb and the address we're
sending a request to. Different verbs signify different intents - whether you want to GET some content, POST it to
a server, PATCH an existing resource or DELETE one.
To send an HTTP GET request in Python, we use the request() method of the PoolManager instance, passing in
the appropriate HTTP Verb and the resource we're sending a request for:
import urllib3
http = urllib3.PoolManager()
print(response.data.decode("utf-8"))
Here, we sent a GET request to {JSON} Placeholder. It's a website that generates dummy JSON data, sent
back in the response's body. Typically, the website is used to test HTTP Requests on, stubbing the response.
The HTTPResponse instance, namely our response object holds the body of the response. It can be accessed by
the data property which is a bytes stream. Since a website might respond with an encoding we're not suited
for, and since we'll want to convert the bytes to a str anyway - we decode() the body and encode it into UTF-8
to make sure we can coherently parse the data.
If you'd like to read more, read our about guide to Converting Bytes to Strings in Python.
Finally, we print the response's body:
[
{
"userId": 1,
"id": 1,
"title": "sunt aut facere repellat provident occaecati excepturi optio reprehenderit",
"body": "quia et suscipit\nsuscipit recusandae consequuntur expedita et cum\nreprehenderit molestiae ut ut qu
},
{
"userId": 1,
"id": 2,
"title": "qui est esse",
"body": "est rerum tempore vitae\nsequi sint nihil reprehenderit dolor beatae ea dolores neque\nfugiat blandi
},
...
Naturally, urllib3 allows us to add parameters to GET requests, via the fields argument. It accepts a
dictionary of the parameter names and their values:
import urllib3
ADVERTISEMENT
http = urllib3.PoolManager()
response = http.request("GET",
"http://jsonplaceholder.typicode.com/posts/",
fields={"id": "1"})
print(response.data.decode("utf-8"))
[
{
"userId": 1,
"id": 1,
"title": "sunt aut facere repellat provident occaecati excepturi optio reprehenderit",
"body": "quia et suscipit\nsuscipit recusandae consequuntur expedita et cum\nreprehenderit molestiae ut
}
]
import urllib3
http = urllib3.PoolManager()
response = http.request("POST", "http://jsonplaceholder.typicode.com/posts", fields={"title": "Created Post", "bo
print(response.data.decode("utf-8"))
Even though we're communicating with the same web address, because we're sending a POST request, the
fields argument will now specify the data that'll be sent to the server, not retrieved.
We've sent a JSON string, denoting an object with a title , body and userId . The {JSON} Placeholder service
also stubs the functionality to add entities, so it returns a response letting us know if we've been able to "add" it
to the database, and returns the id of the "created" post:
{
"id": 101
}
import urllib3
http = urllib3.PoolManager()
for i in range(1, 5):
response = http.request("DELETE", "http://jsonplaceholder.typicode.com/posts", fields={"id": i})
print(response.data.decode("utf-8"))
{}
{}
{}
{}
When creating a REST API - you'll probably want to give some status code and message to let the user know
that a resource has been deleted successfully.
Let's get the first post and then update it with a new title and body :
import urllib3
data = {
'title': 'Updated title',
'body': 'Updated body'
}
http = urllib3.PoolManager()
{
"userId": 1,
"id": 1,
"title": "sunt aut facere repellat provident occaecati excepturi optio reprehenderit",
"body": "quia et suscipit\nsuscipit recusandae consequuntur expedita et cum\nreprehenderit molestiae ut ut quas
}
{
"userId": 1,
"id": 1,
"title": "Updated title",
"body": "Updated body"
}
import urllib3
import certifi
http = urllib3.PoolManager(ca_certs=certifi.where())
response = http.request("GET", "https://httpbin.org/get")
print(response.status)
and pass in the filename as well as its contents as a tuple of file_name: file_data .
ADVERTISEMENT
To read the contents of a file, we can use Python's built-in read() method:
import urllib3
import json
with open("file_name.txt") as f:
file_data = f.read()
print(json.loads(resp.data.decode("utf-8"))["files"])
For the purpose of the example, let's create a file named file_name.txt and add some content:
When we send files using urllib3 , the response's data contains a "files" attribute attached to it, which we
access through resp.data.decode("utf-8")["files"] . To make the output a bit more readable, we use the json
You can also supply a third argument to the tuple, which specifies the MIME type of the uploaded file:
Conclusion
In this guide, we've taken a look at how to send HTTP Requests using urllib3 , a powerful Python module for
handling HTTP requests and responses.
We've also taken a look at what HTTP is, what status codes to expect and how to interpret them, as well as
how to upload files and send secure requests with certifi .
How to Get and Parse HTTP POST Body in Flask - JSON and Form Data
How to Upload Files with Python's requests Library
Serving Files with Python's SimpleHTTPServer Module
How to POST JSON Data Using requests Library in Python
Handling Unix Signals in Python
Improve your dev skills!
Get tutorials, guides, and dev jobs in your inbox.