Рубріки: Теория

Самоучитель по запросам в Python: GET и POST для чайников

Игорь Грегорченко

В веб-программировании на Python самое базовое знание, которое вы должны глубоко и тщательно освоить (прежде чем двигаться дальше),  это техника HTTP-запросов. Несмотря на то, что в Python есть несколько популярных HTTP-библиотек, самой простой является библиотека Requests. В этом посте для начинающих мы последовательно описали все основные операции/режимы этой популярной библиотеки.

Этот пост — вольный перевод на русский вот этой оригинальной статьи (с нашими дополнениями в местах, где это показалось нужным), которую написал Анирудх Рао. 


В этой статье, посвященной веб-запросам в Python, я объясню все основы модуля Requests и расскажу, как можно отправлять запросы HTTP/1.1 с помощью Python. К концу этого поста вы сможете выполнять простейший веб-скрейпинг  (и даже парсинг веб-страниц) с помощью Python. В посте я рассмотрю следующие темы:

  • Что такое веб-запросы Python?
  • Как установить модуль Requests в Python?
  • Как сделать GET-запрос?
  • Загрузка изображения с помощью запросов
  • Как сделать POST-запрос?
  • Как вставить заголовки и Cookies в запрос?
  • Что такое объекты сессии?

Давайте начнем наш пост в стиле «Мини-учебника по запросам» с того, что узнаем, что такое модуль запросов.

Что такое запросы в Python?

Requests — это модуль Python, который можно использовать для отправки всех видов HTTP-запросов. Это простая в использовании библиотека с множеством функций, начиная от передачи параметров в URL и заканчивая отправкой пользовательских заголовков и SSL-проверкой. В этом руководстве вы узнаете, как использовать эту библиотеку для отправки простых HTTP-запросов в Python. Но даже если у вас что-то не будет получаться, то всегда можно перенять знания у опытных специалистов, которые проводят онлайн курсы в школе наших партнеров Mate Academy.

Requests позволяет отправлять запросы протокола HTTP/1.1. Можно добавлять заголовки, данные формы, многокомпонентные файлы и параметры с помощью простых словарей Python, а также получать доступ к данным ответа таким же образом.

Как установить модуль Requests в Python?

Чтобы установить requests, просто сделайте это:

$ pip install requests

Или, если необходимо, добавьте:

$ easy_install requests

 

Как сделать GET-запрос?

Отправить HTTP-запрос с помощью Requests довольно просто. Для начала нужно импортировать модуль, а затем сделать запрос.

Посмотрите пример:

import requests
req = requests.get('<a href="https://www.edureka.co/">https://www.edureka.co/</a>')

Итак, мы где-то храним информацию, верно?

Да, объект Response хранит информацию запроса.

Допустим, вам нужна кодировка веб-страницы, чтобы вы могли проверить ее или использовать где-то еще. Мы можем сделать это, используя свойство req.encoding.

Дополнительный плюс в том, что можно также извлечь многие характеристики, например, код состояния (запроса). Это можно сделать с помощью свойства req.status_code, вот так:

req.encoding # возвращает 'utf-8'
req.status_code # возвращает 200

Также можно получить доступ к cookies, которые сервер отправил обратно. Это делается с помощью req.cookies, вот так все просто! Аналогично можно получить и заголовки ответа. Для этого используется req.headers.

Обратите внимание, что свойство req.headers возвращает словарь заголовков ответа без учета регистра. Что это означает?

Это означает, что req.headers['Content-Length'], req.headers['content-length'] и req.headers['CONTENT-LENGTH'] вернут значение только заголовка ответа 'Content-Length'.

Мы также можем проверить, является ли полученный ответ правильно сформированным HTTP-перенаправлением (или нет), которое могло быть обработано автоматически, используя свойство req.is_redirect. Это свойство возвращает True или False в зависимости от полученного ответа.

