Отправка запросов с urllib.request в Python (полное руководство)
Основы отправки 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
Расширенные примеры работы с 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