DEV Community

Scrapfly
Scrapfly

Posted on • Originally published at scrapfly.io on

Guide to Python requests POST method

Guide to Python requests POST method

Python’s requests library is a powerful and http client library tool that simplifies API communication, especially for making POST requests. Whether you're building an application that interacts with remote APIs or web scraping, mastering the POST method with requests is a foundational skill for efficient web development.

This guide provides a comprehensive walkthrough of using Python requests to make POST requests, a crucial method for sending data to servers. We'll cover examples, common challenges and best practices.

For those new to the library, you can get started by installing it with pip install requests to follow along with this guide.

What Are HTTP POST Requests?

HTTP is the backbone of communication between web clients (like browsers or applications) and servers. This protocol uses requests to exchange data and there can be of multiple method types:

  • GET : Retrieves data from the server without altering it.
  • POST : Sends data to the server, ideal for:
    • Creating new records (e.g., user accounts).
    • Submitting forms or user inputs.
    • Transmitting files or sensitive data.
  • PUT : Updates existing resources, such as modifying user profiles.
  • DELETE : Removes specified resources from the server.
  • PATCH : Partially updates existing resources.
  • HEAD : Requests only the headers (meta info) of a response without the body.
  • OPTIONS : Checks which HTTP methods are supported by a server.

Using the requests POST in Python is essential for interactions that send data to servers and there can be many use cases for this method — let's take a look at that next.

Why Use POST for Data Submission?

Understanding when to use POST over other HTTP methods is key in web development. Unlike GET, which sends data as part of the limited URL parameters, POST sends data through the request body. This allows to accomodate larger payloads and keeping data hidden for security. This makes POST method ideal for:

  • Creating a new record : Adding a new user, posting a comment, or uploading a document.
  • Submitting form data : When users submit information via a contact form, search form, or account setup.
  • Transmitting sensitive data : Unlike GET, POST requests do not display parameters in the URL, providing an added layer of security for sensitive information.

With a clear understand of what POST requests are, let’s now explore how to send them in Python using the requests library, covering essential formats like JSON, form data, and file uploads.

Using Python Requests to Send POST Requests

The requests.post() function is your primary tool for sending POST requests in Python. It allows for customizable and straightforward data sending by specifying the URL, headers, and the data itself. The most common data types include JSON, form data, or raw body data, all handled easily with python requests POST method. For example:

Basic python requests post example for sending a POST request:

import requests

response = requests.post('https://httpbin.dev/post', data={'key': 'value'})
# or start a persisten session:
session = requests.Session()
response = session.post('https://httpbin.dev/post', data={'key': 'value'})

# Check response content
print(response.status_code)
print(response.text)

Enter fullscreen mode Exit fullscreen mode

Using requests.Session() allows you to persist certain parameters (such as cookies or headers) across multiple requests. This can be crucial when working with POST requests as often the server is tracking current client state and can return different data or even block POST requests missing specific headers or cookies.

Different Content Types

The HTTP Content-Type header is critical in POST requests as it specifies the format of the data being sent, which ensures that the server can correctly interpret the request.

Some servers support multiple POST content types, while others require specific formats. Here are some common Content-Type header and what they are used for:

  • application/json represents JSON format commonly used in API communication.
  • application/x-www-form-urlencoded used in HTML form submissions, encoding data as URL-encoded key-value pairs.
  • multipart/form-data designed for file uploads, supporting mixed content like binary files and text in a single request.

To set the Content-Type header in python requests use the headers parameter:

import requests
response = requests.post(
    'https://httpbin.dev/post', 
    headers={
        "Content-Type": "application/json",
    },
    data='{ "key": "value" }'
)

Enter fullscreen mode Exit fullscreen mode

With that in mind let's take a look at the most common data formats used in POST requests next.

How to POST JSON Data

JSON (JavaScript Object Notation) is a commonly used format for API communication as it's easily structured and parsed. It's natively available in JavaScript and in Python it can be easily cast to Python dictionary using the json module.

Using requests library sending Python requests POST with JSON data is straightforward. Use the json parameter in requests.post(), which automatically handles encoding and sets the Content-Type header:

import requests

data = {'username': 'ziad', 'password': '1234'}
response = requests.post('https://httpbin.dev/api', json=data)

Enter fullscreen mode Exit fullscreen mode

