Веб-парсинг с помощью HTTPX на Python

Изучите HTTPX, мощный HTTP-клиент Python для веб-парсинга. Изучите настройку, функции, передовые методы и сравните их с аналогичными параметрами Requests.
5 min read
web scraping with httpx and python blog image

Из этой статьи вы узнаете:

  • Что такое HTTP, и какие функции он предоставляет
  • Как использовать HTTPX для веб-парсинга (в разделе с инструкциями)
  • Расширенные функции HTTPX для веб-парсинга
  • Сравнение HTTPX и Requests в выполнении автоматических запросов

Давайте рассмотрим эти вопросы подробнее!

Что такое HTTPX?

HTTPX — полнофункциональный HTTP-клиент для Python 3, созданный на основе библиотеки retryablehttp . Он предназначен для обеспечения надежных результатов даже при большом количестве потоков. HTTPX предоставляет как синхронные, так и асинхронные API с поддержкой протоколов HTTP/1.1 и HTTP/2.

⚙️ Функции

  • Простая модульная база кода, позволяющая легко вносить свой вклад.
  • Быстрые и полностью настраиваемые флаги для изучения многочисленных элементов.
  • Поддерживает различные методы изучения на основе HTTP.
  • Умный автоматический возврат с HTTPS на HTTP по умолчанию.
  • Принимает хосты, URL-адреса и CIDR в качестве входных данных.
  • Поддерживает прокси-серверы, настраиваемые HTTP-заголовки, настраиваемые таймауты, базовую аутентификацию и многое другое.

👍 Плюсы

  • Доступен из командной строки с помощью httpx[cli].
  • Набор функций, включая поддержку HTTP/2 и асинхронного API.
  • Этот проект активно развивается…

👎 Минусы

  • … часто обновляется, что может привести к критическим изменениям в новых версиях.
  • Менее популярен, чем библиотека requests.

Парсинг с помощью HTTPX: пошаговое руководство

HTTPX — это HTTP-клиент, то есть он помогает извлекать необработанный HTML-контент страницы. Чтобы затем анализировать и извлекать данные из HTML, вам понадобится HTML-парсер типа BeautifulSoup.

На самом деле HTTPX — это не просто HTTP-клиент, а один из лучших HTTP-клиентов Python для веб-парсинга.

Выполняйте указания из этого руководства, чтобы узнать, как использовать HTTPX для веб-парсинга с помощью BeautifulSoup!

Предупреждение: хотя HTTPX используется только на ранних стадиях процесса, мы проведем вас через полный рабочий процесс. Если вас интересуют более продвинутые методы парсинга HTTPX, вы можете перейти к следующей главе после шага 3.

Шаг 1. Настройка проекта

Убедитесь, что на вашем компьютере установлен Python версии 3 или более новой. В противном случае загрузите его с официального сайта и следуйте инструкциям по установке.

Теперь используйте следующую команду для создания каталога для проекта парсинга HTTPX:

mkdir httpx-scraper

Перейдите в него и инициализируйте виртуальную среду внутри него:

cd httpx-scraper
python -m venv env

Откройте папку проекта в предпочитаемой среде Python IDE. Visual Studio Code с расширением Python или PyCharm Community Edition вполне подойдут.

Далее создайте файл scraper.py в папке проекта. Пока scraper.py — это пустой скрипт Python, но вскоре он будет содержать логический механизм парсинга.

В терминале своей IDE активируйте виртуальную среду. В Linux или macOS запустите:

./env/bin/activate

Аналогичным образом, в Windows запустите:

env/Scripts/activate

Потрясающе! Теперь у вас все готово.

Шаг 2. Установите библиотеки для парсинга

В активированной виртуальной среде установите HTTPX и BeautifulSoup с помощью следующей команды:

pip install httpx beautifulsoup4

Это добавит httpx и beautifulsoup4 к зависимым объектам вашего проекта.

Импортируйте их в свой скрипт scraper.py :

import httpx
from bs4 import BeautifulSoup

Прекрасно! Вы готовы перейти к следующему этапу рабочего процесса парсинга.

Шаг 3. Извлечение HTML-кода целевой страницы

В этом примере целевой страницей будет сайт «Цитаты для парсинга»:

Главная страница сайта «Цитаты для парсинга»

Используйте HTTPX для получения HTML-кода главной страницы с помощью метода get():

# Make an HTTP GET request to the target page
response = httpx.get("http://quotes.toscrape.com")

HTTPX без отображения сообщения о своих действиях отправит серверу HTTP-запрос GET, который ответит на него с помощью HTML-кода страницы. Доступ к HTML-контенту можно получить с помощью атрибута response.text:

