pythonist cover biblioteka python urllib3
В данной статье мы опишем библиотеку языка Python urllib3. Мы расскажем, как получать данные, публиковать их и передавать в потоковом режиме, работать с JSON и использовать редирект.
Протокол передачи гипертекста (HTTP) — это прикладной протокол для распределенных, совместимых с гипермедиа, информационных систем. HTTP является основой основ передачи данных для World Wide Web.
urllib3Библиотека urllib3 — это мощный HTTP-клиент на Python c простым для понимания и продуманным кодом. Она поддерживает безопасность потоков, пул соединений, проверку SSL / TLS на стороне клиента, загрузку файлов с многокомпонентным кодированием, создание повторных запросов и работу с редиректом HTTP, архивирование и разархивирование, а также прокси для HTTP и SOCKS.
Установка библиотеки при помощи пакетного менеджера pip:
$ pip install urllib3
Для начала мы выведем на экран версию библиотеки urllib3.
# version.py #!/usr/bin/env python3 import urllib3 rint(urllib3.__version__)
Эта несложная программа позволяет нам узнать версию установленной нами библиотеки urllib3:
1.24.1
HTTP-коды состояния показывают нам, был ли HTTP-запрос успешно обработан, и если нет, то по какой причине. Коды ответов делятся на пять групп:
# status.py
#!/usr/bin/env python3
import urllib3
http = urllib3.PoolManager()
url = 'http://webcode.me'
resp = http.request('GET', url)
print(resp.status) В этом примере мы генерируем GET-запрос на сайт webcode.me и выводим на экран код ответа от сайта.
Для начала мы создаем менеджер соединений при помощи функции urllib3.PoolManager() и сохраняем его в переменную http. Он обрабатывает все детали пула соединений и обеспечивает безопасность потоков.
Далее мы записываем в переменную url строку с адресом сайта ('http://webcode.me').
Затем мы шлем на этот адрес GET-запрос при помощи метода request() и сохраняем результат в переменную resp. После этого выводим статус запроса на экран:
200
Код ответа 200 означает, что запрос прошел успешно.
urllib3В протоколе HTTP метод GET запрашивает представление страницы по адресу, определенному в запросе .
# get_request.py
#!/usr/bin/env python3
import urllib3
http = urllib3.PoolManager()
url = 'http://webcode.me'
resp = http.request('GET', url)
print(resp.data.decode('utf-8')) В данном примере, как и в предыдущем, мы посылаем GET-запрос по адресу webcode.me. Но сейчас мы выводим на экран не код ответа, а сам результат запроса, то есть html-код запрошенной страницы.
Генерируем GET-запрос и записываем результат в переменную resp. Далее мы берем данные из этой переменной, декодируем их и выводим на экран: print(resp.data.decode('utf-8')). В результате получаем:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>My html page</title>
</head>
<body>
<p>
Today is a beautiful day. We go swimming and fishing.
</p>
<p>
Hello there. How are you?
</p>
</body> urllib3HEAD-запрос полностью идентичен GET-запросу, за исключением того, что в нем не запрашивается тело страницы. Обычно он используется для извлечения метаданных.
head_request.py
#!/usr/bin/env python3
import urllib3
http = urllib3.PoolManager()
url = 'http://webcode.me'
resp = http.request('HEAD', url)
print(resp.headers['Server'])
print(resp.headers['Date'])
print(resp.headers['Content-Type'])
print(resp.headers['Last-Modified']) В данном примере мы создаем HEAD-запрос на сайт webcode.me. Переменная, содержащая объект ответа, представляет собой словарь, из которого можно извлечь различные данные:
print(resp.headers['Server']) print(resp.headers['Date']) print(resp.headers['Content-Type']) print(resp.headers['Last-Modified'])
Результат будет следующим:
nginx/1.6.2 Thu, 20 Feb 2020 14:35:14 GMT text/html Sat, 20 Jul 2019 11:49:25 GMT
Из этого ответа можно заключить, что сервер, на котором работает этот сайт, — nginx, а тип контента — html-код.
Библиотека Urllib3 обеспечивает проверку TLS / SSL на стороне клиента. Но для этого нам нужно предварительно установить библиотеку certifi. Она представляет собой тщательно отобранную коллекцию корневых сертификатов для проверки достоверности SSL-сертификатов при проверке подлинности хостов TLS. Эта библиотека была выделена в отдельный модуль из известного проекта Requests (который также является очень известной библиотекой для протокола HTTP)
$ pip install certifi
При помощи приведенной выше команды мы установили библиотеку certifi.
import certifi print(certifi.where())
Для ссылки на установленный модуль центра сертификации (CA) мы используем встроенную функцию where().
# status2.py
#!/usr/bin/env python3
import urllib3
import certifi
url = 'https://httpbin.org/anything'
http = urllib3.PoolManager(ca_certs=certifi.where())
resp = http.request('GET', url)
print(resp.status Чтобы отправить GET- запрос на страницу https://httpbin.org/anything, мы должны передать пакет корневых сертификатов в функцию PoolManager(). Без этого сервер вернет следующее предупреждение: Unverified HTTPS request is being made. Adding certificate verification is strongly advised. («Поступил непроверенный HTTPS-запрос. Крайне рекомендуется добавить сертификат проверки»).
Параметры запроса являются частью URL (унифицированного указателя ресурса), который присваивает значения указанным параметрам. Это один из способов отправки данных на сервер назначения.
http://example.com/api/users?name=John%20Doe&occupation=gardener
Параметры запроса указываются после знака '?', а поля разделяются знаком '&'. Специальные символы, например пробелы, кодируются определенным образом. В приведенном выше примере пробелы закодированы значением %20.
# query_params.py
#!/usr/bin/env python3
import urllib3
import certifi
http = urllib3.PoolManager(ca_certs=certifi.where())
payload = {'name': 'Peter', 'age': 23}
url = 'https://httpbin.org/get'
req = http.request('GET', url, fields=payload)
print(req.data.decode('utf-8')) В данном примере мы послали GET-запрос с некоторыми параметрами на страницу https://httpbin.org/get . Эта страница просто возвращает определенные данные обратно клиенту, включая при этом параметры запроса. Этот сайт вообще создан для тестирования HTTP-запросов.
payload = {'name': 'Peter', 'age': 23}
Параметры запросы были заданы в формате словаря, который был сохранен в переменную payload.
req = http.request('GET', url, fields=payload)
А при помощи необязательного аргумента fields они были переданы в функцию request().
{
"args": {
"age": "23",
"name": "Peter"
},
"headers": {
"Accept-Encoding": "identity",
"Host": "httpbin.org",
"X-Amzn-Trace-Id": "Root=1-5e4ea45f-c3c9c721c848f8f81a3129d8"
},
"origin": "188.167.251.9",
"url": "https://httpbin.org/get?name=Peter&age=23"
} Ответ сайта httpbin.org был дан в виде строки в формате JSON, в начале которой стоят параметры нашего запроса.
В протоколе HTTP метод POST используется для передачи данных на сервер. Он часто применяется для загрузки файлов или для заполнения веб-форм.
# post_request.py
#!/usr/bin/env python3
import urllib3
import certifi
http = urllib3.PoolManager(ca_certs=certifi.where())
url = 'https://httpbin.org/post'
req = http.request('POST', url, fields={'name': 'John Doe'})
print(req.data.decode('utf-8')) В данном примере был послан POST-запрос. Его данные были заданы при помощи аргумента fields.
А ответ сервера был таким:
{
"args": {},
"data": "",
"files": {},
"form": {
"name": "John Doe"
},
...
"url": "https://httpbin.org/post"
} В запросах, таких как POST или PUT, клиент сообщает серверу, какой тип данных фактически будет отправлен при помощи поля 'Content-Type' в параметре headers.
# send_json.py
#!/usr/bin/env python3
import urllib3
import certifi
import json
http = urllib3.PoolManager(ca_certs=certifi.where())
payload = {'name': 'John Doe'}
encoded_data = json.dumps(payload).encode('utf-8')
resp = http.request(
'POST',
'https://httpbin.org/post',
body=encoded_data,
headers={'Content-Type': 'application/json'})
data = json.loads(resp.data.decode('utf-8'))['json']
print(data) В данном примере мы отправили данные в формате JSON.
payload = {'name': 'John Doe'}
encoded_data = json.dumps(payload).encode('utf-8') Здесь мы перевели данные в формате JSON в двоичный формат.
resp = http.request(
'POST',
'https://httpbin.org/post',
body=encoded_data,
headers={'Content-Type': 'application/json'}) Тут мы задали тип передаваемых данных в поле 'Content-Type' параметра headers.
data = json.loads(resp.data.decode('utf-8'))['json']
print(data) И в конце мы декодировали в текстовый формат данные, возвращенные сервером, и вывели их на экран.
В следующем примере мы загружаем с сервера двоичные данные.
get_binary.py
#!/usr/bin/env python3
import urllib3
http = urllib3.PoolManager()
url = 'http://webcode.me/favicon.ico'
req = http.request('GET', url)
with open('favicon.ico', 'wb') as f:
f.write(req.data) В данном примере с сервера загружается маленькая иконка.
with open('favicon.ico', 'wb') as f:
f.write(req.data) req.data имеет двоичный формат, так что мы можем записывать его прямо на диск.
Кодирование данных по частям — это механизм передачи потоковых данных, доступный начиная с версии HTTP 1.1. При кодировании с частичной передачей поток данных делится на ряд непересекающихся блоков. Эти блоки отправляются и принимаются независимо друг от друга. Перед отправкой блока всегда посылается его размер в байтах.
Установка параметра preload_content в состояние False означает, что библиотека urllib3 будет производить потоковою передачу данных. Метод stream() выполняет итерации по частям содержимого ответа. При потоковой передаче мы должны вызывать метод release_conn(), который переносит http-соединение обратно в пул соединений, чтобы его можно было использовать повторно.
# streaming.py
#!/usr/bin/env python3
import urllib3
import certifi
url = "https://docs.oracle.com/javase/specs/jls/se8/jls8.pdf"
local_filename = url.split('/')[-1]
http = urllib3.PoolManager(ca_certs=certifi.where())
resp = http.request(
'GET',
url,
preload_content=False)
with open(local_filename, 'wb') as f:
for chunk in resp.stream(1024):
f.write(chunk)
resp.release_conn() В данном примере мы загружаем с сервера PDF-файл.
resp = http.request(
'GET',
url,
preload_content=False) Задав параметр preload_content=False, мы включаем потоковую передачу данных.
with open(local_filename, 'wb') as f:
for chunk in resp.stream(1024):
f.write(chunk) Мы производим итерацию по блокам данных и записываем их в файл.
resp.release_conn()
В конце мы освобождаем соединение для дальнейшего использования.
Редирект переадресовывает пользователей и поисковые системы на разные URL-адреса, отличные от тех, которые они первоначально запрашивали. Чтобы разрешить перенаправление нашего запроса, мы присваиваем параметру redirect значение True.
# redirect.py
#!/usr/bin/env python3
import urllib3
import certifi
http = urllib3.PoolManager(ca_certs=certifi.where())
url = 'https://httpbin.org/redirect-to?url=/'
resp = http.request('GET', url, redirect=True)
print(resp.status)
print(resp.geturl())
print(resp.info()) В данном примере мы создали запрос с разрешением редиректа. А вот результат выполнения нашего запроса:
200
/
HTTPHeaderDict({'Date': 'Fri, 21 Feb 2020 12:49:29 GMT', 'Content-Type': 'text/html;
charset=utf-8', 'Content-Length': '9593', 'Connection': 'keep-alive',
'Server': 'gunicorn/19.9.0', 'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Credentials': 'true'}) urllib3 с фреймворком FlaskВ данном примере мы пошлем запрос на небольшое веб-приложение, запущенное на сервере flask. Подробнее о фреймворке flask можно прочитать, например, в нашем обзоре.
Для начала установим библиотеку flask:
$ pip install flask
# app.py
#!/usr/bin/env python3
from flask import Flask
from flask import request
app = Flask(__name__)
@app.route('/headers')
def hello():
ua = request.headers.get('user-agent')
ka = request.headers.get('connection')
return f'User agent: {ua}; Connection: {ka}' Данное приложение на фреймворке flask выполняет только одну операцию: в ответ на запрос оно возвращает пользователю заголовки этого самого запроса.
# send_req.py
#!/usr/bin/env python3
import urllib3
http = urllib3.PoolManager()
url = 'localhost:5000/headers'
headers = urllib3.make_headers(keep_alive=True, user_agent='Python program')
resp = http.request('GET', url, headers=headers)
print(resp.data.decode('utf-8')) В данном коде мы посылаем запрос нашему серверному приложению на базе библиотеки flask.
url = 'localhost:5000/headers'
По умолчанию, flask сервер запускается на 5000 порте.
headers = urllib3.make_headers(keep_alive=True, user_agent='Python program')
При помощи метода make_headers() мы создаем словарь заголовков.
resp = http.request('GET', url, headers=headers)
Посылаем запрос по заданному ранее URL.
print(resp.data.decode('utf-8'))
Выводим ответ на дисплей.
$ export FLASK_APP=app.py $ flask run
Таким образом мы запускаем приложение flask.
$ ./send_req.py User agent: Python program; Connection: keep-alive
А с другого терминала мы запускаем программу запроса и получаем от сервера ответ.
Итак, мы вкратце рассмотрели библиотеку Python urllib3.
Перевод статьи «Python urllib3».
Если вы ищете работу на Python, на Talanto.work сейчас есть варианты для junior, middle, senior…
Рынок Python-вакансий большой, но удобным его назвать сложно. Формально вакансий много, однако в реальном поиске…
Срезы в Python — это больше, чем a[2:7]. В статье — быстрый разбор полезных приёмов:…
В этой статье мы рассмотрим возведение в степень в Python с помощью различных методов, от…
Дубликаты в списке Python — частая проблема. В статье показано, как быстро убрать повторы, в…
Услуга виртуального хостинга на SpaceWeb позволяет арендовать часть сервера (shared-сервера) и разместить на нём свой…