JSON is by far the most popular POST data type often encountered in scenarios such as:

  • User Authentication : When logging in or signing up, JSON is used to send credentials and receive authentication tokens.
  • Data Retrieval and Submission : APIs for fetching or updating data, such as weather, stock prices, or user profiles, typically respond with JSON, and often require JSON for sending updates.
  • Configuration Settings : Many applications use JSON to send or receive configuration details, allowing flexible setup based on user preferences or system requirements.
  • Form Submissions in Web Apps : JSON is also common in applications where forms or user inputs are submitted, such as surveys or e-commerce transactions.

How to POST Form Data

Form Data is used when users interact with input fields on a webpage like:

  • Performing login
  • Submitting a search
  • Submitting user generated content like comments or posts

Form data sends data with Content-Type header application/x-www-form-urlencoded and URL-encodes data in a key-value format. Let's see an example of how to POST Form Data with Python Requests to better understand this format:

form_data = {'search': 'product 1 & 2', 'count': 10}
response = requests.post(
    'https://httpbin.dev/post', 
    data=form_data,
)
# this will automatically add the Content-Type header
# and convert data from dictionary to URL encoded format
print(response.request.body)
'search=product+1+%26+2&count=10'
print(response.request.headers['Content-Type'])
'application/x-www-form-urlencoded'

# alternatively if we POST data as string
# we need to manually identify Content-Type
response = requests.post(
    'https://httpbin.dev/post', 
    data='search=product+1+%26+2&count=10'
    headers={
        "Content-Type": "application/x-www-form-urlencoded"
    }
)
print(response.request.body)
'search=product+1+%26+2&count=10'
print(response.request.headers['Content-Type'])
'application/x-www-form-urlencoded'

Enter fullscreen mode Exit fullscreen mode

In the above example the Content-Type header is automatically set when we're using a python dictionary as the data parameter. Otherwise, if we pass a string, we need to manually set the Content-Type header.

Sending Files

To send files using Python’s requests library the files parameter can be used. This parameter takes bytes data and automatically sets the Content-Type header to multipart/form-data. This is useful for uploading images, documents, or media content. Let's take a look at some examples of how to upload a file using Python requests POST:

import requests
from pathlib import Path

image_path = Path('./profile_picture.jpg')
with image_path.open('rb') as image_file:
    response = requests.post(
        'https://httpbin.org/post', 
        files={'file': image_file},
    )
print(response.json())
{
    "args": {},
    "data": "",
    "files": {
        "file": "data:application/octet-stream;base64,UklGRoIwAABXR..."
    },
    "form": {},
    "headers": {
        "Accept": "*/*",
        "Accept-Encoding": "gzip, deflate, br",
        "Content-Length": "12572",
        "Content-Type": "multipart/form-data; boundary=bfcc14d5a32e8b678e9b9004c5bcd9c8",
        "Host": "httpbin.org",
        "User-Agent": "python-requests/2.32.3",
    },
    "json": null,
    "origin": "49.222.251.131",
    "url": "https://httpbin.org/post"
}

Enter fullscreen mode Exit fullscreen mode

Above we see that we can either provide a file object for requests to stream the data to the server or provide byte data directly.

Handling POST Responses in Python

After making a POST request it's a good practice to verify the response for errors or meta notes. For that, the requests' Response object provides attributes like status_code, headers, and json() that help assess success or diagnose issues.

To start, inspect response.status_code to verify whether a successful POST request was made with response 200 OK. Otherwise, refer to this handy table below.

Common POST Response Issues and How to Resolve Them

Status Code Issue Description Solution
400 Bad Request Incorrect data or syntax error The server couldn't process the request due to data format issues. Check the data format and headers (e.g., Content-Type) for correctness.
401 Unauthorized Missing or invalid authentication The request lacks valid authentication credentials. Include valid API keys or tokens in headers.
403 Forbidden Access denied The server refuses to authorize the request. Verify permissions and check the API documentation for access requirements.
404 Not Found Incorrect URL The server cannot find the requested endpoint. Double-check the endpoint URL for typos and ensure it’s valid.
405 Method Not Allowed Unsupported HTTP method The endpoint does not support the HTTP method used. Confirm the correct HTTP method is used by consulting the API documentation.
500 Internal Server Error Server-side error A generic error indicating an internal server issue. Retry the request; contact API support if the issue persists.
503 Service Unavailable Temporary overload/maintenance The server is temporarily unavailable due to high traffic or maintenance. Wait and retry later; consider implementing retry logic for critical applications.

By monitoring response.status_code and incorporating error-handling logic, you can ensure robust, reliable interactions when making POST requests.

Here's an example to how to handle response status codes:

