Основы работы с requests: от простого к сложному
Библиотека requests: основы HTTP-запросов на Python
Библиотека requests является стандартным инструментом для выполнения HTTP-запросов в Python. Она предоставляет простой интерфейс, позволяющий отправлять GET и POST запросы, управлять заголовками, куками, параметрами и обрабатывать ответы. Рассмотрим наиболее эффективные подходы и альтернативные варианты.
Наиболее эффективное решение - использование встроенных методов requests с автоматическим управлением соединениями и обработкой ответов. Установка библиотеки выполняется командой:
pip install requestsзапрос страницы python (запрос веб-страницы в python)
После установки можно отправлять базовый GET-запрос:
import requests
response = requests.get('https://api.example.com/data')
print(response.status_code) # 200
print(response.text) # содержимое ответаPython requests (библиотека requests в python)
200
{"key": "value"}
Ответ (объект Response) содержит статус, заголовки, тело. Для JSON данных удобно использовать response.json().
Типичная ошибка: забыть обработать статус ответа (например, 404). Рекомендуется вызывать raise_for_status() для автоматического выброса исключения при ошибках HTTP.
Как отправить GET-запрос с параметрами?
Параметры URL передаются через словарь params:
params = {'key1': 'value1', 'key2': 'value2'}
response = requests.get('https://api.example.com/search', params=params)
print(response.url) # https://api.example.com/search?key1=value1&key2=value2
https://api.example.com/search?key1=value1&key2=value2
Этот метод автоматически кодирует параметры, избавляя от ручной работы.
Проблема: если параметр имеет значение None, он будет пропущен. Для пустых значений используется пустая строка.
Как отправить POST-запрос с данными?
Для отправки формы используется аргумент data:
data = {'username': 'user', 'password': 'pass'}
response = requests.post('https://httpbin.org/post', data=data)
print(response.json())
{
"form": {
"password": "pass",
"username": "user"
}
}
Для отправки JSON-данных используйте json:
import json
data = {'key': 'value'}
response = requests.post('https://httpbin.org/post', json=data)
print(response.json()['json'])
{'key': 'value'}
json автоматически устанавливает заголовок Content-Type: application/json.
Ошибка: передача одновременно data и json может привести к игнорированию одного из них. Следует использовать только один вариант.
Как добавить заголовки и куки?
Заголовки передаются через словарь headers:
headers = {'User-Agent': 'Mozilla/5.0'}
cookies = {'session_id': 'abc123'}
response = requests.get('https://httpbin.org/cookies', headers=headers, cookies=cookies)
print(response.json())
{
"cookies": {
"session_id": "abc123"
}
}
Проблема: если передать куки через cookies и одновременно через заголовок Cookie, requests использует аргумент cookies. Не стоит дублировать.
Как использовать сессии для сохранения состояния?
Объект Session сохраняет куки и заголовки между запросами:
session = requests.Session()
session.headers.update({'User-Agent': 'my-app'})
session.get('https://httpbin.org/cookies/set?name=value')
response = session.get('https://httpbin.org/cookies')
print(response.json()['cookies'])
{"name": "value"}
Сессии также улучшают производительность за счет повторного использования TCP-соединений.
Ошибка: использование разных сессий для каждого запроса может привести к потере кук. Рекомендуется создавать одну сессию для группы взаимосвязанных запросов.
Как обрабатывать ошибки и таймауты?
Для обработки ошибок HTTP используется raise_for_status():
try:
response = requests.get('https://httpbin.org/status/404')
response.raise_for_status()
except requests.exceptions.HTTPError as err:
print(f"HTTP ошибка: {err}")
HTTP ошибка: 404 Client Error: NOT FOUND for url: https://httpbin.org/status/404
Таймаут задается аргументом timeout:
try:
response = requests.get('https://httpbin.org/delay/5', timeout=3)
except requests.exceptions.Timeout:
print("Запрос превысил время ожидания")
Запрос превысил время ожидания
Типичная ошибка: не устанавливать timeout, что может привести к зависанию программы. Всегда указывайте разумное значение (например, 10 секунд).
Как работать с прокси и SSL?
Прокси передаются словарем с ключами 'http' и 'https':
proxies = {
'http': 'http://proxy.example.com:8080',
'https': 'https://proxy.example.com:8080'
}
response = requests.get('https://httpbin.org/ip', proxies=proxies)
Для отключения проверки SSL (не рекомендуется для продакшена) используйте verify=False:
response = requests.get('https://self-signed.badssl.com', verify=False)
Проблема: отключение SSL делает соединение уязвимым. Для самоподписанных сертификатов лучше указать путь к CA-файлу через verify='/path/to/cert.pem'.
Как загружать и скачивать файлы?
Для скачивания файла используйте потоковую передачу с stream=True:
response = requests.get('https://httpbin.org/image/png', stream=True)
with open('image.png', 'wb') as f:
for chunk in response.iter_content(chunk_size=8192):
f.write(chunk)
Для отправки файла используйте аргумент files:
files = {'file': open('report.pdf', 'rb')}
response = requests.post('https://httpbin.org/post', files=files)
При больших файлах рекомендуется открывать их в бинарном режиме.
Ошибка: забыть закрыть файл. Лучше использовать менеджер контекста with open().
Как использовать авторизацию (Basic, Bearer)?
Для Basic-авторизации передается кортеж (логин, пароль):
response = requests.get('https://httpbin.org/basic-auth/user/pass', auth=('user', 'pass'))
print(response.status_code)
200
Для Bearer-токена используется заголовок Authorization:
headers = {'Authorization': 'Bearer token123'}
response = requests.get('https://api.example.com/protected', headers=headers)
Существует также класс HTTPDigestAuth для Digest-аутентификации.
Проблема: передача пароля в открытом виде при использовании HTTP (не HTTPS). Всегда используйте шифрование.
Расширенные примеры использования requests
Данный раздел содержит более сложные и редко встречающиеся сценарии работы с библиотекой requests.
1. Управление перенаправлениями (redirects)
По умолчанию requests автоматически следует редиректам. Для запрета используется параметр allow_redirects=False:
response = requests.get('https://httpbin.org/redirect/3', allow_redirects=False)
print(response.status_code) # 302
302
Можно отслеживать историю редиректов через response.history:
response = requests.get('https://httpbin.org/redirect/2')
for hist in response.history:
print(hist.status_code, hist.url)
302 https://httpbin.org/redirect/2 302 https://httpbin.org/relative-redirect/1
2. Использование адаптеров для настройки пула соединений
Адаптеры позволяют управлять количеством соединений. Например, для HTTP можно настроить пул:
from requests.adapters import HTTPAdapter
from requests.packages.urllib3.util.retry import Retry
session = requests.Session()
retries = Retry(total=3, backoff_factor=1, status_forcelist=[502, 503])
adapter = HTTPAdapter(max_retries=retries, pool_connections=100, pool_maxsize=100)
session.mount('http://', adapter)
session.mount('https://', adapter)
response = session.get('https://httpbin.org/status/502')
print(response.status_code)
200 # после повторных попыток (в примере httpbin вернет 200 при третьей попытке)
3. Загрузка больших файлов с прогресс-баром
Можно отображать прогресс с помощью tqdm:
import requests
from tqdm import tqdm
url = 'https://speed.hetzner.de/100MB.bin'
response = requests.get(url, stream=True)
total = int(response.headers.get('content-length', 0))
with open('100MB.bin', 'wb') as f, tqdm(desc='Download', total=total, unit='B', unit_scale=True) as pbar:
for chunk in response.iter_content(chunk_size=8192):
f.write(chunk)
pbar.update(len(chunk))
Download: 100%|██████████| 100M/100M [00:10<00:00, 9.8MB/s]
4. Отправка Multipart-форм с файлами и данными
Для отправки формы, включающей файл и текстовые поля, используется словарь с кортежами:
files = {
'file': ('report.pdf', open('report.pdf', 'rb'), 'application/pdf'),
'note': (None, 'some text')
}
response = requests.post('https://httpbin.org/post', files=files)
print(response.json()['files']['file'])
data:application/pdf;base64,JVBERi0xL... (содержимое файла в base64)
5. Использование custom User-Agent и Referer для имитации браузера
Некоторые API требуют специфических заголовков:
session = requests.Session()
session.headers.update({
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36',
'Accept': 'text/html,application/xhtml+xml',
'Accept-Language': 'ru-RU,ru;q=0.9',
'Referer': 'https://www.google.com/'
})
response = session.get('https://httpbin.org/headers')
print(response.json()['headers']['User-Agent'])
Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36
6. Аутентификация через OAuth2 с использованием requests-oauthlib
Для работы с OAuth2 требуется дополнительная библиотека:
from requests_oauthlib import OAuth2Session
import os
oauth = OAuth2Session(os.environ['CLIENT_ID'], redirect_uri='https://localhost/callback')
authorization_url, state = oauth.authorization_url('https://provider.com/oauth/authorize')
print('Перейдите по URL:', authorization_url)
# После редиректа извлекаем код
redirect_response = input('Вставьте полный URL редиректа: ')
token = oauth.fetch_token('https://provider.com/oauth/token', authorization_response=redirect_response, client_secret=os.environ['CLIENT_SECRET'])
response = oauth.get('https://api.provider.com/user')
print(response.json())
{'id': 123, 'name': 'John Doe'}
7. Проверка SSL сертификата и настройка CA bundle
Для использования собственного сертификата:
response = requests.get('https://example.com', verify='/path/to/custom_ca.pem')
Если не требуется проверка сертификата (только для тестов):
import urllib3
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
response = requests.get('https://self-signed.badssl.com', verify=False)
8. Использование параметра hooks для изменения поведения запроса
Хуки позволяют выполнять действия до или после запроса:
def print_url(r, *args, **kwargs):
print(f"Запрос к {r.url}")
response = requests.get('https://httpbin.org/get', hooks={'response': print_url})
Запрос к https://httpbin.org/get
9. Работа с временем выполнения (elapsed)
response.elapsed возвращает время, затраченное на запрос:
response = requests.get('https://httpbin.org/delay/1')
print(f"Время: {response.elapsed.total_seconds()} с")
Время: 1.002 с
10. Отправка запросов с HTTP-методами PUT, DELETE, PATCH
Аналогично GET и POST:
response_put = requests.put('https://httpbin.org/put', data={'key': 'value'})
response_del = requests.delete('https://httpbin.org/delete')
response_patch = requests.patch('https://httpbin.org/patch', data={'field': 'new'})