Также можно получить время, прошедшее с момента отправки запроса до получения ответа, используя другое свойство. Угадаете его название? Да, это свойство req.elapsed.

Помните URL, который вы изначально передали функции get()? Так вот, он может отличаться от конечного URL ответа по многим причинам, включая перенаправления.

Чтобы увидеть фактический URL-адрес ответа, можно использовать свойство req.url.

import requests
req = requests.get('<a href="http://www.edureka.co/">http://www.edureka.co/</a>')
 
req.encoding # returns 'utf-8'
req.status_code # returns 200
req.elapsed # returns datetime.timedelta(0, 1, 666890)
req.url # returns '<a href="https://edureka.co/">https://edureka.co/</a>'
 
req.history 
 
req.headers['Content-Type']
# returns 'text/html; charset=utf-8'

Согласны, что получать всю эту служебную информацию о веб-странице — очень интересная возможность? Но вы, скорее всего, хотите чего-то большего — получить доступ к реальному содержимому страницы, верно?

Если содержимое, к которому вы обращаетесь, является текстом, вы всегда можете использовать свойство req.text для доступа к нему. Обратите внимание, что содержимое будет разобрано только как юникод. Вы можете передать кодировку, с помощью которой можно декодировать текст, используя свойство req.encoding, как мы обсуждали ранее.

В случае нетекстовых ответов к ним получить доступ также очень просто. Фактически это делается в двоичном формате, когда используется req.content. Этот модуль автоматически декодирует для нас передаваемые кодировки gzip и deflate. Это может быть очень полезно, когда вы имеете дело непосредственно с медиафайлами. Кроме того, можно получить доступ к JSON-кодированному содержимому ответа, если оно существует, используя функцию req.json().

Довольно просто и очень гибко

Кроме того, при необходимости можно получить необработанный raw-ответ от сервера, просто используя req.raw. Имейте в виду, что вам придется передать stream=True в запросе, чтобы получить необработанный ответ в соответствии с вашими потребностями.

Но некоторые файлы, которые вы загружаете из интернета с помощью модуля Requests, могут иметь огромный размер, верно? В таких случаях не стоит сразу загружать весь ответ или файл в память сервера. При правильном подходе рекомендуется загружать такой файл по частям или кусками, используя метод iter_content(chunk_size = 1, decode_unicode = False).

Итак, этот метод итерирует данные ответа в количестве байт chunk_size за один раз. А когда stream=True в запросе, этот метод позволит избежать чтения всего файла в память за один раз только для реально больших ответов.

Обратите внимание, что параметр chunk_size может быть как целым числом, так и None. Если параметр chunk_size имеет целочисленное значение, то он определяет количество байт, которые должны быть считаны в память за один раз.

Когда chunk_size установлен в None, а stream установлен в True, данные будут считываться по мере их поступления в виде кусков любого размера. Но если chunk_size установлен в None, а stream установлен в False, все данные будут возвращаться только как один кусок данных.

Далее в этом посте «Мини-учебника по запросам» мы рассмотрим, как можно загрузить изображение с помощью модуля Requests. Давайте попробуем применить всю эту теорию к чему-то из реального мира.

Загрузка изображения с помощью модуля Requests

Итак, давайте загрузим следующее изображение леса с помощью модуля Requests, о котором мы узнали. Вот фактическое изображение для тестирования:

Вот код, который вам понадобится для загрузки изображения:

import requests
req = requests.get('path/to/forest.jpg', stream=True)
req.raise_for_status()
with open('Forest.jpg', 'wb') as fd:
for chunk in req.iter_content(chunk_size=50000):
print('Received a Chunk')
fd.write(chunk)

Обратите внимание, что 'path/to/forest.jpg' — это фактический URL изображения. Вы можете подставить сюда URL highload.today, либо любого другого хоста-источника, чтобы загрузить что-то еще. Это просто пример, размер данного файла изображения составляет около 185 Кб, а размер chunk_size установлен на 50 000 байт.