html = response.text
print(html)

Будет выдан необработанный HTML-контент страницы:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Quotes to Scrape</title>
    <link rel="stylesheet" href="/static/bootstrap.min.css">
    <link rel="stylesheet" href="/static/main.css">
</head>
<body>
    <!-- omitted for brevity... -->
</body>
</html>

Великолепно! Пора проанализировать этот контент и извлечь нужные данные.

Шаг 4. Анализ HTML

Передайте HTML-контент в конструктор BeautifulSoup, чтобы проанализировать его:

# Parse the HTML content using
BeautifulSoup soup = BeautifulSoup(html, "html.parser")

html.parser — это стандартный HTML-парсер на Python, который будет использоваться для анализа контента.

Переменная soup теперь содержит код HTML, подвергнутый парсингу, и предоставляет методы извлечения необходимых данных.

HTTPX выполнил свою работу по извлечению HTML, и теперь вы переходите к традиционному этапу парсинга данных с помощью BeautifulSoup. Для получения дополнительной информации обратитесь к нашему руководству по веб-парсингу с помощью BeautifulSoup.

Шаг 5. Извлечение данных

Вы можете выполнить парсинг данных цитат со страницы с помощью следующих строк кода:

# Where to store the scraped data
quotes = []

# Extract all quotes from the page
quote_elements = soup.find_all("div", class_="quote")

# Loop through quotes and extract text, author, and tags
for quote_element in quote_elements:
    text = quote_element.find("span", class_="text").get_text().get_text().replace("“", "").replace("”", "")
    author = quote_element.find("small", class_="author")
    tags = [tag.get_text() for tag in quote_element.find_all("a", class_="tag")]

    # Store the scraped data
    quotes.append({
        "text": text,
        "author": author,
        "tags": tags
    })

Этот фрагмент кода определяет список с именем quotes для хранения данных, полученных в ходе парсинга. Затем фрагмент кода выбирает все HTML-элементы цитаты и выполняет их перебор, чтобы извлечь текст, автора и теги цитаты. Каждая извлеченная цитата сохраняется в виде словаря в списке quotes, в котором данные упорядочиваются для дальнейшего использования или экспорта.

Да! Логический механизм парсинга создан.

Шаг 6. Экспорт данных, полученных в ходе парсинга

Используйте следующую логику для экспорта данных парсинга в CSV-файл:

# Specify the file name for export
with open("quotes.csv", mode="w", newline="", encoding="utf-8") as file:
    writer = csv.DictWriter(file, fieldnames=["text", "author", "tags"])

    # Write the header row
    writer.writeheader()

    # Write the scraped quotes data
    writer.writerows(quotes)

Этот фрагмент кода открывает файл с именем quotes.csv в режиме записи, задает заголовки столбцов (текставтортеги), записывает заголовки в файл, а затем записывает каждый словарь из списка quotes в CSV-файл. csv.DictWriter обрабатывает форматирование, упрощая хранение структурированных данных.

Не забудьте импортировать csv из стандартной библиотеки Python:

import csv

Шаг 7. Заключительная сборка

Ваш последний скрипт веб-парсинга HTTPX будет содержать следующее:

import httpx
from bs4 import BeautifulSoup
import csv

# Make an HTTP GET request to the target page
response = httpx.get("http://quotes.toscrape.com")

# Access the HTML of the target page
html = response.text

# Parse the HTML content using BeautifulSoup
soup = BeautifulSoup(html, "html.parser")

# Where to store the scraped data
quotes = []

# Extract all quotes from the page
quote_elements = soup.find_all("div", class_="quote")

# Loop through quotes and extract text, author, and tags
for quote_element in quote_elements:
    text = quote_element.find("span", class_="text").get_text().replace("“", "").replace("”", "")
    author = quote_element.find("small", class_="author").get_text()
    tags = [tag.get_text() for tag in quote_element.find_all("a", class_="tag")]

    # Store the scraped data
    quotes.append({
        "text": text,
        "author": author,
        "tags": tags
    })

# Specify the file name for export
with open("quotes.csv", mode="w", newline="", encoding="utf-8") as file:
    writer = csv.DictWriter(file, fieldnames=["text", "author", "tags"])

    # Write the header row
    writer.writeheader()

    # Write the scraped quotes data
    writer.writerows(quotes)

Выполните его с помощью:

python scraper.py

Или в Linux/macOS:

python3 scraper.py

Файл quotes.csv появится в корневой папке вашего проекта. Откройте его, и вы увидите:

CSV-файл, содержащий очищенные данные

Все готово! Вы только что узнали, как выполнять веб-парсинг с помощью HTTPX и BeautifulSoup.

