Python’s requests library (guide)
Содержание:
- Передача параметров в URL
- Properties and Methods
- Обработка ошибок
- Как послать Multipart-Encoded файл
- POST
- Python requests reading a web page
- Parameter Values
- Производительность
- What Are the Various Types of HTTP Request Methods?
- Headers
- C# POST request with WebRequest
- Заголовки
- Python requests upload image
- PHP POST request in Laravel
- Асинхронность
- Эффективная обработка файлов
Передача параметров в URL
Часто вы хотите послать какие-то данные в строке запроса URL. Если вы строите URL вручную, то эти данные будут представлены в нем в виде пар ключ-значение после знака вопроса. Например, . Requests позволяет передать эти аргументы в качестве словаря, используя аргумент . В качестве примера, если вы хотите передать и ресурсу , вы должны использовать следующий код:
>>> payload = {'key1': 'value1', 'key2': 'value2'} >>> r = requests.get("http://httpbin.org/get", params=payload)
Вы можете видеть, что URL был закодирован правильно:
>>> print(r.url) http://httpbin.org/get?key2=value2&key1=value1
Заметим, что любой ключ словаря, значение которого , не будет добавлен к строке запроса URL.
Properties and Methods
Property/Method | Description | |
---|---|---|
apparent_encoding | Try it | Returns the apparent encoding |
close() | Try it | Closes the connection to the server |
content | Try it | Returns the content of the response, in bytes |
cookies | Try it | Returns a CookieJar object with the cookies sent back from the server |
elapsed | Try it | Returns a timedelta object with the time elapsed from sending the request to the arrival of the response |
encoding | Try it | Returns the encoding used to decode r.text |
headers | Try it | Returns a dictionary of response headers |
history | Try it | Returns a list of response objects holding the history of request (url) |
is_permanent_redirect | Try it | Returns True if the response is the permanent redirected url, otherwise False |
is_redirect | Try it | Returns True if the response was redirected, otherwise False |
iter_content() | Try it | Iterates over the response |
iter_lines() | Try it | Iterates over the lines of the response |
json() | Try it | Returns a JSON object of the result (if the result was written in JSON format, if not it raises an error) |
links | Try it | Returns the header links |
next | Try it | Returns a PreparedRequest object for the next request in a redirection |
ok | Try it | Returns True if status_code is less than 400, otherwise False |
raise_for_status() | Try it | If an error occur, this method returns a HTTPError object |
reason | Try it | Returns a text corresponding to the status code |
request | Try it | Returns the request object that requested this response |
status_code | Try it | Returns a number that indicates the status (200 is OK, 404 is Not Found) |
text | Try it | Returns the content of the response, in unicode |
url | Try it | Returns the URL of the response |
Обработка ошибок
Всегда хорошо реализовать обработку ошибок. Это не только поможет избежать неожиданного выхода скрипта, но также помоет вести журнал ошибок и уведомлений. Используя запросы Python, я предпочитаю ловить ошибки следующим образом:
Попробуйте:
Python
try:
# Логика нашего парсера.
r = requests.get(‘https://python-scripts.com’)
except requests.ConnectionError as e:
print(«OOPS!! Connection Error. Make sure you are connected to Internet. Technical Details given below.\n»)
print(str(e))
except requests.Timeout as e:
print(«OOPS!! Timeout Error»)
print(str(e))
except requests.RequestException as e:
print(«OOPS!! General Error»)
print(str(e))
except KeyboardInterrupt:
print(«Someone closed the program»)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
try # Логика нашего парсера. r=requests.get(‘https://python-scripts.com’) exceptrequests.ConnectionError ase print(«OOPS!! Connection Error. Make sure you are connected to Internet. Technical Details given below.\n») print(str(e)) exceptrequests.Timeout ase print(«OOPS!! Timeout Error») print(str(e)) exceptrequests.RequestException ase print(«OOPS!! General Error») print(str(e)) exceptKeyboardInterrupt print(«Someone closed the program») |
Проверьте последнюю часть кода. В ней программе указывается, что если кто-нибудь хочет завершить программу через Ctrl+C, то содержимое сначала оборачивается, после чего выполняется. Эта ситуация хороша, если вы храните информацию в файле и хотите сбросить все в момент выхода.
Как послать Multipart-Encoded файл
Requests позволяет легко послать на сервер Multipart-Encoded файлы:
>>> url = 'http://httpbin.org/post' >>> files = {'file': open('report.xls', 'rb')} >>> r = requests.post(url, files=files) >>> r.text { ... "files": { "file": "<censored...binary...data>" }, ... }
Вы можете установить имя файла, content-type и заголовки в явном виде:
>>> url = 'http://httpbin.org/post' >>> files = {'file': ('report.xls', open('report.xls', 'rb'), 'application/vnd.ms-excel', {'Expires': '0'})} >>> r = requests.post(url, files=files) >>> r.text { ... "files": { "file": "<censored...binary...data>" }, ... }
При желании, вы можете отправить строки, которые будут приняты в виде файлов:
>>> url = 'http://httpbin.org/post' >>> files = {'file': ('report.csv', 'some,data,to,send\nanother,row,to,send\n')} >>> r = requests.post(url, files=files) >>> r.text { ... "files": { "file": "some,data,to,send\nanother,row,to,send\n" }, ... }
В случае, если вы отправляете очень большой файл как , вы можете захотеть отправить запрос потоком. По умолчанию не поддерживает этого, но есть отдельный пакет, который это делает — .
Для отправки нескольких файлов в одном запросе, обратитесь к дополнительной документации.
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’}
Python requests reading a web page
The method issues a GET request; it fetches documents
identified by the given URL.
read_webpage.py
#!/usr/bin/env python3 import requests as req resp = req.get("http://www.webcode.me") print(resp.text)
The script grabs the content of the web page.
resp = req.get("http://www.webcode.me")
The method returns a response object.
print(resp.text)
The text attribute contains the content of the response, in Unicode.
$ ./read_webpage.py <!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> </html>
This is the output of the script.
The following program gets a small web page and strips its HTML tags.
strip_tags.py
#!/usr/bin/env python3 import requests as req import re resp = req.get("http://www.webcode.me") content = resp.text stripped = re.sub('<+?>', '', content) print(stripped)
The script strips the HTML tags of the
web page.
stripped = re.sub('<+?>', '', content)
A simple regular expression is used to strip the HTML tags.
Parameter Values
Parameter | Description | |
---|---|---|
url | Try it | Required. The url of the request |
data | Try it | Optional. A dictionary, list of tuples, bytes or a file object to send to the specified url |
json | Try it | Optional. A JSON object to send to the specified url |
files | Try it | Optional. A dictionary of files to send to the specified url |
allow_redirects | Try it | Optional. A Boolean to enable/disable redirection.Default (allowing redirects) |
auth | Try it | Optional. A tuple to enable a certain HTTP authentication.Default |
cert | Try it | Optional. A String or Tuple specifying a cert file or key.Default |
cookies | Try it | Optional. A dictionary of cookies to send to the specified url.Default |
headers | Try it | Optional. A dictionary of HTTP headers to send to the specified url.Default |
proxies | Try it | Optional. A dictionary of the protocol to the proxy url.Default |
stream | Try it | Optional. A Boolean indication if the response should be immediately downloaded (False) or streamed (True).Default |
timeout | Try it | Optional. A number, or a tuple, indicating how many seconds to wait for the client to make a connection and/or send a response.Default which means the request will continue until the connection is closed |
verify |
Try it Try it |
Optional. A Boolean or a String indication to verify the servers TLS certificate or not.Default |
Производительность
При использовании , особенно в продакшене, важно учитывать влияние на производительность. Такие функции, как контроль времени ожидания, сеансы и ограничения повторных попыток, могут обеспечить вам бесперебойную работу приложения
Время ожидания
Когда вы отправляете запрос во внешнюю службу, вашей системе потребуется дождаться ответа, прежде чем двигаться дальше. Если ваше предложение слишком долго ожидает ответа — запросы к службе могут быть скопированы, пользовательский интерфейс может пострадать или фоновые задания могут зависнуть.
По умолчанию, будет ждать ответа до бесконечности, поэтому вы почти всегда должны указывать время ожидания. Чтобы установить время ожидания, используйте параметр . Тайм-аут может быть целым числом или числом с плавающей запятой, представляющим количество секунд ожидания ответа:
В первом запросе, время ожидания истекает через одну секунду. Во втором — через 3,05 секунд.
Вы также можете передать кортеж тайм-ауту. Первый элемент в кортеже является тайм-аутом соединения (время, которое позволяет установить клиенту соединение с сервером), а второй элемент — время ожидания чтения (время ожидания ответа после того, как клиент установил соединение):
Если запрос устанавливает соединение в течение 2 секунд и получает данные в течение 5 секунд после установки соединения, то ответ будет возвращен. Если время ожидания истекло — функция вызовет исключение :
Ваша программа может перехватить исключение и ответить соответствующим образом.
Объект Session
До сих пор вы имели дело с интерфейсами API высокого уровня, такими как и . Эти функции являются абстракциями над тем, что происходит когда вы делаете свои запросы. Они скрывают детали реализации, такие как управление соединениями, так что вам не нужно беспокоиться о них.
Под этими абстракциями находится класс . Если вам необходимо настроить контроль над выполнением запросов и повысить производительность вашего приложения — вам может потребоваться использовать экземпляр напрямую.
Сеансы используются для сохранения параметров в запросах. Например, если вы хотите использовать одну и ту же аутентификацию для нескольких запросов, вы можете использовать сеанс:
Каждый раз, когда вы делаете запрос в сеансе, после того, как он был инициализирован с учетными данными аутентификации, учетные данные будут сохраняться.
Первичная оптимизация производительности сессий происходит в форме постоянных соединений. Когда ваше приложение устанавливает соединение с сервером, используя , оно сохраняет это соединение в пуле с остальными соединениями. Когда ваше приложение снова подключиться к тому же серверу, оно будет повторно использовать соединение из пула, а не устанавливать новое.
Максимальное количество попыток
В случае сбоя запроса, вы можете захотеть, чтобы приложение отправило запрос повторно. Однако не делает этого за вас по умолчанию. Чтобы реализовать эту функцию, вам необходимо реализовать собственный .
Транспортные адаптеры позволяют вам определять набор конфигураций для каждой службы , с которой вы взаимодействуете. Например, вы хотите, чтобы все запросы к https://api.github.com, повторялись по три раза, прежде чем вызовется исключение . Вы должны сконструировать транспортный адаптер, установить его параметр и подключить его к существующему сеансу:
Когда вы монтируете и в — будет придерживаться этой конфигурации в каждом запросе к https://api.github.com.
Время ожидания, транспортные адаптеры и сеансы, предназначены для обеспечения эффективности вашего кода и отказоустойчивости приложения.
What Are the Various Types of HTTP Request Methods?
GET
GET is used to retrieve and request data from a specified resource in a server. GET is one of the most popular HTTP request techniques. In simple words, the GET method is used to retrieve whatever information is identified by the Request-URL.
HEAD
The HEAD technique requests a reaction that is similar to that of GET request, but doesn’t have a message-body in the response. The HEAD request method is useful in recovering meta-data that is written according to the headers, without transferring the entire content. The technique is commonly used when testing hypertext links for accessibility, validity, and recent modification.
POST
Another popular HTTP request method is POST. In web communication, POST requests are utilized to send data to a server to create or update a resource. The information submitted to the server with POST request method is archived in the request body of the HTTP request. The HTTP POST method is often used to send user-generated data to a server. One example is when a user uploads a profile photo.
PUT
PUT is similar to POST as it is used to send data to the server to create or update a resource. The difference between the two is that PUT requests are idempotent. This means that if you call the same PUT requests multiple times, the results will always be the same.
DELETE
Just as it sounds, the DELETE request method is used to delete resources indicated by a specific URL. Making a DELETE request will remove the targeted resource.
PATCH
A PATCH request is similar to POST and PUT. However, its primary purpose is to apply partial modifications to the resource. And just like a POST request, the PATCH request is also non-idempotent. Additionally, unlike POST and PUT which require a full user entity, with PATCH requests, you may only send the updated username.
TRACE
TRACE requests are used to invoke a remote, application loop-back test along the path to the target resource. The TRACE method allows clients to view whatever message is being received at the other end of the request chain so that they can use the information for testing or diagnostic functions.
CONNECT
The CONNECT request method is used by the client to create a network connection to a web server over a particular HTTP. A good example is SSL tunneling. In a nutshell, CONNECT request establishes a tunnel to the server identified by a specific URL.
Headers
Another thing you can get from the response are the headers. You can take a look at them by using the headers dictionary on the response object.
Headers are sent along with the request and returned in the response. Headers are used so both the client and the server know how to interpret the data that is being sent and received in the response/response.
We see the various headers that are returned. A lot of times you won’t need to use the header information directly, but it’s there if you need it.
The content type is usually the one you may need because it reveals the format of the data, for example HTML, JSON, PDF, text, etc. But the content type is normally handled by Requests so you can easily access the data that gets returned.
C# POST request with WebRequest
The next example creates a POST request with .
Program.cs
using System; using System.IO; using System.Text; using System.Net; using System.Text.Json; var url = "https://httpbin.org/post"; var request = WebRequest.Create(url); request.Method = "POST"; var user = new User("John Doe", "gardener"); var json = JsonSerializer.Serialize(user); byte[] byteArray = Encoding.UTF8.GetBytes(json); request.ContentType = "application/x-www-form-urlencoded"; request.ContentLength = byteArray.Length; using var reqStream = request.GetRequestStream(); reqStream.Write(byteArray, 0, byteArray.Length); using var response = request.GetResponse(); Console.WriteLine(((HttpWebResponse)response).StatusDescription); using var respStream = response.GetResponseStream(); using var reader = new StreamReader(respStream); string data = reader.ReadToEnd(); Console.WriteLine(data); record User(string Name, string Occupation);
We send a POST request to the https://httpbin.org/post page. The data sent
is in JSON format.
var request = WebRequest.Create(url); request.Method = "POST";
We set the method of the request to POST.
var user = new User("John Doe", "gardener"); var json = JsonSerializer.Serialize(user); byte[] byteArray = Encoding.UTF8.GetBytes(json);
We serialize a user object to JSON and transform the JSON data into an array of
bytes.
using var reqStream = request.GetRequestStream(); reqstream.Write(byteArray, 0, byteArray.Length);
We get the stream of the request with and write
the byte array into the stream with .
using var response = request.GetResponse();
We get the response with .
Console.WriteLine(((HttpWebResponse)response).StatusDescription);
We print the status of the response.
using var respStream = response.GetResponseStream(); using var reader = new StreamReader(respStream); string data = reader.ReadToEnd(); Console.WriteLine(data);
We read the data from the response stream.
$ dotnet run OK { "args": {}, "data": "", "files": {}, "form": { "{\"Name\":\"John Doe\",\"Occupation\":\"gardener\"}": "" }, "headers": { "Content-Length": "43", "Content-Type": "application/x-www-form-urlencoded", "Host": "httpbin.org", "X-Amzn-Trace-Id": "Root=1-5ffb119c-010dea546a9b4c8c370bca46" }, "json": null, "origin": "188.167.250.74", "url": "https://httpbin.org/post" }
Заголовки
Также в ответе вы можете получить заголовки. Вы можете посмотреть их, используя словарь headers для объекта response.
script.py
Заголовки отправляются вместе с запросом и возвращаются с ответом. Заголовки используются для того, чтобы клиент и сервер понимали, как интерпретировать данные, отправляемые и получаемые в запросе и ответе.
Мы увидим в ответе несколько заголовков. Обычно информация из заголовков не требуется, однако если она вам нужна, вы можете ее получить.
Обычно требуется заголовок content type, поскольку он показывает формат данных, например HTML, JSON, PDF, обычный текст и т. д. Однако заголовок content type обрабатывается библиотекой Requests, и вы имеете доступ ко всем возвращаемым данным.
Python requests upload image
In the following example, we are going to upload an image. We create
a web application with Flask.
app.py
#!/usr/bin/env python3 import os from flask import Flask, request app = Flask(__name__) @app.route("/") def home(): return 'This is home page' @app.route("/upload", methods=) def handleFileUpload(): msg = 'failed to upload image' if 'image' in request.files: photo = request.files if photo.filename != '': photo.save(os.path.join('.', photo.filename)) msg = 'image uploaded successfully' return msg if __name__ == '__main__': app.run()
This is a simple application with two endpoints. The
endpoint checks if there is some image and saves it to the current directory.
upload_file.py
#!/usr/bin/env python3 import requests as req url = 'http://localhost:5000/upload' with open('sid.jpg', 'rb') as f: files = {'image': f} r = req.post(url, files=files) print(r.text)
We send the image to the Flask application. The file is specified
in the attribute of the method.
PHP POST request in Laravel
In the following example, we send a POST request from an HTML form.
resources/views/home.blade.php
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>Home page</title> <style> .alert { color: red} </style> </head> <body> @if ($errors->any()) <div class="alert"> <ul> @foreach ($errors->all() as $error) <li>{{ $error }}</li> @endforeach </ul> </div> @endif <form action="process_form" method="post"> @csrf <label for="name">Name</label> <input id="name" value="{{old('name')}}"type="text" name="name"> <label for="message">Message</label> <input id="message" value="{{old('message')}}" type="text" name="message"> <button type="submit">Submit</button> </form> </body> </html>
We have a POST form in a Blade template. Laravel requires CSRF protection for
POST requests. We enable CSRF protection with .
routes/web.php
<?php use Illuminate\Support\Facades\Route; use Illuminate\Http\Request; Route::get('/', function () { return view('home'); }); Route::post('/process_form', function (Request $request) { $request->validate(); $name = $request->input('name'); $message = $request->input('message'); $output = "$name says: $message"; return $output; });
We validate and retrieve the POST parameters and send them in the response.
This example should be tested in a browser.
In this tutorial, we have worked with GET and POST requests in plain PHP,
Symfony, Slim, and Laravel.
List tutorials.
Асинхронность
Как объяснялось ранее, requests полностью синхронен. Он блокирует приложение в ожидании ответа сервера, замедляя работу программы. Создание HTTP-запросов в потоках является одним из решений, но потоки имеют свои собственные накладные расходы, и это подразумевает параллелизм, который не всегда каждый рад видеть в программе.
Начиная с версии 3.5, Python предлагает асинхронность внутри своего ядра, используя aiohttp. Библиотека aiohttp предоставляет асинхронный HTTP-клиент, построенный поверх asyncio. Эта библиотека позволяет отправлять запросы последовательно, но не дожидаясь первого ответа, прежде чем отправлять новый. В отличие от конвейерной передачи HTTP, aiohttp отправляет запросы по нескольким соединениям параллельно, избегая проблемы, описанной ранее.
Использование aiohttp
import aiohttp import asyncio async def get(url): async with aiohttp.ClientSession() as session: async with session.get(url) as response: return response loop = asyncio.get_event_loop() coroutines = [get("http://example.com") for _ in range(8)] results = loop.run_until_complete(asyncio.gather(*coroutines)) print("Results: %s" % results)
Все эти решения (с использованием Session, thread, futures или asyncio) предлагают разные подходы к ускорению работы HTTP-клиентов. Но какая между ними разница с точки зрения производительности?
Эффективная обработка файлов
Одна из функций парсера – это хранение данных как в базе данных, так и в обычных файлах, таких как CSV/Text. Если собираете большой объем данных, это не означает, что операция ввода-вывода будет в цикле. Давайте рассмотрим, как это делается.
Пробуем:
Python
try:
a_list_variable = []
a_list_variable.extend(a_func_return_record())
except requests.ConnectionError as e:
print(«Упс!! Ошибка подключения к интернету.»)
print(str(e))
except requests.Timeout as e:
print(«Упс!! Время ожидания истекло.»)
print(str(e))
except requests.RequestException as e:
print(«Упс!! Возникла непредвиденная ошибка!»)
print(str(e))
except KeyboardInterrupt:
print(«Кто-то закрыл принудительно программу.»)
finally:
print(«Total Records = » + str(len(property_urls)))
try:
# файл для хранения URL
record_file = open(‘records_file.txt’, ‘a+’)
record_file.write(«\n».join(property_urls))
record_file.close()
except Exception as ex:
print(«Возникла ошибка при сохранении данных, текст ошибки:»)
print(str(e))
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
try a_list_variable= a_list_variable.extend(a_func_return_record()) exceptrequests.ConnectionError ase print(«Упс!! Ошибка подключения к интернету.») print(str(e)) exceptrequests.Timeout ase print(«Упс!! Время ожидания истекло.») print(str(e)) exceptrequests.RequestException ase print(«Упс!! Возникла непредвиденная ошибка!») print(str(e)) exceptKeyboardInterrupt print(«Кто-то закрыл принудительно программу.») finally print(«Total Records = «+str(len(property_urls))) try # файл для хранения URL record_file=open(‘records_file.txt’,’a+’) record_file.write(«\n».join(property_urls)) record_file.close() exceptExceptionasex print(«Возникла ошибка при сохранении данных, текст ошибки:») print(str(e)) |
Здесь я вызываю функцию (хотя вы не обязаны делать то же самое), которая добавляет записи в список. Как только это будет сделано, или программа будет остановлена, перед завершением она просто сохранит весь список в файл за раз. Намного лучше, чем несколько операций ввода-вывода
Надеюсь, эта статья была для вас полезной. Пожалуйста, Поделитесь своим опытом о том, как сделать парсер более эффективным!