Введение
Библиотека Python requests — это мощный инструмент для взаимодействия с веб-сервисами и API. В этом руководстве вы узнаете, как отправлять HTTP-запросы и анализировать данные ответов с помощью Python. К концу этой лабораторной работы вы сможете извлекать ценную информацию из различных типов ответов API, что позволит вам создавать приложения, управляемые данными, и автоматизировать веб-взаимодействия.
Установка библиотеки Requests и выполнение базового запроса
На этом первом шаге мы установим библиотеку Python requests и выполним наш первый HTTP-запрос для получения данных из общедоступного API.
Установка Requests
Библиотека requests — это сторонний пакет, который необходимо установить с помощью pip, установщика пакетов Python. Давайте начнем с его установки:
pip install requests
Вы должны увидеть вывод, подтверждающий, что requests успешно установлена.
Выполнение вашего первого HTTP-запроса
Теперь давайте создадим файл Python для выполнения простого HTTP-запроса. В WebIDE создайте новый файл с именем basic_request.py в каталоге /home/labex/project.
Добавьте следующий код в файл:
import requests
## Make a GET request to a public API
response = requests.get("https://jsonplaceholder.typicode.com/todos/1")
## Print the status code
print(f"Status code: {response.status_code}")
## Print the raw response content
print("\nRaw response content:")
print(response.text)
## Print the response headers
print("\nResponse headers:")
for header, value in response.headers.items():
print(f"{header}: {value}")
Этот код выполняет GET-запрос к образцу конечной точки API и выводит информацию об ответе.
Понимание объекта Response
Давайте запустим код, чтобы увидеть, какую информацию мы получим обратно. В терминале запустите:
python basic_request.py
Вы должны увидеть вывод, похожий на этот:
Status code: 200
Raw response content:
{
"userId": 1,
"id": 1,
"title": "delectus aut autem",
"completed": false
}
Response headers:
Date: Mon, 01 Jan 2023 12:00:00 GMT
Content-Type: application/json; charset=utf-8
...
Объект response содержит несколько важных атрибутов:
status_code: HTTP-код состояния (200 означает успех)text: Содержимое ответа в виде строкиheaders: Словарь заголовков ответа
При работе с веб-запросами эти атрибуты помогают вам понять ответ сервера и обработать его соответствующим образом.
HTTP-коды состояния
HTTP-коды состояния указывают, был ли запрос успешным или неудачным:
- 2xx (например, 200): Успех
- 3xx (например, 301): Перенаправление
- 4xx (например, 404): Ошибки клиента
- 5xx (например, 500): Ошибки сервера
Давайте изменим наш код, чтобы проверить успешный ответ. Создайте новый файл с именем check_status.py со следующим содержимым:
import requests
try:
## Make a GET request to a valid URL
response = requests.get("https://jsonplaceholder.typicode.com/todos/1")
## Check if the request was successful
if response.status_code == 200:
print("Request successful!")
else:
print(f"Request failed with status code: {response.status_code}")
## Try an invalid URL
invalid_response = requests.get("https://jsonplaceholder.typicode.com/invalid")
print(f"Invalid URL status code: {invalid_response.status_code}")
except requests.exceptions.RequestException as e:
print(f"An error occurred: {e}")
Запустите этот код, чтобы увидеть, как разные URL-адреса возвращают разные коды состояния:
python check_status.py
Вы должны увидеть, что действительный URL-адрес возвращает код состояния 200, а недействительный URL-адрес возвращает код состояния 404.
Разбор данных JSON-ответа
Многие современные API возвращают данные в формате JSON (JavaScript Object Notation). На этом шаге вы узнаете, как анализировать ответы JSON и работать с данными в Python.
Понимание JSON
JSON — это облегченный формат обмена данными, который легко читать и писать людям, а также легко анализировать и генерировать машинам. Он основан на парах ключ-значение, аналогично словарям Python.
Вот пример объекта JSON:
{
"name": "John Doe",
"age": 30,
"email": "john@example.com",
"is_active": true,
"hobbies": ["reading", "swimming", "cycling"]
}
Разбор ответов JSON
Библиотека requests упрощает разбор ответов JSON с помощью метода .json(). Давайте создадим новый файл с именем parse_json.py и добавим следующий код:
import requests
## Make a request to a GitHub API endpoint that returns JSON data
response = requests.get("https://api.github.com/users/python")
## Check if the request was successful
if response.status_code == 200:
## Parse the JSON response
data = response.json()
## Print the parsed data
print("Parsed JSON data:")
print(f"Username: {data['login']}")
print(f"Name: {data.get('name', 'Not provided')}")
print(f"Followers: {data['followers']}")
print(f"Public repositories: {data['public_repos']}")
## Print the type to verify it's a Python dictionary
print(f"\nType of parsed data: {type(data)}")
## Access nested data
print("\nAccessing specific elements:")
print(f"Avatar URL: {data['avatar_url']}")
else:
print(f"Request failed with status code: {response.status_code}")
Запустите этот скрипт, чтобы увидеть, как данные JSON анализируются в словарь Python:
python parse_json.py
Вы должны увидеть вывод, который отображает информацию о пользователе GitHub, включая его имя пользователя, количество подписчиков и количество репозиториев.
Работа со списками данных
Многие API возвращают списки объектов. Давайте посмотрим, как обрабатывать этот тип ответа. Создайте файл с именем json_list.py со следующим содержимым:
import requests
## Make a request to an API that returns a list of posts
response = requests.get("https://jsonplaceholder.typicode.com/posts")
## Check if the request was successful
if response.status_code == 200:
## Parse the JSON response (this will be a list of posts)
posts = response.json()
## Print the total number of posts
print(f"Total posts: {len(posts)}")
## Print details of the first 3 posts
print("\nFirst 3 posts:")
for i, post in enumerate(posts[:3], 1):
print(f"\nPost #{i}")
print(f"User ID: {post['userId']}")
print(f"Post ID: {post['id']}")
print(f"Title: {post['title']}")
print(f"Body: {post['body'][:50]}...") ## Print just the beginning of the body
else:
print(f"Request failed with status code: {response.status_code}")
Запустите этот скрипт, чтобы увидеть, как обрабатывать список объектов JSON:
python json_list.py
Вы должны увидеть информацию о первых трех сообщениях, включая их заголовки и начало их содержимого.
Обработка ошибок при разборе JSON
Иногда ответ может не содержать допустимых данных JSON. Давайте посмотрим, как это элегантно обработать. Создайте файл с именем json_error.py с этим кодом:
import requests
import json
def get_and_parse_json(url):
try:
## Make the request
response = requests.get(url)
## Check if the request was successful
response.raise_for_status()
## Try to parse the JSON
try:
data = response.json()
return data
except json.JSONDecodeError:
print(f"Response from {url} is not valid JSON")
print(f"Raw response: {response.text[:100]}...") ## Print part of the raw response
return None
except requests.exceptions.HTTPError as e:
print(f"HTTP error: {e}")
except requests.exceptions.RequestException as e:
print(f"Request error: {e}")
return None
## Test with a valid JSON endpoint
json_data = get_and_parse_json("https://jsonplaceholder.typicode.com/posts/1")
if json_data:
print("\nValid JSON response:")
print(f"Title: {json_data['title']}")
## Test with a non-JSON endpoint
html_data = get_and_parse_json("https://www.example.com")
if html_data:
print("\nThis should not print as example.com returns HTML, not JSON")
else:
print("\nAs expected, could not parse HTML as JSON")
Запустите этот скрипт, чтобы увидеть, как обрабатывать разные типы ответов:
python json_error.py
Вы должны увидеть, что код успешно обрабатывает как допустимые ответы JSON, так и ответы, не являющиеся JSON.
Разбор содержимого HTML с помощью BeautifulSoup
При работе с веб-данными вы часто будете сталкиваться с ответами HTML. Для разбора HTML библиотека BeautifulSoup в Python — отличный инструмент. На этом шаге мы узнаем, как извлекать информацию из ответов HTML.
Установка BeautifulSoup
Сначала установим BeautifulSoup и его HTML-парсер:
pip install beautifulsoup4
Базовый разбор HTML
Давайте создадим файл с именем parse_html.py для получения и разбора веб-страницы:
import requests
from bs4 import BeautifulSoup
## Make a request to a webpage
url = "https://www.example.com"
response = requests.get(url)
## Check if the request was successful
if response.status_code == 200:
## Parse the HTML content
soup = BeautifulSoup(response.text, 'html.parser')
## Extract the page title
title = soup.title.text
print(f"Page title: {title}")
## Extract all paragraphs
paragraphs = soup.find_all('p')
print(f"\nNumber of paragraphs: {len(paragraphs)}")
## Print the text of the first paragraph
if paragraphs:
print(f"\nFirst paragraph text: {paragraphs[0].text.strip()}")
## Extract all links
links = soup.find_all('a')
print(f"\nNumber of links: {len(links)}")
## Print the href attribute of the first link
if links:
print(f"First link href: {links[0].get('href')}")
else:
print(f"Request failed with status code: {response.status_code}")
Запустите этот скрипт, чтобы увидеть, как извлечь основную информацию из HTML-страницы:
python parse_html.py
Вы должны увидеть вывод, показывающий заголовок страницы, количество абзацев, текст первого абзаца, количество ссылок и URL-адрес первой ссылки.
Поиск конкретных элементов
Теперь давайте посмотрим, как найти конкретные элементы с помощью CSS-селекторов. Создайте файл с именем html_selectors.py:
import requests
from bs4 import BeautifulSoup
## Make a request to a webpage with more complex structure
url = "https://quotes.toscrape.com/"
response = requests.get(url)
## Check if the request was successful
if response.status_code == 200:
## Parse the HTML content
soup = BeautifulSoup(response.text, 'html.parser')
## Find all quote elements
quote_elements = soup.select('.quote')
print(f"Number of quotes found: {len(quote_elements)}")
## Process the first 3 quotes
print("\nFirst 3 quotes:")
for i, quote_element in enumerate(quote_elements[:3], 1):
## Extract the quote text
text = quote_element.select_one('.text').text
## Extract the author
author = quote_element.select_one('.author').text
## Extract the tags
tags = [tag.text for tag in quote_element.select('.tag')]
## Print the information
print(f"\nQuote #{i}")
print(f"Text: {text}")
print(f"Author: {author}")
print(f"Tags: {', '.join(tags)}")
else:
print(f"Request failed with status code: {response.status_code}")
Запустите этот скрипт, чтобы увидеть, как использовать CSS-селекторы для извлечения конкретных элементов:
python html_selectors.py
Вы должны увидеть вывод, показывающий информацию о первых трех цитатах, включая текст цитаты, автора и теги.
Создание простого веб-скребка
Давайте объединим все вместе, чтобы создать простой веб-скребок, который извлекает структурированные данные с веб-страницы. Создайте файл с именем quotes_scraper.py:
import requests
from bs4 import BeautifulSoup
import json
import os
def scrape_quotes_page(url):
## Make a request to the webpage
response = requests.get(url)
## Check if the request was successful
if response.status_code != 200:
print(f"Request failed with status code: {response.status_code}")
return None
## Parse the HTML content
soup = BeautifulSoup(response.text, 'html.parser')
## Extract all quotes
quotes = []
for quote_element in soup.select('.quote'):
## Extract the quote text
text = quote_element.select_one('.text').text.strip('"')
## Extract the author
author = quote_element.select_one('.author').text
## Extract the tags
tags = [tag.text for tag in quote_element.select('.tag')]
## Add the quote to our list
quotes.append({
'text': text,
'author': author,
'tags': tags
})
## Check if there's a next page
next_page = soup.select_one('.next a')
next_page_url = None
if next_page:
next_page_url = 'https://quotes.toscrape.com' + next_page['href']
return {
'quotes': quotes,
'next_page': next_page_url
}
## Scrape the first page
result = scrape_quotes_page('https://quotes.toscrape.com/')
if result:
## Print information about the quotes found
quotes = result['quotes']
print(f"Found {len(quotes)} quotes on the first page")
## Print the first 2 quotes
print("\nFirst 2 quotes:")
for i, quote in enumerate(quotes[:2], 1):
print(f"\nQuote #{i}")
print(f"Text: {quote['text']}")
print(f"Author: {quote['author']}")
print(f"Tags: {', '.join(quote['tags'])}")
## Save the quotes to a JSON file
output_dir = '/home/labex/project'
with open(os.path.join(output_dir, 'quotes.json'), 'w') as f:
json.dump(quotes, f, indent=2)
print(f"\nSaved {len(quotes)} quotes to {output_dir}/quotes.json")
## Print information about the next page
if result['next_page']:
print(f"\nNext page URL: {result['next_page']}")
else:
print("\nNo next page available")
Запустите этот скрипт, чтобы извлечь цитаты с веб-сайта:
python quotes_scraper.py
Вы должны увидеть вывод, показывающий информацию о цитатах, найденных на первой странице, и цитаты будут сохранены в файл JSON с именем quotes.json.
Проверьте файл JSON, чтобы увидеть структурированные данные:
cat quotes.json
Файл должен содержать массив JSON-объектов цитат, каждый из которых имеет свойства text, author и tags.
Работа с бинарным содержимым ответа
До сих пор мы фокусировались на текстовых ответах, таких как JSON и HTML. Однако библиотека requests также может обрабатывать бинарное содержимое, такое как изображения, PDF-файлы и другие файлы. На этом шаге мы узнаем, как загружать и обрабатывать бинарное содержимое.
Загрузка изображения
Начнем с загрузки изображения. Создайте файл с именем download_image.py:
import requests
import os
## URL of an image to download
image_url = "https://httpbin.org/image/jpeg"
## Make a request to get the image
response = requests.get(image_url)
## Check if the request was successful
if response.status_code == 200:
## Get the content type
content_type = response.headers.get('Content-Type', '')
print(f"Content-Type: {content_type}")
## Check if the content is an image
if 'image' in content_type:
## Create a directory to save the image if it doesn't exist
output_dir = '/home/labex/project/downloads'
os.makedirs(output_dir, exist_ok=True)
## Save the image to a file
image_path = os.path.join(output_dir, 'sample_image.jpg')
with open(image_path, 'wb') as f:
f.write(response.content)
## Print information about the saved image
print(f"Image saved to: {image_path}")
print(f"Image size: {len(response.content)} bytes")
else:
print("The response does not contain an image")
else:
print(f"Request failed with status code: {response.status_code}")
Запустите этот скрипт, чтобы загрузить изображение:
python download_image.py
Вы должны увидеть вывод, подтверждающий, что изображение было загружено и сохранено в /home/labex/project/downloads/sample_image.jpg.
Загрузка файла с индикатором прогресса
При загрузке больших файлов может быть полезно отображать индикатор прогресса. Давайте создадим скрипт, который показывает ход загрузки. Создайте файл с именем download_with_progress.py:
import requests
import os
import sys
def download_file(url, filename):
## Make a request to get the file
## Stream the response to handle large files efficiently
response = requests.get(url, stream=True)
## Check if the request was successful
if response.status_code != 200:
print(f"Request failed with status code: {response.status_code}")
return False
## Get the total file size if available
total_size = int(response.headers.get('Content-Length', 0))
if total_size:
print(f"Total file size: {total_size/1024:.2f} KB")
else:
print("Content-Length header not found. Unable to determine file size.")
## Create a directory to save the file if it doesn't exist
os.makedirs(os.path.dirname(filename), exist_ok=True)
## Download the file in chunks and show progress
print(f"Downloading {url} to {filename}...")
## Initialize variables for progress tracking
downloaded = 0
chunk_size = 8192 ## 8 KB chunks
## Open the file for writing
with open(filename, 'wb') as f:
## Iterate through the response chunks
for chunk in response.iter_content(chunk_size=chunk_size):
if chunk: ## Filter out keep-alive chunks
f.write(chunk)
downloaded += len(chunk)
## Calculate and display progress
if total_size:
percent = downloaded * 100 / total_size
sys.stdout.write(f"\rProgress: {percent:.1f}% ({downloaded/1024:.1f} KB)")
sys.stdout.flush()
else:
sys.stdout.write(f"\rDownloaded: {downloaded/1024:.1f} KB")
sys.stdout.flush()
## Print a newline to ensure the next output starts on a new line
print()
return True
## URL of a file to download
file_url = "https://speed.hetzner.de/100MB.bin"
## Path where the file will be saved
output_path = '/home/labex/project/downloads/test_file.bin'
## Download the file
success = download_file(file_url, output_path)
if success:
## Get file stats
file_size = os.path.getsize(output_path)
print(f"\nDownload complete!")
print(f"File saved to: {output_path}")
print(f"File size: {file_size/1024/1024:.2f} MB")
else:
print("\nDownload failed.")
Запустите этот скрипт, чтобы загрузить файл с отслеживанием прогресса:
python download_with_progress.py
Вы увидите, как полоса прогресса обновляется по мере загрузки файла. Обратите внимание, что это загружает файл размером 100 МБ, что может занять некоторое время в зависимости от скорости вашего соединения.
Чтобы отменить загрузку, вы можете нажать Ctrl+C.
Работа с заголовками ответов и метаданными
При загрузке файлов заголовки ответов часто содержат полезные метаданные. Давайте создадим скрипт, который подробно изучает заголовки ответов. Создайте файл с именем response_headers.py:
import requests
def check_url(url):
print(f"\nChecking URL: {url}")
try:
## Make a HEAD request first to get headers without downloading the full content
head_response = requests.head(url)
print(f"HEAD request status code: {head_response.status_code}")
if head_response.status_code == 200:
## Print all headers
print("\nResponse headers:")
for header, value in head_response.headers.items():
print(f" {header}: {value}")
## Extract content type and size
content_type = head_response.headers.get('Content-Type', 'Unknown')
content_length = head_response.headers.get('Content-Length', 'Unknown')
print(f"\nContent Type: {content_type}")
if content_length != 'Unknown':
size_kb = int(content_length) / 1024
size_mb = size_kb / 1024
if size_mb >= 1:
print(f"Content Size: {size_mb:.2f} MB")
else:
print(f"Content Size: {size_kb:.2f} KB")
else:
print("Content Size: Unknown")
## Check if the server supports range requests
accept_ranges = head_response.headers.get('Accept-Ranges', 'none')
print(f"Supports range requests: {'Yes' if accept_ranges != 'none' else 'No'}")
else:
print(f"HEAD request failed with status code: {head_response.status_code}")
except requests.exceptions.RequestException as e:
print(f"Error: {e}")
## Check a few different URLs
check_url("https://httpbin.org/image/jpeg")
check_url("https://speed.hetzner.de/100MB.bin")
check_url("https://example.com")
Запустите этот скрипт, чтобы увидеть подробную информацию о заголовках ответов:
python response_headers.py
Вы увидите вывод, показывающий заголовки для различных типов контента, включая изображения, бинарные файлы и HTML-страницы.
Понимание заголовков ответов имеет решающее значение для многих задач веб-разработки, таких как:
- Определение типов и размеров файлов перед загрузкой
- Реализация возобновляемых загрузок с помощью range requests (запросы диапазона)
- Проверка политик кэширования и сроков истечения срока действия
- Обработка перенаправлений и аутентификации
Резюме
В этой лабораторной работе вы узнали, как работать с библиотекой Python requests для взаимодействия с веб-сервисами и API. Теперь у вас есть навыки:
- Выполнять HTTP-запросы и обрабатывать коды состояния и ошибки ответов
- Разбирать данные JSON из ответов API
- Извлекать информацию из HTML-контента с помощью BeautifulSoup
- Загружать и обрабатывать бинарное содержимое, такое как изображения и файлы
- Работать с заголовками ответов и метаданными
Эти навыки составляют основу для многих приложений Python, включая веб-скрейпинг (web scraping), интеграцию с API, сбор данных и автоматизацию. Теперь вы можете создавать приложения, которые взаимодействуют с веб-сервисами, извлекают полезную информацию с веб-сайтов и обрабатывают различные типы веб-контента.
Чтобы продолжить обучение, вы можете изучить:
- Методы аутентификации для доступа к защищенным API
- Работу с более сложными API, требующими определенных заголовков или форматов запросов
- Создание полноценного проекта веб-скрейпинга, который собирает и анализирует данные
- Создание приложения Python, которое интегрируется с несколькими API
Помните, что при скрейпинге веб-сайтов или использовании API важно проверять условия предоставления услуг и соблюдать ограничения скорости, чтобы избежать блокировки.