HTTPX для веб-парсинга: расширенные функции и методы

Теперь, когда вы знаете, как использовать HTTPX для веб-парсинга в базовом сценарии, вы готовы увидеть его в действии в более сложных сценариях использования.

В приведенных ниже примерах целевым сайтом будет конечная точка HTTPBin.io /anything. Это специальный API, который возвращает IP-адрес, заголовки и другую информацию, отправленную вызывающей функцией.

Освойте HTTPX для веб-парсинга!

Настройка пользовательских заголовков

HTTPX позволяет указывать пользовательские заголовки с помощью аргумента headers:

import httpx

# Custom headers for the request
headers = {
    "accept": "application/json",
    "accept-language": "en-US,en;q=0.9,fr-FR;q=0.8,fr;q=0.7,es-US;q=0.6,es;q=0.5,it-IT;q=0.4,it;q=0.3"
}

# Make a GET request with custom headers
response = httpx.get("https://httpbin.io/anything", headers=headers)
# Handle the response...

Настройка особого пользовательского агента

User-Agent — один из самых важных HTTP-заголовков для веб-парсинга. По умолчанию HTTPX использует следующий пользовательский агент User-Agent:

python-httpx/<VERSION>

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

Чтобы избежать этого, вы можете настроить собственный User-Agent, имитирующий настоящий браузер, например:

import httpx

# Define a custom User-Agent
headers = {
    "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Safari/537.36"
}

# Make a GET request with the custom User-Agent
response = httpx.get("https://httpbin.io/anything", headers=headers)
# Handle the response...

Узнайте про лучшие пользовательские агенты для веб-парсинга!

Установка файлов cookie

Как и в HTTP-заголовках, вы можете задать файлы cookie в HTTPX, используя аргумент cookie:

import httpx

# Define cookies as a dictionary
cookies = {
    "session_id": "3126hdsab161hdabg47adgb",
    "user_preferences": "dark_mode=true"
}

# Make a GET request with custom cookies
response = httpx.get("https://httpbin.io/anything", cookies=cookies)
# Handle the response...

Это дает вам возможность включать данные сеанса, необходимые для запросов веб-парсинга.

Интеграция прокси

Вы можете направлять запросы HTTPX через прокси-сервер, чтобы скрыть свою личность и избежать блокировок IP-адресов при веб-парсинге. Это можно сделать, используя аргумент proxies:

import httpx

# Replace with the URL of your proxy server
proxy = "<YOUR_PROXY_URL>"

# Make a GET request through a proxy server
response = httpx.get("https://httpbin.io/anything", proxy=proxy)
# Handle the response...

Узнайте больше в нашем руководстве о том, как использовать HTTPX с прокси-сервером.

Обработка ошибок

По умолчанию HTTPX отображает ошибки только при проблемах с подключением или сетью. Чтобы также создать исключения для HTTP-ответов с кодами состояния 4xx и 5xx, используйте метод raise_for_status(), как показано ниже:

import httpx

try:
    response = httpx.get("https://httpbin.io/anything")
    # Raise an exception for 4xx and 5xx responses
    response.raise_for_status()
    # Handle the response...
except httpx.HTTPStatusError as e:
    # Handle HTTP status errors
    print(f"HTTP error occurred: {e}")
except httpx.RequestError as e:
    # Handle connection or network errors
    print(f"Request error occurred: {e}")

Обработка сеанса

При использовании API верхнего уровня в HTTPX для каждого запроса устанавливается новое соединение. Другими словами, TCP-соединения не используются повторно. По мере увеличения количества запросов к хосту такой подход становится неэффективным.

Напротив, использование экземпляра httpx.Client позволяет объединить HTTP-соединения в пул. Это означает, что несколько запросов к одному и тому же хосту могут повторно использовать существующее TCP-соединение вместо создания нового для каждого запроса.

Преимущества использования клиента по сравнению с API верхнего уровня:

  • Уменьшение задержки запросов (избежание повторной установки связи)
  • Меньшая загрузка процессора и меньшее количество передачи данных в оба конца
  • Снижение перегрузки сети

Кроме того, экземпляры Client поддерживают обработку сеансов с использованием функций, недоступных в API верхнего уровня, включая:

  • Сохранение файлов cookie в разных запросах.
  • Применение конфигурации ко всем исходящим запросам.
  • Отправка запросов через прокси-серверы HTTP.

Рекомендуемый способ использования клиента в HTTPX — использовать диспетчер контекста (с оператором with):

import httpx

with httpx.Client() as client:
    # Make an HTTP request using the client
    response = client.get("https://httpbin.io/anything")

    # Extract the JSON response data and print it
    response_data = response.json()
    print(response_data)

