Python, библиотека requests: быстрый старт
Содержание:
Pydoc
Для более удобной работы с документацией, в Python существует встроенная библиотека pydoc.
Pydoc автоматически генерирует документацию из Python модулей. Информацию по доступным командам модуля можно получить набрав в терминале:
Разберем подробнее, что умеет pydoc.
Вывод текста документации
— покажет текст документации указанного модуля, пакета, функции, класса и т.д. Если <name> содержит «\», Python будет искать документацию по указанному пути.
Для примера, посмотрим документацию встроенного модуля math:
В консоль выведется название модуля, его описание и описание всех функций в модуле.
Поиск по документации
— найдет ключевое слово в документации всех доступных модулей.
Допустим, нам нужно распаковать gzip файл. Поищем слово «gzip»:
В списке мы видим модуль . Теперь можно посмотреть его документацию:
По описанию, данный модуль решит нашу задачу.
HTTP сервер с документацией
Для удобства просмотра документации, pydoc позволяет одной командой создать HTTP-сервер:
Теперь можно перейти в браузер и зайти на
HTTP сервер pydoc
Для остановки сервера введите «q» и нажмите «Enter»:
Также HTTP-сервер доступен через – эта команда создаст сервер на свободном порту, откроет браузер и перейдет на нужную страницу.
Using Python request headers
Python request headers hold important data related to the message
Response headers are another important part of the request. While they do not contain any content of the original message, headers hold many important details of the response such as information about the server, the date, encoding, etc. Every detail can be acquired from the initial response by making a call:
As with the .json() call, headers create a dictionary type object which can then be accessed. Adding parameters to the call will list out a part of the response, e.g.:
Our function will now print the date stored in the response header. Values are considered case-insensitive, therefore Requests will output the same result regardless of whether the parameter was formed as ‘date’ or ‘Date’.
You can also send custom Python requests headers. Dictionary-type objects are used yet again, although this time they have to be created. Headers are passed in an identical manner to parameters. To check whether our request header has been sent successfully we will need to make the call response.request.headers:
Running our code should output the request header in the debugger window with the user agent stated as ‘my-agent/1.0.1’. As a general rule, sending most common user agents is recommended as otherwise some websites could return a 403 ‘Forbidden’ response.
Custom HTTP headers are usually used for troubleshooting or informational purposes. User agents are often utilized in web scraping projects in order to change the perceived source of incoming requests.
Коды состояния API
Коды состояния возвращаются при каждом запросе к веб-серверу. Коды состояния указывают информацию о том, что произошло с запросом.
Ответы сгруппированы в пять классов:
- Информационные ответы ( — ),
- Успешные ответы ( — ),
- Перенаправления ( — ),
- Ошибки клиента ( — ),
- и ошибки сервера ( — ).
Вот некоторые коды, которые относятся к запросам GET
- : Все прошло хорошо и результат был возвращен (если есть).
- : Сервер перенаправляет вас на другую конечную точку. Это может произойти, когда компания меняет доменные имена или имя конечной точки изменяется.
- : Сервер считает, что вы сделали неверный запрос. Это может произойти, если вы отправите неверные данные.
- : Сервер думает, что вы не аутентифицированы. Для многих API требуются учетные данные для входа, поэтому код 401 случается, когда вы отправляете неверные учетные данные для доступа к API.
- : Ресурс, к которому вы пытаетесь получить доступ, запрещен: у вас нет прав для его просмотра.
- : Ресурс, к которому вы пытались получить доступ, не найден на сервере.
- : Сервер не готов обработать запрос.
Event Hooks¶
Requests has a hook system that you can use to manipulate portions of
the request process, or signal event handling.
Available hooks:
-
The response generated from a Request.
You can assign a hook function on a per-request basis by passing a
dictionary to the request
parameter:
hooks={'response' print_url}
That will receive a chunk of data as its first
argument.
def print_url(r, *args, **kwargs): print(r.url)
Your callback function must handle its own exceptions. Any unhandled exception won’t be passed silently and thus should be handled by the code calling Requests.
If the callback function returns a value, it is assumed that it is to
replace the data that was passed in. If the function doesn’t return
anything, nothing else is affected.
def record_hook(r, *args, **kwargs): r.hook_called = True return r
Let’s print some request method arguments at runtime:
>>> requests.get('https://httpbin.org/', hooks={'response' print_url}) https://httpbin.org/ <Response >
You can add multiple hooks to a single request. Let’s call two hooks at once:
>>> r = requests.get('https://httpbin.org/', hooks={'response' print_url, record_hook]}) >>> r.hook_called True
You can also add hooks to a instance. Any hooks you add will then
be called on every request made to the session. For example:
>>> s = requests.Session() >>> s.hooks'response'.append(print_url) >>> s.get('https://httpbin.org/') https://httpbin.org/ <Response >
Custom Authentication¶
Requests allows you to specify your own authentication mechanism.
Any callable which is passed as the argument to a request method will
have the opportunity to modify the request before it is dispatched.
Authentication implementations are subclasses of ,
and are easy to define. Requests provides two common authentication scheme
implementations in : and
.
Let’s pretend that we have a web service that will only respond if the
header is set to a password value. Unlikely, but just go with it.
from requests.auth import AuthBase class PizzaAuth(AuthBase): """Attaches HTTP Pizza Authentication to the given Request object.""" def __init__(self, username): # setup any auth-related data here self.username = username def __call__(self, r): # modify and return the request r.headers'X-Pizza' = self.username return r
Then, we can make a request using our Pizza Auth:
HTTPResponse Objects¶
An instance wraps the HTTP response from the
server. It provides access to the request headers and the entity
body. The response is an iterable object and can be used in a with
statement.
Changed in version 3.5: The interface is now implemented and
all of its reader operations are supported.
- (amt)
-
Reads and returns the response body, or up to the next amt bytes.
- (b)
-
Reads up to the next len(b) bytes of the response body into the buffer b.
Returns the number of bytes read.New in version 3.3.
- (name, default=None)
-
Return the value of the header name, or default if there is no header
matching name. If there is more than one header with the name name,
return all of the values joined by ‘, ‘. If ‘default’ is any iterable other
than a single string, its elements are similarly returned joined by commas.
- ()
-
Return a list of (header, value) tuples.
- ()
-
Return the of the underlying socket.
-
HTTP protocol version used by server. 10 for HTTP/1.0, 11 for HTTP/1.1.
-
URL of the resource retrieved, commonly used to determine if a redirect was followed.
-
Status code returned by server.
-
Reason phrase returned by server.
-
A debugging hook. If is greater than zero, messages
will be printed to stdout as the response is read and parsed.
-
Is if the stream is closed.
- ()
-
Deprecated since version 3.9: Deprecated in favor of .
- ()
-
Deprecated since version 3.9: Deprecated in favor of .
Examples of Request Message
Now let’s put it all together to form an HTTP request to fetch hello.htm page from the web server running on tutorialspoint.com
GET /hello.htm HTTP/1.1 User-Agent: Mozilla/4.0 (compatible; MSIE5.01; Windows NT) Host: www.tutorialspoint.com Accept-Language: en-us Accept-Encoding: gzip, deflate Connection: Keep-Alive
Here we are not sending any request data to the server because we are fetching a plain HTML page from the server. Connection is a general-header, and the rest of the headers are request headers. The following example shows how to send form data to the server using request message body:
POST /cgi-bin/process.cgi HTTP/1.1 User-Agent: Mozilla/4.0 (compatible; MSIE5.01; Windows NT) Host: www.tutorialspoint.com Content-Type: application/x-www-form-urlencoded Content-Length: length Accept-Language: en-us Accept-Encoding: gzip, deflate Connection: Keep-Alive licenseID=string&content=string&/paramsXML=string
Here the given URL /cgi-bin/process.cgi will be used to process the passed data and accordingly, a response will be returned. Here content-type tells the server that the passed data is a simple web form data and length will be the actual length of the data put in the message body. The following example shows how you can pass plain XML to your web server:
POST /cgi-bin/process.cgi HTTP/1.1 User-Agent: Mozilla/4.0 (compatible; MSIE5.01; Windows NT) Host: www.tutorialspoint.com Content-Type: text/xml; charset=utf-8 Content-Length: length Accept-Language: en-us Accept-Encoding: gzip, deflate Connection: Keep-Alive <?xml version="1.0" encoding="utf-8"?> <string xmlns="http://clearforest.com/">string</string>
Previous Page
Print Page
Next Page
Краткий обзор запросов HTTP
Запросы HTTP лежат в основе всемирной сети. Каждый раз, когда вы открываете веб-страницу, ваш браузер направляет множество запросов на сервер этой веб-страницы. Сервер отвечает на них, пересылая все необходимые данные для вывода страницы, и ваш браузер отображает страницу, чтобы вы могли увидеть ее.
В целом этот процесс выглядит так: клиент (например браузер или скрипт Python, использующий библиотеку Requests) отправляет данные на URL, а сервер с этим URL считывает данные, решает, что с ними делать, и отправляет клиенту ответ. После этого клиент может решить, что делать с полученными в ответе данными.
В составе запроса клиент отправляет данные по методу запроса. Наиболее распространенными методами запроса являются GET, POST и PUT. Запросы GET обычно предназначены только для чтения данных без их изменения, а запросы POST и PUT обычно предназначаются для изменения данных на сервере. Например, Stripe API позволяет использовать запросы POST для тарификации, чтобы пользователь мог купить что-нибудь в вашем приложении.
Примечание. В этой статье рассказывается о запросах GET, поскольку мы не собираемся изменять никакие данные на сервере.
При отправке запроса из скрипта Python или веб-приложения вы как разработчик решаете, что отправлять в каждом запросе и что делать с полученными ответами. Для начала отправим запрос на Scotch.io и используем API для перевода.
Examples¶
Here is an example session that uses the method:
>>> import http.client >>> conn = http.client.HTTPSConnection("www.python.org") >>> conn.request("GET", "/") >>> r1 = conn.getresponse() >>> print(r1.status, r1.reason) 200 OK >>> data1 = r1.read() # This will return entire content. >>> # The following example demonstrates reading data in chunks. >>> conn.request("GET", "/") >>> r1 = conn.getresponse() >>> while chunk := r1.read(200): ... print(repr(chunk)) b'<!doctype html>\n<!--[if"... ... >>> # Example of an invalid request >>> conn = http.client.HTTPSConnection("docs.python.org") >>> conn.request("GET", "/parrot.spam") >>> r2 = conn.getresponse() >>> print(r2.status, r2.reason) 404 Not Found >>> data2 = r2.read() >>> conn.close()
Here is an example session that uses the method. Note that the
method never returns any data.
>>> import http.client >>> conn = http.client.HTTPSConnection("www.python.org") >>> conn.request("HEAD", "/") >>> res = conn.getresponse() >>> print(res.status, res.reason) 200 OK >>> data = res.read() >>> print(len(data)) >>> data == b'' True
Here is an example session that shows how to requests:
>>> import http.client, urllib.parse >>> params = urllib.parse.urlencode({'@number' 12524, '@type' 'issue', '@action' 'show'}) >>> headers = {"Content-type" "application/x-www-form-urlencoded", ... "Accept" "text/plain"} >>> conn = http.client.HTTPConnection("bugs.python.org") >>> conn.request("POST", "", params, headers) >>> response = conn.getresponse() >>> print(response.status, response.reason) 302 Found >>> data = response.read() >>> data b'Redirecting to <a href="http://bugs.python.org/issue12524">http://bugs.python.org/issue12524</a>' >>> conn.close()
Client side requests are very similar to requests. The
difference lies only the server side where HTTP server will allow resources to
be created via request. It should be noted that custom HTTP methods
are also handled in by setting the appropriate
method attribute. Here is an example session that shows how to send a
request using http.client:
Body Content Workflow¶
By default, when you make a request, the body of the response is downloaded
immediately. You can override this behaviour and defer downloading the response
body until you access the
attribute with the parameter:
tarball_url = 'https://github.com/psf/requests/tarball/master' r = requests.get(tarball_url, stream=True)
At this point only the response headers have been downloaded and the connection
remains open, hence allowing us to make content retrieval conditional:
if int(r.headers'content-length']) < TOO_LONG content = r.content ...
You can further control the workflow by use of the
and methods.
Alternatively, you can read the undecoded body from the underlying
urllib3 at
.
If you set to when making a request, Requests cannot
release the connection back to the pool unless you consume all the data or call
. This can lead to
inefficiency with connections. If you find yourself partially reading request
bodies (or not reading them at all) while using , you should
make the request within a statement to ensure it’s always closed:
Чтение ответа
Ответ на HTTP-запрос может содержать множество заголовков, содержащих различную информацию.
httpbin – популярный веб-сайт для тестирования различных операций HTTP. В этой статье мы будем использовать httpbin или get для анализа ответа на запрос GET. Прежде всего, нам нужно узнать заголовок ответа и то, как он выглядит. Вы можете использовать любой современный веб-браузер, чтобы найти его, но для этого примера мы будем использовать браузер Google Chrome:
- В Chrome откройте URL-адрес http://httpbin.org/get, щелкните правой кнопкой мыши в любом месте страницы и выберите параметр «Проверить».
- Это откроет новое окно в вашем браузере. Обновите страницу и перейдите на вкладку «Сеть».
- Эта вкладка «Сеть» покажет вам все различные типы сетевых запросов, сделанных браузером. Щелкните запрос «получить» в столбце «Имя» и выберите вкладку «Заголовки» справа.
Содержание «Заголовков ответа» является нашим обязательным элементом. Вы можете увидеть пары ключ-значение, содержащие различную информацию о ресурсе и запросе. Попробуем разобрать эти значения с помощью библиотеки запросов:
import requests r = requests.get('http://httpbin.org/get') print(r.headers) print(r.headers) print(r.headers) print(r.headers) print(r.headers) print(r.headers) print(r.headers) print(r.headers)
Мы получили информацию заголовка с помощью r.headers, и мы можем получить доступ к каждому значению заголовка с помощью определенных ключей
Обратите внимание, что ключ не чувствителен к регистру.. Точно так же попробуем получить доступ к значению ответа
Заголовок выше показывает, что ответ находится в формате JSON: (Content-type: application/json). Библиотека запросов поставляется с одним встроенным парсером JSON, и мы можем использовать request.get (‘url’). Json() для анализа его как объекта JSON. Затем значение для каждого ключа результатов ответа можно легко проанализировать, как показано ниже:
Точно так же попробуем получить доступ к значению ответа. Заголовок выше показывает, что ответ находится в формате JSON: (Content-type: application/json). Библиотека запросов поставляется с одним встроенным парсером JSON, и мы можем использовать request.get (‘url’). Json() для анализа его как объекта JSON. Затем значение для каждого ключа результатов ответа можно легко проанализировать, как показано ниже:
import requests r = requests.get('http://httpbin.org/get') response = r.json() print(r.json()) print(response) print(response) print(response) print(response) print(response) print(response) print(response) print(response) print(response)
Приведенный выше код напечатает следующий вывод:
{'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
Третья строка, ierjson(), напечатала значение ответа JSON. Мы сохранили значение JSON в ответе переменной, а затем распечатали значение для каждого ключа
Обратите внимание, что в отличие от предыдущего примера, пара «ключ-значение» чувствительна к регистру.
Подобно JSON и текстовому контенту, мы можем использовать запросы для чтения контента ответа в байтах для нетекстовых запросов, используя свойство .content. Это автоматически декодирует gzip и дефлирует закодированные файлы.
Request Header Fields
We will study General-header and Entity-header in a separate chapter when we will learn HTTP header fields. For now, let’s check what Request header fields are.
The request-header fields allow the client to pass additional information about the request, and about the client itself, to the server. These fields act as request modifiers.Here is a list of some important Request-header fields that can be used based on the requirement:
-
Accept-Charset
-
Accept-Encoding
-
Accept-Language
-
Authorization
-
Expect
-
From
-
Host
-
If-Match
-
If-Modified-Since
-
If-None-Match
-
If-Range
-
If-Unmodified-Since
-
Max-Forwards
-
Proxy-Authorization
-
Range
-
Referer
-
TE
-
User-Agent
You can introduce your custom fields in case you are going to write your own custom Client and Web Server.
POST
Чтобы отправить и проверить POST запрос внесите небольшие изменения в код.
Очевидно, что GET нужно заменить на POST, также params нужно заменить на data
url: https://httpbin.org/post
text:
{
«args»: {},
«data»: «»,
«files»: {},
«form»: {
«established»: «2018»,
«website»: «heihei.ru»
},
«headers»: {
«Accept»: «*/*»,
«Accept-Encoding»: «gzip, deflate»,
«Content-Length»: «34»,
«Content-Type»: «application/x-www-form-urlencoded»,
«Host»: «httpbin.org»,
«User-Agent»: «python-requests/2.24.0»,
«X-Amzn-Trace-Id»: «Root=1-5f8c30ac-6b32899f073f9df4055c55c4»
},
«json»: null,
«origin»: «87.92.8.47»,
«url»: «https://httpbin.org/post»
}
Ответы, которые мы получили с httpbin приходили в формате json
Для работы c json бывает удобно
использовать встроенный метод .json()
В этом случае данные записываются в словарь и к ним очень легко обращаться.
Обратите внимание на «form» данные, которые были переданы возвращаются в этом поле.
Изменим код так, чтобы на экран выводились только эти данные. python3 rdemo.py
python3 rdemo.py
{‘established’: ‘2018’, ‘website’: ‘heihei.ru’}
OpenerDirector Objects¶
instances have the following methods:
- (handler)
-
handler should be an instance of . The following methods
are searched, and added to the possible chains (note that HTTP errors are a
special case). Note that, in the following, protocol should be replaced
with the actual protocol to handle, for example would
be the HTTP protocol response handler. Also type should be replaced with
the actual HTTP code, for example would handle HTTP
404 errors.-
— signal that the handler knows how to open protocol
URLs.See for more information.
-
— signal that the handler knows how to handle HTTP
errors with HTTP error code type.See for more information.
-
— signal that the handler knows how to handle errors
from (non-) protocol. -
— signal that the handler knows how to pre-process
protocol requests.See for more information.
-
— signal that the handler knows how to
post-process protocol responses.See for more information.
-
- (url, data=None, timeout)
-
Open the given url (which can be a request object or a string), optionally
passing the given data. Arguments, return values and exceptions raised are
the same as those of (which simply calls the
method on the currently installed global ). The
optional timeout parameter specifies a timeout in seconds for blocking
operations like the connection attempt (if not specified, the global default
timeout setting will be used). The timeout feature actually works only for
HTTP, HTTPS and FTP connections.
- (proto, *args)
-
Handle an error of the given protocol. This will call the registered error
handlers for the given protocol with the given arguments (which are protocol
specific). The HTTP protocol is a special case which uses the HTTP response
code to determine the specific error handler; refer to the
methods of the handler classes.Return values and exceptions raised are the same as those of .
OpenerDirector objects open URLs in three stages:
The order in which these methods are called within each stage is determined by
sorting the handler instances.
Задержка
Часто бывает нужно ограничить время ожидания ответа. Это можно сделать с помощью параметра timeout
Перейдите на
раздел — / #/ Dynamic_data / delete_delay__delay_
и изучите документацию — если делать запрос на этот url можно выставлять время, через которое
будет отправлен ответ.
Создайте файл
timeout_demo.py
следующего содержания
Задержка равна одной секунде. А ждать ответ можно до трёх секунд.
python3 timeout_demo.py
<Response >
Измените код так, чтобы ответ приходил заведомо позже чем наш таймаут в три секунды.
Задержка равна семи секундам. А ждать ответ можно по-прежнему только до трёх секунд.
python3 timeout_demo.py
Traceback (most recent call last):
File «/usr/lib/python3/dist-packages/urllib3/connectionpool.py», line 421, in _make_request
six.raise_from(e, None)
File «<string>», line 3, in raise_from
File «/usr/lib/python3/dist-packages/urllib3/connectionpool.py», line 416, in _make_request
httplib_response = conn.getresponse()
File «/usr/lib/python3.8/http/client.py», line 1347, in getresponse
response.begin()
File «/usr/lib/python3.8/http/client.py», line 307, in begin
version, status, reason = self._read_status()
File «/usr/lib/python3.8/http/client.py», line 268, in _read_status
line = str(self.fp.readline(_MAXLINE + 1), «iso-8859-1»)
File «/usr/lib/python3.8/socket.py», line 669, in readinto
return self._sock.recv_into(b)
File «/usr/lib/python3/dist-packages/urllib3/contrib/pyopenssl.py», line 326, in recv_into
raise timeout(«The read operation timed out»)
socket.timeout: The read operation timed out
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File «/usr/lib/python3/dist-packages/requests/adapters.py», line 439, in send
resp = conn.urlopen(
File «/usr/lib/python3/dist-packages/urllib3/connectionpool.py», line 719, in urlopen
retries = retries.increment(
File «/usr/lib/python3/dist-packages/urllib3/util/retry.py», line 400, in increment
raise six.reraise(type(error), error, _stacktrace)
File «/usr/lib/python3/dist-packages/six.py», line 703, in reraise
raise value
File «/usr/lib/python3/dist-packages/urllib3/connectionpool.py», line 665, in urlopen
httplib_response = self._make_request(
File «/usr/lib/python3/dist-packages/urllib3/connectionpool.py», line 423, in _make_request
self._raise_timeout(err=e, url=url, timeout_value=read_timeout)
File «/usr/lib/python3/dist-packages/urllib3/connectionpool.py», line 330, in _raise_timeout
raise ReadTimeoutError(
urllib3.exceptions.ReadTimeoutError: HTTPSConnectionPool(host=’httpbin.org’, port=443): Read timed out. (read timeout=3)
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File «timeout_demo.py», line 4, in <module>
r = requests.get(‘https://httpbin.org/delay/7’, timeout=3)
File «/usr/lib/python3/dist-packages/requests/api.py», line 75, in get
return request(‘get’, url, params=params, **kwargs)
File «/usr/lib/python3/dist-packages/requests/api.py», line 60, in request
return session.request(method=method, url=url, **kwargs)
File «/usr/lib/python3/dist-packages/requests/sessions.py», line 533, in request
resp = self.send(prep, **send_kwargs)
File «/usr/lib/python3/dist-packages/requests/sessions.py», line 646, in send
r = adapter.send(request, **kwargs)
File «/usr/lib/python3/dist-packages/requests/adapters.py», line 529, in send
raise ReadTimeout(e, request=request)
requests.exceptions.ReadTimeout: HTTPSConnectionPool(host=’httpbin.org’, port=443): Read timed out. (read timeout=3)
Если такая обработка исключений не вызывает у вас восторга — измените код используя try except
python3 timeout_demo.py
Response is taking too long.
Response Status Codes¶
We can check the response status code:
>>> r = requests.get('https://httpbin.org/get') >>> r.status_code 200
Requests also comes with a built-in status code lookup object for easy
reference:
>>> r.status_code == requests.codes.ok True
If we made a bad request (a 4XX client error or 5XX server error response), we
can raise it with
:
>>> bad_r = requests.get('https://httpbin.org/status/404') >>> bad_r.status_code 404 >>> bad_r.raise_for_status() Traceback (most recent call last): File "requests/models.py", line 832, in raise_for_status raise http_error requests.exceptions.HTTPError: 404 Client Error
But, since our for was , when we call
we get:
>>> r.raise_for_status() None
Response Content¶
We can read the content of the server’s response. Consider the GitHub timeline
again:
>>> import requests >>> r = requests.get('https://api.github.com/events') >>> r.text '[{"repository":{"open_issues":0,"url":"https://github.com/...
Requests will automatically decode content from the server. Most unicode
charsets are seamlessly decoded.
When you make a request, Requests makes educated guesses about the encoding of
the response based on the HTTP headers. The text encoding guessed by Requests
is used when you access . You can find out what encoding Requests is
using, and change it, using the property:
>>> r.encoding 'utf-8' >>> r.encoding = 'ISO-8859-1'
If you change the encoding, Requests will use the new value of
whenever you call . You might want to do this in any situation where
you can apply special logic to work out what the encoding of the content will
be. For example, HTML and XML have the ability to specify their encoding in
their body. In situations like this, you should use to find the
encoding, and then set . This will let you use with
the correct encoding.