Это означает, что при тестировании загрузки сообщение «Received a Chunk» должно быть выведено в терминале четыре раза. Размер последнего чанка будет равен 39 350 байт, потому что часть файла, которую осталось получить после первых трех итераций, равна 39 350 байт. Если вы посчитали все так же, как и мы, значит, понимаете все правильно.

Запросы также позволяют передавать параметры в URL. Это особенно полезно, когда вы ищете веб-страницу по каким-то результатам, например, учебник или конкретное изображение. Это работает и с поиском в Google. Можно передать эти строки запроса в виде словаря строк, используя ключевое слово params в запросе GET. Посмотрите этот простой пример:

import requests
 
query = {'q': 'Forest', 'order': 'popular', 'min_width': '800', 'min_height': '600'}
req = requests.get('<a href="https://pixabay.com/en/photos/">https://pixabay.com/en/photos/</a>', params=query)
 
req.url
# returns '<a href="https://pixabay.com/en/photos/?order=popular_height=600&q=Forest&min_width=800">https://pixabay.com/en/photos/?order=popular_height=600&q=Forest&min_width=800</a>'

Все готово, далее в этом руководстве мы рассмотрим, как сделать свой первый POST-запрос!

Как сделать POST-запрос?

Выполнить POST-запрос так же просто, как и GET-запрос. Просто используйте функцию post() вместо get().

Это может быть полезно при автоматической отправке форм. Например, следующий код загрузит всю страницу Википедии о нанотехнологиях и сохранит ее на вашем компьютере.

import requests
req = requests.post('<a href="https://en.wikipedia.org/w/index.php">https://en.wikipedia.org/w/index.php</a>', data = {'search':'Nanotechnology'})
req.raise_for_status()
with open('Nanotechnology.html', 'wb') as fd:
for chunk in req.iter_content(chunk_size=50000):
fd.write(chunk)

Если вы хотите стать экспертом в языке программирования python, то обратите внимание на курсы наших партнеров Mate Academy и Powercode. Их выпускники работают в крупных компаниях по всему миру.

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

Как уже упоминалось ранее, вы можете получить доступ к кукам и заголовкам, которые сервер отправляет вам обратно, используя req.cookies и req.headers. Запросы также позволяют вам отправлять собственные пользовательские куки и заголовки вместе с запросом. Это может быть полезно, когда вы хотите, например, установить определенный пользовательский агент для вашего запроса.

Чтобы добавить HTTP-заголовки в запрос, вы можете просто передать их в виде dict в параметр headers. Аналогичным образом вы можете отправить на сервер свои собственные cookies, используя dict, переданный в параметре cookies.

import requests
 
url = '<a href="http://some-domain.com/set/cookies/headers">http://some-domain.com/set/cookies/headers</a>'
 
headers = {'user-agent': 'your-own-user-agent/0.0.1'}
cookies = {'visit-month': 'February'}
 
req = requests.get(url, headers=headers, cookies=cookies)

Cookie jar также могут хранить файлы cookie. Они предоставляют более полный интерфейс, позволяющий использовать эти куки по нескольким путям.

Посмотрите на этот обзорный пример ниже:

import requests
 
jar = requests.cookies.RequestsCookieJar()
jar.set('first_cookie', 'first', domain='httpbin.org', path='/cookies')
jar.set('second_cookie', 'second', domain='httpbin.org', path='/extra')
jar.set('third_cookie', 'third', domain='httpbin.org', path='/cookies')
 
url = '<a href="http://httpbin.org/cookies">http://httpbin.org/cookies</a>'
req = requests.get(url, cookies=jar)
 
req.text
 
# returns '{ "cookies": { "first_cookie": "first", "third_cookie": "third" }}'


Что такое сессионные объекты?

Иногда полезно сохранять определенные параметры при нескольких запросах. Объект Session делает именно это. Например, он сохраняет данные cookie во всех запросах, сделанных с помощью одной и той же сессии.

