Вступление
Работа с HTTP-запросами - непростая задача для любого языка
программирования. Если говорить о Python, он поставляется с двумя
встроенными модулями urllib
и urllib2
для обработки операций,
связанных с HTTP. Оба модуля имеют разный набор функций, и часто их
нужно использовать вместе. Основным недостатком использования urllib
является то, что это сбивает с толку (несколько методов доступно как в
urllib
, так и в urllib2
), документация не ясна, и нам нужно
написать много кода, чтобы сделать даже простой HTTP-запрос.
Чтобы упростить эти вещи, доступна одна простая в использовании
сторонняя библиотека, известная как
Requests , и большинство
разработчиков предпочитают использовать ее вместо urllib
/ urllib2
.
Это лицензированная HTTP-библиотека
Apache2, работающая на urllib3 и
httplib
.
Установка модуля запросов
Установить этот пакет, как и большинство других пакетов Python, довольно просто. Вы можете либо загрузить исходный код запросов с Github и установить его, либо использовать pip:
$ pip install requests
Для получения дополнительной информации о процессе установки обратитесь к официальной документации .
Чтобы проверить установку, вы можете попробовать импортировать ее, как показано ниже:
import requests
Если при импорте модуля вы не получаете никаких ошибок, значит, он был успешным.
Создание запроса GET
GET на сегодняшний день является наиболее часто используемым методом HTTP. Мы можем использовать запрос GET для извлечения данных из любого места назначения. Сначала позвольте мне начать с простого примера. Предположим, мы хотим получить содержимое домашней страницы нашего веб-сайта и распечатать результат в виде HTML-данных. Используя модуль запросов, мы можем сделать это, как показано ниже:
import requests
r = requests.get('https://api.github.com/events')
print(r.content)
Он напечатает ответ в закодированной форме. Если вы хотите увидеть
фактический текстовый результат HTML-страницы, вы можете прочитать
.text
этого объекта. Точно так же status_code
выводит текущий код
состояния URL-адреса:
import requests
r = requests.get('https://api.github.com/events')
print(r.text)
print(r.status_code)
requests
расшифруют необработанный контент и покажут вам результат.
Если вы хотите проверить, какой тип encoding
используется requests
,
вы можете распечатать это значение, вызвав .encoding
. Даже тип
кодировки можно изменить, изменив его значение. Не все ли так просто?
Чтение ответа
Ответ на HTTP-запрос может содержать множество заголовков, содержащих различную информацию.
httpbin - популярный веб-сайт для тестирования различных операций HTTP. В этой статье мы будем использовать httpbin / get для анализа ответа на запрос GET. Прежде всего, нам нужно узнать заголовок ответа и то, как он выглядит. Вы можете использовать любой современный веб-браузер, чтобы найти его, но для этого примера мы будем использовать браузер Google Chrome.
- В Chrome откройте URL-адрес http://httpbin.org/get , щелкните правой кнопкой мыши в любом месте страницы и выберите параметр «Проверить».
- Это откроет новое окно в вашем браузере. Обновите страницу и перейдите на вкладку «Сеть».
- Эта вкладка «Сеть» покажет вам все различные типы сетевых запросов, сделанных браузером. Щелкните запрос «получить» в столбце «Имя» и выберите вкладку «Заголовки» справа.
{.ezlazyload .img-responsive}
Содержание «Заголовков ответа» является нашим обязательным элементом. Вы
можете увидеть пары ключ-значение, содержащие различную информацию о
ресурсе и запросе. Попробуем разобрать эти значения с помощью библиотеки
requests
import requests
r = requests.get('http://httpbin.org/get')
print(r.headers['Access-Control-Allow-Credentials'])
print(r.headers['Access-Control-Allow-Origin'])
print(r.headers['CONNECTION'])
print(r.headers['content-length'])
print(r.headers['Content-Type'])
print(r.headers['Date'])
print(r.headers['server'])
print(r.headers['via'])
Мы получили информацию заголовка с помощью r.headers
и мы можем
получить доступ к каждому значению заголовка с помощью определенных
ключей. Обратите внимание, что ключ не чувствителен к регистру .
Точно так же попробуем получить доступ к значению ответа. Заголовок выше
показывает, что ответ находится в формате JSON:
(Content-type: application/json)
. Библиотека запросов поставляется с
одним встроенным парсером JSON, и мы можем использовать
requests.get('url').json()
для анализа его как объекта JSON. Затем
значение для каждого ключа результатов ответа можно легко
проанализировать, как показано ниже:
import requests
r = requests.get('http://httpbin.org/get')
response = r.json()
print(r.json())
print(response['args'])
print(response['headers'])
print(response['headers']['Accept'])
print(response['headers']['Accept-Encoding'])
print(response['headers']['Connection'])
print(response['headers']['Host'])
print(response['headers']['User-Agent'])
print(response['origin'])
print(response['url'])
Приведенный выше код напечатает следующий вывод:
{'headers': {'Host': 'httpbin.org', 'Accept-Encoding': 'gzip, deflate', 'Connection': 'close', 'Accept': '*/*', 'User-Agent': 'python-requests/2.9.1'}, 'url': 'http://httpbin.org/get', 'args': {}, 'origin': '103.9.74.222'}
{}
{'Host': 'httpbin.org', 'Accept-Encoding': 'gzip, deflate', 'Connection': 'close', 'Accept': '*/*', 'User-Agent': 'python-requests/2.9.1'}
*/*
gzip, deflate
close
httpbin.org
python-requests/2.9.1
103.9.74.222
http://httpbin.org/get
Третья строка, т.е. r.json()
, напечатала значение ответа JSON. Мы
сохранили значение JSON в response
переменной, а затем распечатали
значение для каждого ключа. Обратите внимание, что в отличие от
предыдущего примера, пара "ключ-значение" чувствительна к регистру.
Подобно JSON и текстовому контенту, мы можем использовать requests
для
чтения контента ответа в байтах для нетекстовых запросов, используя
свойство .content
Это автоматически декодирует gzip
и deflate
закодированные файлы.
Передача параметров в GET
В некоторых случаях вам нужно будет передавать параметры вместе с вашими
запросами GET, которые принимают форму строк запроса. Для этого нам
нужно передать эти значения в params
, как показано ниже:
import requests
payload = {'user_name': 'admin', 'password': 'password'}
r = requests.get('http://httpbin.org/get', params=payload)
print(r.url)
print(r.text)
Здесь мы присваиваем значения наших параметров payload
, а затем -
запросу GET через params
. Приведенный выше код вернет следующий
результат:
http://httpbin.org/get?password=password&user_name=admin
{"args":{"password":"password","user_name":"admin"},"headers":{"Accept":"*/*","Accept-Encoding":"gzip, deflate","Connection":"close","Host":"httpbin.org","User-Agent":"python-requests/2.9.1"},"origin":"103.9.74.222","url":"http://httpbin.org/get?password=password&user_name=admin"}
Как видите, библиотека Reqeusts автоматически превратила наш словарь параметров в строку запроса и прикрепила ее к URL-адресу.
Обратите внимание, что вам нужно быть осторожным, какие данные вы передаете через запросы GET, поскольку полезная нагрузка видна в URL-адресе, как вы можете видеть в выходных данных выше.
Выполнение запросов POST
Запросы HTTP POST противоположны запросам GET, поскольку они предназначены для отправки данных на сервер, а не для их получения. Хотя запросы POST также могут получать данные в ответе, как и запросы GET.
Вместо использования get()
нам нужно использовать метод post()
. Для
передачи аргумента мы можем передать его внутри параметра data
import requests
payload = {'user_name': 'admin', 'password': 'password'}
r = requests.post("http://httpbin.org/post", data=payload)
print(r.url)
print(r.text)
Выход:
http://httpbin.org/post
{"args":{},"data":"","files":{},"form":{"password":"password","user_name":"admin"},"headers":{"Accept":"*/*","Accept-Encoding":"gzip, deflate","Connection":"close","Content-Length":"33","Content-Type":"application/x-www-form-urlencoded","Host":"httpbin.org","User-Agent":"python-requests/2.9.1"},"json":null,"origin":"103.9.74.222","url":"http://httpbin.org/post"}
По умолчанию данные будут "закодированы в форме". Вы также можете передавать более сложные запросы заголовков, такие как кортеж, если несколько значений имеют один и тот же ключ, строку вместо словаря или файл с многокомпонентным кодированием.
Отправка файлов с помощью POST
Иногда нам нужно отправить на сервер один или несколько файлов одновременно. Например, если пользователь отправляет форму, а форма включает в себя различные поля формы для загрузки файлов, такие как изображение профиля пользователя, резюме пользователя и т. Д. Запросы могут обрабатывать несколько файлов в одном запросе. Этого можно добиться, поместив файлы в список кортежей, как показано ниже:
import requests
url = 'http://httpbin.org/post'
file_list = [
('image', ('image1.jpg', open('image1.jpg', 'rb'), 'image/png')),
('image', ('image2.jpg', open('image2.jpg', 'rb'), 'image/png'))
]
r = requests.post(url, files=file_list)
print(r.text)
Кортежи, содержащие информацию о файлах, имеют форму
(field_name, file_info)
.
Другие типы HTTP-запросов
Подобно GET и POST, мы можем выполнять другие HTTP-запросы, такие как
PUT, DELETE, HEAD и OPTIONS, используя requests
, как показано ниже:
import requests
requests.put('url', data={'key': 'value'})
requests.delete('url')
requests.head('url')
requests.options('url')
Обработка перенаправлений
Перенаправление в HTTP означает перенаправление сетевого запроса на другой URL-адрес. Например, если мы сделаем запрос на « http://www.github.com », он будет перенаправлен на « https://github.com » с использованием 301 редиректа .
import requests
r = requests.post("http://www.github.com")
print(r.url)
print(r.history)
print(r.status_code)
Выход:
https://github.com/
[<Response [301]>, <Response [301]>]
200
Как видите, процесс перенаправления автоматически обрабатывается
requests
, поэтому вам не нужно заниматься этим самостоятельно.
Свойство history
содержит список всех объектов ответа, созданных для
выполнения перенаправления. В нашем примере Response
с кодом ответа
301. Ответы HTTP 301 и 302 используются для постоянного и временного
перенаправления соответственно.
Если вы не хотите, чтобы библиотека запросов автоматически
allow_redirects=False
вместе с запросом.
Обработка тайм-аутов
Другая важная конфигурация сообщает нашей библиотеке, как обрабатывать
тайм-ауты или запросы, на возврат которых уходит слишком много времени.
Мы можем настроить requests
чтобы они перестали ждать сетевых
запросов, используя параметр timeout
По умолчанию время requests
не
истекает. Итак, если мы не настроим это свойство, наша программа может
зависнуть на неопределенное время, что не является той
функциональностью, которую вы хотели бы иметь в процессе, заставляющем
пользователя ждать.
import requests
requests.get('http://www.google.com', timeout=1)
Здесь будет выброшено исключение, если сервер не ответит в течение 1 секунды (что по-прежнему агрессивно для реального приложения). Чтобы это происходило чаще (для примера), вам нужно установить предел тайм-аута на гораздо меньшее значение, например 0,001.
Тайм-аут может быть настроен как для операций «подключения», так и для «чтения» запроса с помощью кортежа, что позволяет указать оба значения отдельно:
import requests
requests.get('http://www.google.com', timeout=(5, 14))
Здесь таймаут «подключения» составляет 5 секунд, а таймаут «чтения» - 14 секунд. Это позволит вашему запросу завершиться ошибкой намного быстрее, если он не может подключиться к ресурсу, а если он все же подключится, это даст ему больше времени для загрузки данных.
Файлы cookie и пользовательские заголовки
Ранее мы видели, как получить доступ к заголовкам с помощью свойства
headers
Точно так же мы можем получить доступ к файлам cookie из
ответа, используя свойство cookies
Например, в приведенном ниже примере показано, как получить доступ к
cookie с именем cookie_name
:
import requests
r = requests.get('http://www.examplesite.com')
r.cookies['cookie_name']
Мы также можем отправлять пользовательские файлы cookie на сервер,
предоставляя словарь для cookies
в нашем запросе GET.
import requests
custom_cookie = {'cookie_name': 'cookie_value'}
r = requests.get('http://www.examplesite.com/cookies', cookies=custom_cookie)
Файлы cookie также могут передаваться в объекте Cookie Jar. Это позволяет вам предоставлять файлы cookie для другого пути.
import requests
jar = requests.cookies.RequestsCookieJar()
jar.set('cookie_one', 'one', domain='httpbin.org', path='/cookies')
jar.set('cookie_two', 'two', domain='httpbin.org', path='/other')
r = requests.get('https://httpbin.org/cookies', cookies=jar)
print(r.text)
Выход:
{"cookies":{"cookie_one":"one"}}
Точно так же мы можем создавать собственные заголовки, назначая словарь
заголовку запроса с помощью параметра headers
import requests
custom_header = {'user-agent': 'customUserAgent'}
r = requests.get('https://samplesite.org', headers=custom_header)
Объект сеанса
Объект сеанса в основном используется для сохранения определенных параметров, например файлов cookie, в различных HTTP-запросах. Объект сеанса может использовать одно TCP-соединение для обработки нескольких сетевых запросов и ответов, что приводит к повышению производительности.
import requests
first_session = requests.Session()
second_session = requests.Session()
first_session.get('http://httpbin.org/cookies/set/cookieone/111')
r = first_session.get('http://httpbin.org/cookies')
print(r.text)
second_session.get('http://httpbin.org/cookies/set/cookietwo/222')
r = second_session.get('http://httpbin.org/cookies')
print(r.text)
r = first_session.get('http://httpbin.org/anything')
print(r.text)
Выход:
{"cookies":{"cookieone":"111"}}
{"cookies":{"cookietwo":"222"}}
{"args":{},"data":"","files":{},"form":{},"headers":{"Accept":"*/*","Accept-Encoding":"gzip, deflate","Connection":"close","Cookie":"cookieone=111","Host":"httpbin.org","User-Agent":"python-requests/2.9.1"},"json":null,"method":"GET","origin":"103.9.74.222","url":"http://httpbin.org/anything"}
Путь httpbin / cookies / set / {имя} /
{значение}
установит файл cookie с name
и value
. Здесь мы устанавливаем разные
значения cookie для объектов first_session
и second_session
Вы
можете видеть, что один и тот же файл cookie возвращается во всех
будущих сетевых запросах для определенного сеанса.
Точно так же мы можем использовать объект сеанса для сохранения определенных параметров для всех запросов.
import requests
first_session = requests.Session()
first_session.cookies.update({'default_cookie': 'default'})
r = first_session.get('http://httpbin.org/cookies', cookies={'first-cookie': '111'})
print(r.text)
r = first_session.get('http://httpbin.org/cookies')
print(r.text)
Выход:
{"cookies":{"default_cookie":"default","first-cookie":"111"}}
{"cookies":{"default_cookie":"default"}}
Как видите, default_cookie
отправляется с каждым запросом сеанса. Если
мы добавим какой-либо дополнительный параметр к cookie
, он
default_cookie
. "first-cookie": "111"
добавляется к cookie по
умолчанию "default_cookie": "default"
Использование прокси
proxies
используется для настройки прокси-сервера для использования в
ваших запросах.
http = "http://10.10.1.10:1080"
https = "https://10.10.1.11:3128"
ftp = "ftp://10.10.1.10:8080"
proxy_dict = {
"http": http,
"https": https,
"ftp": ftp
}
r = requests.get('http://sampleurl.com', proxies=proxy_dict)
Библиотека requests
также поддерживает прокси
SOCKS. Это дополнительная
функция, и она требует, чтобы перед использованием была установлена
зависимость requests[socks]
Как и раньше, вы можете установить его с
помощью pip:
$ pip install requests[socks]
После установки вы можете использовать его, как показано здесь:
proxies = {
'http': 'socks5:user: [email protected] :port'
'https': 'socks5:user: [email protected] :port'
}
Обработка SSL
Мы также можем использовать библиотеку запросов для проверки сертификата
HTTPS веб-сайта, передав в запрос verify=true
import requests
r = requests.get('https://www.github.com', verify=True)
Это вызовет ошибку, если есть какие-либо проблемы с SSL сайта. Если вы
не хотите истинности, просто передайте False
вместо True
. По
умолчанию для этого параметра установлено значение True
Скачивание файла
Для загрузки файла с помощью requests
мы можем либо загрузить его
путем потоковой передачи содержимого, либо напрямую загрузить его
целиком. stream
используется для обозначения обоих вариантов
поведения.
Как вы, наверное, догадались, если stream
имеет значение True
,
requests
будут передавать контент в потоковом режиме. Если stream
имеет значение False
, весь контент будет загружен в память, прежде
чем он будет возвращен вам.
Для потокового контента мы можем перебирать фрагмент контента фрагментом
с помощью iter_content
или перебирать построчно с помощью iter_line
. В любом случае он будет загружать файл по частям.
Например:
import requests
r = requests.get('https://cdn.pixabay.com/photo/2018/07/05/02/50/sun-hat-3517443_1280.jpg', stream=True)
downloaded_file = open("sun-hat.jpg", "wb")
for chunk in r.iter_content(chunk_size=256):
if chunk:
downloaded_file.write(chunk)
Приведенный выше код загрузит изображение с сервера
Pixabay и сохранит его в локальном файле
sun-hat.jpg
.
Мы также можем читать необработанные данные, используя свойство raw
stream=True
в запросе.
import requests
r = requests.get("http://exampleurl.com", stream=True)
r.raw
Для загрузки или потоковой передачи контента iter_content()
.
Ошибки и исключения
requests
вызывают различные типы исключений и ошибок, если когда-либо
возникает проблема с сетью. Все исключения наследуются от класса
requests.exceptions.RequestException
Вот краткое описание распространенных ошибок, с которыми вы можете столкнуться:
ConnectionError
выдается в случаеDNS failure
,refused connection
или любых других проблем, связанных с подключением.Timeout
увеличивается, если время ожидания запроса истекло.TooManyRedirects
возникает, если запрос превышает максимальное количество предопределенных перенаправлений.HTTPError
возникает для недопустимых ответов HTTP.
Более полный список и описание исключений, с которыми вы можете столкнуться, можно найти в документации .
Заключение
В этом руководстве я объяснил вам многие функции requests
и различные
способы ее использования. Вы можете использовать requests
не только
для взаимодействия с REST API, но и в равной степени использовать ее для
сбора данных с веб-сайта или для загрузки файлов из Интернета.
Измените и попробуйте приведенные выше примеры и оставьте комментарий
ниже, если у вас есть какие-либо вопросы относительно requests
.