Отправка запросов с urllib.request в Python (полное руководство)

Раздел: Сетевое программирование -> HTTP

Основы отправки HTTP запросов с urllib.request

Модуль urllib.request входит в стандартную библиотеку Python и позволяет выполнять HTTP запросы без установки сторонних пакетов. Это базовое, но мощное средство для работы с сетью, которое подходит для простых задач: получение содержимого страниц, отправка форм, работа с REST API.

Наиболее эффективный способ - использовать функцию urlopen() для GET и POST запросов. Она возвращает объект-ответ, из которого можно прочитать данные, заголовки и код статуса.


import urllib.request

# GET запрос
response = urllib.request.urlopen('https://httpbin.org/get')
print(response.status)  # 200
print(response.read().decode('utf-8'))

# POST запрос с данными в теле
data = b'key=value'
response = urllib.request.urlopen('https://httpbin.org/post', data=data)
print(response.read().decode('utf-8'))
  

Python requests get (get-запрос через requests в python)

Проблема: кодирование данных для POST. Если data не байтовая строка, возникает ошибка TypeError. Решение: использовать urllib.parse.urlencode() для преобразования словаря в строку, затем encode().

Как настроить заголовки запроса?

Для добавления заголовков используется класс Request. Это полезно, например, для имитации браузера или добавления токена авторизации.


import urllib.request

url = 'https://httpbin.org/headers'
req = urllib.request.Request(url, headers={'User-Agent': 'Mozilla/5.0'})
response = urllib.request.urlopen(req)
print(response.read().decode())
  

Get html python (получение html-содержимого через http в python)

Ошибка 403 Forbidden часто возникает, если сервер проверяет User-Agent. Решение - добавить корректный заголовок через Request.

Как обработать ошибки HTTP (404, 500)?

Используйте исключение urllib.error.HTTPError. Можно получить код ошибки и ответное тело.


import urllib.request
from urllib.error import HTTPError

try:
    response = urllib.request.urlopen('https://httpbin.org/status/404')
except HTTPError as e:
    print('Код:', e.code)
    print('Ответ:', e.read().decode())
  

Url запрос python (работа с url в python)

Как передать параметры в URL (query string)?

Для формирования корректной строки запроса используйте urllib.parse.urlencode(). Результат добавляется к URL после символа ?.


import urllib.request
import urllib.parse

params = {'q': 'python', 'page': 1}
query_string = urllib.parse.urlencode(params)
url = 'https://httpbin.org/get?' + query_string

response = urllib.request.urlopen(url)
print(response.read().decode())
  

Python urllib request (отправка запросов с помощью urllib.request в python)

Как установить таймаут для запроса?

Параметр timeout в urlopen() задаётся в секундах. Помогает избежать зависаний при медленных ответах.


import urllib.request

try:
    response = urllib.request.urlopen('https://httpbin.org/delay/5', timeout=3)
except TimeoutError:
    print('Запрос превысил время ожидания')
  

Files upload python (загрузка файлов на сервер с помощью python (requests, flask))

Как работать с редиректами?

По умолчанию urllib автоматически следует редиректам (коды 301, 302). Отключить это поведение можно через создание собственного HTTPRedirectHandler.


import urllib.request
from urllib.request import HTTPRedirectHandler

class NoRedirect(HTTPRedirectHandler):
    def redirect_request(self, req, fp, code, msg, headers, newurl):
        return None  # не перенаправлять

opener = urllib.request.build_opener(NoRedirect)
response = opener.open('https://httpbin.org/redirect/1')
print('Код:', response.status)  # 302, а не 200
  
- Python send request (отправка http-запроса в python (requests.get/post))
- Python post file (отправка файла через post-запрос (requests.post(file)) в python)
- Python requests параметры (передача параметров в get/post запросах requests в python)

Расширенные примеры работы с urllib.request

Загрузка файла с прогрессом и сохранением

Пример

import urllib.request
import os

def download_file(url, local_filename):
    response = urllib.request.urlopen(url)
    total = int(response.headers.get('Content-Length', 0))
    downloaded = 0
    chunk_size = 8192

    with open(local_filename, 'wb') as f:
        while True:
            chunk = response.read(chunk_size)
            if not chunk:
                break
            f.write(chunk)
            downloaded += len(chunk)
            if total:
                progress = (downloaded / total) * 100
                print(f'Загружено {downloaded}/{total} байт ({progress:.1f}%)', end='\r')
    print()
    return local_filename

url = 'https://httpbin.org/image/png'
file_path = download_file(url, 'image.png')
print(f'Файл сохранён: {file_path}')
Загружено 8192/8192 байт (100.0%)
Файл сохранён: image.png

Использование базовой аутентификации (HTTP Basic Auth)

Пример

import urllib.request
from urllib.request import HTTPBasicAuthHandler, build_opener, install_opener

auth_handler = HTTPBasicAuthHandler()
auth_handler.add_password(realm=None,
                          uri='https://httpbin.org',
                          user='user',
                          passwd='pass')  # пароль не шифруется, только base64
opener = build_opener(auth_handler)
install_opener(opener)

response = urllib.request.urlopen('https://httpbin.org/basic-auth/user/pass')
print(response.read().decode())
{
  "authenticated": true,
  "user": "user"
}

Работа с куки через HTTPCookieProcessor

Пример

import urllib.request
from http.cookiejar import CookieJar

cookie_jar = CookieJar()
opener = urllib.request.build_opener(urllib.request.HTTPCookieProcessor(cookie_jar))

# Первый запрос - сервер может установить куку
opener.open('https://httpbin.org/cookies/set?name=value')
print('Куки после первого запроса:', list(cookie_jar))

# Второй запрос - кука будет отправлена автоматически
response = opener.open('https://httpbin.org/cookies')
print('Ответ с кукой:', response.read().decode())
Куки после первого запроса: [<Cookie name=value for httpbin.org />]
Ответ с кукой: {
  "cookies": {
    "name": "value"
  }
}

Установка кастомного SSL контекста (например, для игнорирования сертификата)

Пример

import ssl
import urllib.request

# Создаём контекст, который не проверяет сертификат (только для отладки!)
ssl_context = ssl.create_default_context()
ssl_context.check_hostname = False
ssl_context.verify_mode = ssl.CERT_NONE

response = urllib.request.urlopen('https://self-signed.badssl.com/', context=ssl_context)
print(response.status)
200

Работа с прокси-сервером

Пример

import urllib.request

proxy_handler = urllib.request.ProxyHandler({'http': 'http://proxy.example.com:8080',
                                              'https': 'http://proxy.example.com:8080'})
opener = urllib.request.build_opener(proxy_handler)
response = opener.open('https://httpbin.org/ip')
print(response.read().decode())  # IP, видимый через прокси
{
  "origin": "203.0.113.5"
}

Парсинг JSON ответа с использованием json.loads

Пример

import urllib.request
import json

response = urllib.request.urlopen('https://api.github.com/repos/python/cpython')
data = json.loads(response.read().decode())
print('Полное имя:', data['full_name'])
print('Звёзды:', data['stargazers_count'])
Полное имя: python/cpython
Звёзды: 61900

Отправка запросов с помощью urllib.request в Python - comments

En
Python urllib request (python)