Кроме того, вы можете вручную управлять клиентом и явным образом закрыть пул соединений с помощью client.close():

import httpx

client = httpx.Client()
try:
    # Make an HTTP request using the client
    response = client.get("https://httpbin.io/anything")

    # Extract the JSON response data and print it
    response_data = response.json()
    print(response_data)
except:
  # Handle the error...
  pass
finally:
  # Close the client connections and release resources
  client.close()

Примечание: если вы знакомы с библиотекой requestshttpx.client() служит той же цели, что и requests.session().

Асинхронный API

По умолчанию HTTPX предоставляет стандартный синхронный API. В то же время он также предлагает асинхронный клиент для тех случаев, когда это необходимо. Если вы работаете с asyncio, использование асинхронного клиента необходимо для эффективной отправки исходящих HTTP-запросов.

Асинхронное программирование — это модель параллелизма, которая значительно эффективнее многопоточности. Она предлагает заметные улучшения производительности и поддерживает долгоживущие сетевые соединения, такие как WebSockets. Это делает ее ключевым фактором успеха в ускорении веб-парсинга.

Для выполнения асинхронных запросов в HTTPX вам понадобится AsyncClient. Инициализируйте его и используйте для запроса GET, как показано ниже:

import httpx
import asyncio

async def fetch_data():
    async with httpx.AsyncClient() as client:
        # Make an async HTTP request
        response = await client.get("https://httpbin.io/anything")

        # Extract the JSON response data and print it
        response_data = response.json()
        print(response_data)

# Run the async function
asyncio.run(fetch_data())

Оператор with обеспечивает автоматическое закрытие клиента по окончании блокировки. Кроме того, если вы управляете клиентом вручную, вы можете явно закрыть его с помощью await client.close().

Помните, что все методы запроса HTTPX (get()post()и т. д.) являются асинхронными при использовании AsyncClient. Поэтому вы должны добавить await, прежде чем вызывать их, чтобы получить ответ.

Повтор неудачных запросов

Нестабильность сети во время веб-парсинга может привести к сбоям соединения или таймаутам. HTTPX упрощает решение таких проблем с помощью интерфейса HTTPTransport. Этот механизм повторяет запросы при возникновении ошибки httpx.ConnectError или httpx.ConnectTimeout.

В следующем примере показано, как настроить транспорт для повторных запросов до 3 раз:

import httpx

# Configure transport with retry capability on connection errors or timeouts
transport = httpx.HTTPTransport(retries=3)

# Use the transport with an HTTPX client
with httpx.Client(transport=transport) as client:
    # Make a GET request
    response = client.get("https://httpbin.io/anything")
    # Handle the response...

Обратите внимание, что повторную попытку вызывают только ошибки, связанные с подключением. Чтобы обрабатывать ошибки чтения/записи или определенные коды состояния HTTP, вам необходимо реализовать собственную логику повторных попыток с помощью таких библиотек, как tenacity.

HTTPX и запросы веб-парсинга

Вот сводная таблица для сравнения HTTPX и Requests в сфере веб-парсинга:

Особенности HTTPX Requests
Звезды на GitHub 8 тыс. 52,4 тыс.
Поддержка асинхронного режима ✔️
Пул соединений ✔️ ✔️
Поддержка HTTP/2 ✔️
Настройка пользовательского агента ✔️ ✔️
Поддержка прокси-сервера ✔️ ✔️
Обработка файлов cookie ✔️ ✔️
Таймауты Настройка для подключения и чтения Настройка для подключения и чтения
Механизм повторов Доступно через транспорты Доступно через HTTPAdapters
Производительность Высокая Средняя
Поддержка сообщества и популярность Растущая Большая

Заключение

В этой статье вы изучили использование библиотеки httpx для веб-парсинга. Вы поняли, что это такое, что она предлагает и каковы ее преимущества. HTTPX — это быстрый и надежный способ отправки HTTP-запросов при сборе онлайн-данных.

Проблема в том, что автоматические HTTP-запросы отображают ваш публичный IP-адрес, что может раскрыть вашу личность и местоположение. Это ставит под угрозу вашу конфиденциальность. Чтобы повысить безопасность и конфиденциальность, одним из наиболее эффективных способов является использование прокси-сервера, чтобы скрыть свой IP-адрес.

Bright Data контролирует лучшие прокси-серверы в мире, обслуживая компании из списка Fortune 500 и более 20 000 клиентов. Предложение компании включает в себя широкий ассортимент прокси-серверов различных типов:

Создайте бесплатную учетную запись Bright Data сегодня, чтобы протестировать наши решения для парсинга и прокси-серверы!

Кредитная карта не требуется