Объект Session в Python использует пул соединений urllib3. Это означает, что базовое TCP-соединение будет повторно использоваться для всех запросов, сделанных к одному и тому же хосту.

Это может значительно повысить производительность. Также можно использовать методы объекта Requests с объектом Session.

Сессии также полезны, когда вы хотите отправлять одни и те же данные во всех запросах. Например, если вы решили отправлять cookie или заголовок user-agent при всех запросах к определенному домену, можно использовать объекты Session.

import requests
 
ssn = requests.Session()
ssn.cookies.update({'visit-month': 'February'})
 
reqOne = ssn.get('<a href="http://httpbin.org/cookies">http://httpbin.org/cookies</a>')
print(reqOne.text)
# prints information about "visit-month" cookie
 
reqTwo = ssn.get('<a href="http://httpbin.org/cookies">http://httpbin.org/cookies</a>', cookies={'visit-year': '2017'})
print(reqTwo.text)
# prints information about "visit-month" and "visit-year" cookie
 
reqThree = ssn.get('<a href="http://httpbin.org/cookies">http://httpbin.org/cookies</a>')
print(reqThree.text)
# prints information about "visit-month" cookie

Как можете видеть, сессионный файл cookie «visit-month» отправляется со всеми тремя запросами. Однако cookie «visit-year» отправляется только во время второго запроса. В третьем запросе также нет упоминания о cookie «visit-year». Это подтверждает тот факт, что файлы cookie или другие данные, установленные в отдельных запросах, не будут отправлены с другими сессионными запросами.

Подведение итогов

В качестве закрепления, еще раз тезисно пробежим по самому главному из того, что мы узнали выше. HTTP — это набор протоколов, предназначенных для обеспечения связи между клиентами и серверами. Он работает как протокол «запрос-ответ» между клиентом и сервером.

В качестве клиента может выступать веб-браузер, а в качестве сервера — приложение на компьютере, на котором размещен веб-сайт.

Таким образом, чтобы запросить ответ от сервера, существует два стандартных метода в рамках HTTP/1.1:

  • GET: запрос данных с сервера.
  • POST: отправка данных для обработки на сервер.

Вот простая диаграмма, которая объясняет основную концепцию методов GET и POST:

Теперь, чтобы выполнять HTTP-запросы в Python, мы можем использовать несколько популярных в Python HTTP-библиотек, таких как:

  • httplib.
  • urllib.
  • requests.

Самой элегантной и простой из перечисленных выше библиотек является библиотека Requests. В этом посте выше мы последовательно описали все основные операции из самой популярной Python-библиотеки Requests.

Останні статті

Обучение Power BI – какие онлайн курсы аналитики выбрать

Сегодня мы поговорим о том, как выбрать лучшие курсы Power BI в Украине, особенно для…

13.01.2024

Work.ua назвал самые конкурентные вакансии в IТ за 2023 год

В 2023 году во всех крупнейших регионах конкуренция за вакансию выросла на 5–12%. Не исключением…

08.12.2023

Украинская IT-рекрутерка создала бесплатный трекер поиска работы

Unicorn Hunter/Talent Manager Лина Калиш создала бесплатный трекер поиска работы в Notion, систематизирующий все этапы…

07.12.2023

Mate academy отправит работников в 10-дневный оплачиваемый отпуск

Edtech-стартап Mate academy принял решение отправить своих работников в десятидневный отпуск – с 25 декабря…

07.12.2023

Переписки, фото, история браузера: киевский программист зарабатывал на шпионаже

Служба безопасности Украины задержала в Киеве 46-летнего программиста, который за деньги устанавливал шпионские программы и…

07.12.2023

Как вырасти до сеньйора? Девелопер создал популярную подборку на Github

IT-специалист Джордан Катлер создал и выложил на Github подборку разнообразных ресурсов, которые помогут достичь уровня…

07.12.2023