Python9 min read

How to URL Encode in Python (urllib.parse Complete Guide)

Python URL encoding uses urllib.parse.quote() for percent-encoding strings and urllib.parse.urlencode() for encoding dictionaries into query strings. This guide covers quote(), unquote(), urlencode(), and parse_qs() with practical examples.

URL Encoding with quote()

The urllib.parse.quote() function is Python's primary tool for percent-encoding strings. It converts characters that are not safe for use in URLs into their percent-encoded equivalents. By default, it considers forward slashes (/) as safe characters, but you can customize this behavior.

from urllib.parse import quote

# Basic encoding
print(quote('hello world'))
# Output: hello%20world

# Encoding special characters
print(quote('price=10&qty=2'))
# Output: price%3D10%26qty%3D2

# By default, / is not encoded
print(quote('path/to/file'))
# Output: path/to/file

# To encode slashes too, set safe=''
print(quote('path/to/file', safe=''))
# Output: path%2Fto%2Ffile

# Encoding Unicode characters
print(quote('cafe'))
# Output: caf%C3%A9

# Specifying additional safe characters
print(quote('key=value&foo=bar', safe='=&'))
# Output: key=value&foo=bar

The safe parameter is the key to controlling what gets encoded. By default,safe='/'. If you want to encode everything except alphanumeric characters and _.-~, set safe=''. This is equivalent to JavaScript's encodeURIComponent().

There is also quote_plus() which works like quote() but encodes spaces as + instead of %20. This is the format used in HTML form data (application/x-www-form-urlencoded).

from urllib.parse import quote_plus

print(quote_plus('hello world'))
# Output: hello+world

print(quote_plus('key=value&name=John Doe'))
# Output: key%3Dvalue%26name%3DJohn+Doe

URL Decoding with unquote()

The urllib.parse.unquote() function reverses percent-encoding, converting %XX sequences back to their original characters. There is also unquote_plus() which additionally converts + signs to spaces.

from urllib.parse import unquote, unquote_plus

# Basic decoding
print(unquote('hello%20world'))
# Output: hello world

print(unquote('caf%C3%A9'))
# Output: cafe (with accent)

# unquote does NOT convert + to space
print(unquote('hello+world'))
# Output: hello+world

# unquote_plus converts + to space
print(unquote_plus('hello+world'))
# Output: hello world

# Decoding a full URL
url = 'https://example.com/search?q=C%2B%2B%20programming'
print(unquote(url))
# Output: https://example.com/search?q=C++ programming

Always use unquote_plus() when decoding form data, since HTML forms encode spaces as +. Use unquote() for general URL decoding where spaces are encoded as %20.

Encoding Query Strings with urlencode()

The urllib.parse.urlencode() function takes a dictionary or a list of tuples and converts it into a properly formatted query string. This is the most convenient way to build query strings in Python.

from urllib.parse import urlencode

# Dictionary to query string
params = {
    'q': 'python programming',
    'page': 1,
    'lang': 'en'
}
print(urlencode(params))
# Output: q=python+programming&page=1&lang=en

# List of tuples (preserves order, allows duplicate keys)
params = [
    ('tag', 'python'),
    ('tag', 'web'),
    ('sort', 'date')
]
print(urlencode(params))
# Output: tag=python&tag=web&sort=date

# Using doseq=True for list values
params = {
    'tag': ['python', 'web', 'api'],
    'sort': 'date'
}
print(urlencode(params, doseq=True))
# Output: tag=python&tag=web&tag=api&sort=date

# Using quote_via to control space encoding
from urllib.parse import quote
params = {'q': 'hello world'}
print(urlencode(params, quote_via=quote))
# Output: q=hello%20world  (uses %20 instead of +)

By default, urlencode() uses quote_plus() internally, which means spaces become +. If you need %20 for spaces, pass quote_via=quote as shown above.

Parsing Query Strings with parse_qs()

The urllib.parse.parse_qs() function parses a query string back into a dictionary. Each value in the dictionary is a list, since query parameters can have multiple values. There is also parse_qsl() which returns a list of tuples.

from urllib.parse import parse_qs, parse_qsl

# Parse a query string into a dictionary
qs = 'q=python+programming&page=1&lang=en'
result = parse_qs(qs)
print(result)
# Output: {'q': ['python programming'], 'page': ['1'], 'lang': ['en']}

# Note: values are always lists
print(result['q'][0])  # 'python programming'

# Handling multiple values for the same key
qs = 'tag=python&tag=web&tag=api'
result = parse_qs(qs)
print(result)
# Output: {'tag': ['python', 'web', 'api']}

# parse_qsl returns a list of tuples
result = parse_qsl(qs)
print(result)
# Output: [('tag', 'python'), ('tag', 'web'), ('tag', 'api')]

# Keep blank values (by default they are omitted)
qs = 'name=John&email=&age=30'
print(parse_qs(qs, keep_blank_values=True))
# Output: {'name': ['John'], 'email': [''], 'age': ['30']}

Encoding Full URLs with urlparse

When working with complete URLs, Python's urlparse() and urlunparse() functions let you safely decompose and reconstruct URLs. This is particularly useful when you need to modify specific parts of a URL without breaking its structure.

from urllib.parse import urlparse, urlunparse, urlencode, quote

# Parse a URL into components
url = 'https://example.com/search?q=hello&page=1#results'
parsed = urlparse(url)
print(parsed.scheme)    # 'https'
print(parsed.netloc)    # 'example.com'
print(parsed.path)      # '/search'
print(parsed.query)     # 'q=hello&page=1'
print(parsed.fragment)  # 'results'

# Build a URL from components
from urllib.parse import ParseResult
new_url = urlunparse(ParseResult(
    scheme='https',
    netloc='api.example.com',
    path='/v2/search',
    params='',
    query=urlencode({'q': 'python & java', 'limit': 10}),
    fragment=''
))
print(new_url)
# Output: https://api.example.com/v2/search?q=python+%26+java&limit=10

# Safely add a path segment with special characters
base = 'https://example.com/files/'
filename = 'my report (final).pdf'
safe_url = base + quote(filename, safe='')
print(safe_url)
# Output: https://example.com/files/my%20report%20%28final%29.pdf

For modern Python code, consider using the requests library, which handles URL encoding automatically when you pass parameters as a dictionary. The httpx library also provides similar automatic encoding capabilities.

import requests

# requests handles encoding automatically
response = requests.get(
    'https://api.example.com/search',
    params={
        'q': 'python & java',
        'page': 1,
        'sort': 'relevance'
    }
)
print(response.url)
# https://api.example.com/search?q=python+%26+java&page=1&sort=relevance

Related Articles

Try Our Free Tools