response = requests.post('https://httpbin.dev/post', data={'key': 'value'})

# Raise an error for bad responses (4xx and 5xx)
response.raise_for_status()

if response.status_code == 201:
    print("Request was successful!")
else:
    print("Error:", response.status_code)

Enter fullscreen mode Exit fullscreen mode

Knowing how to interpret these responses helps handle errors effectively, ensuring smooth user experiences and troubleshooting in API interactions.

Posting Compressed Data

To optimize data transfer bandwidth, you can POST Gzip or Brotli compressed data. Here’s an example of gzip compression:

import requests
import gzip
import json

data = json.dumps({'key': 'value'}).encode('utf-8')
compressed_data = gzip.compress(data)

headers = {'Content-Encoding': 'gzip'}

response = requests.post('https://httpbin.dev/api', data=compressed_data, headers=headers)
response.raise_for_status()

print("Gzip Compressed Request Status:", response.status_code)

Enter fullscreen mode Exit fullscreen mode

For Brotli compression the brotli package can be used:

import requests
import brotli

data = json.dumps({'key': 'value'}).encode('utf-8')
compressed_data = brotli.compress(data)

headers = {'Content-Encoding': 'br'}

response = requests.post('https://httpbin.dev/api', data=compressed_data, headers=headers)
response.raise_for_status()

print("Brotli Compressed Request Status:", response.status_code)

Enter fullscreen mode Exit fullscreen mode

Using compression reduces payload size significantly optimizing bandwidth and improving request speed. This is especially applicable to formats like JSON that can be compressed well.

Enhancing Performance with Concurrent POST Requests

POST requests, especially those involving large datasets or high volumes, can be slow due to the time needed for data transmission and server-side processing. Concurrency can mitigate these delays by allowing multiple requests to run simultaneously, speeding up tasks like bulk data uploads or API interactions.

Unfortunately, Python’s requests library doesn’t support asynchronous operations with asyncio, limiting its ability to handle many simultaneous POST requests efficiently.

This is where httpx comes in, as it offers an AsyncClient that integrates seamlessly with Python's asyncio event loop. This means you can send numerous requests concurrently without blocking, making httpx a powerful choice for high-performance applications that require true async support.

Alternatively, you can use threading to enable parallel requests in Python requests. Here's an example using built-in threading package with requests:

import threading
import requests

def post_data(data):
    requests.post('https://httpbin.dev/api', json=data)

# Sample data list
data_list = [{'name': 'User1'}, {'name': 'User2'}]

threads = []
for data in data_list:
    thread = threading.Thread(target=post_data, args=(data,))
    threads.append(thread)
    thread.start()

for thread in threads:
    thread.join()

Enter fullscreen mode Exit fullscreen mode

By using threading, multiple POST requests can be launched in parallel, allowing each thread to handle a single request.

You can learn more about Concurrency vs Parallelism in our dedicated article:

Concurrency vs Parallelism
(https://scrapfly.io/blog/concurrency-vs-parallelism/)

Power Up with Scrapfly

HTTP requests can be difficult and get complicated quickly with headless browser requirements or client blocking. For that, Scrapfly can give you a hand!

Guide to Python requests POST method

ScrapFly provides web scraping, screenshot, and extraction APIs for data collection at scale.

FAQ

To wrap up this guide, here are answers to some frequently asked questions about python requests POST.

How can I include custom headers in using Python requests?

Pass headers as a dictionary using the headers parameter. Note that requests automatically generates some headers like User-Agent, Content-Length and Content-Type, so be cautious when overriding them.

What is the difference between data and json parameters in Python requests?

data is for form-encoded (default) or raw data (when Content-Type header is overriden). While json is specifically for JSON format data and automatically sets Content-Type to application/json.

Does the Python requests library support asynchronous POST requests?

Unfortunately, the requests library does not support asynchronous requests. However, the httpx library is an alternative that provides async capabilities, making it suitable for applications requiring concurrency.

Summary

In this article we've taken a deep look at requests' POST method in Python and learned:

  • How are POST requests used to send data to servers of various types like JSON, form data, and file uploads.
  • How to handle POST request responses and common status codes and how to fix them.
  • How to enhance performance with concurrent POST requests using httpx or threading for parallel requests.
  • How to compress data for optimized bandwidth and speed using gzip and brotli modules.

There's much more to learn about Python requests and POST requests, but with this guide, you're well-equipped to start building robust applications and web scrapers that interact with APIs and servers effectively.

Top comments (0)