Веб-скрапинг — это процесс автоматического извлечения данных с веб-сайтов. Это распространенный метод, используемый для сбора больших объемов данных для анализа, машинного обучения и многого другого. В Python есть множество отличных библиотек, которые упрощают парсинг веб-страниц. Одним из популярных вариантов является HTTPX.
HTTPX — мощный и современный HTTP-клиент для Python. Он был создан разработчиками Requests и во многом вдохновлен Requests, а также добавил новые функции, такие как поддержка HTTP/2.
В этом подробном руководстве мы рассмотрим, как эффективно парсить веб-сайты на Python с использованием HTTPX.
Начало работы с HTTPX
Для начала HTTPX можно установить через pip:
pip install httpx
Альтернативно, Поэзию можно использовать:
poetry add httpx
После установки HTTPX можно импортировать и использовать:
import httpx
response = httpx.get(‘https://example.com‘)
print(response.text)
Это приведет к отправке GET-запроса на сайт example.com и распечатке HTML-кода домашней страницы.
HTTPX имеет простой API и поддерживает все популярные команды HTTP, такие как GET, POST, PUT, DELETE, HEAD, OPTIONS и т. д.
Некоторые ключевые особенности включают:
- Поддержка HTTP/1.1 и HTTP/2
- Асинхронный API в стиле aiohttp
- Пул соединений и поддержка активности
- Поддержка прокси
- Конфигурация тайм-аута
- Сохранение файлов cookie
- Знакомый API в стиле запросов
Далее давайте рассмотрим некоторые распространенные шаблоны использования.
Выполнение запросов с помощью HTTPX
Чтобы сделать запрос GET, httpx.get()
можно использовать метод:
response = httpx.get(‘https://example.com‘)
Кроме того, httpx.post()
, httpx.put()
, httpx.delete()
и т. д. можно использовать для других команд HTTP.
Такие параметры, как заголовки, файлы cookie, тайм-аут и т. д., можно передавать в качестве аргументов ключевого слова:
response = httpx.get(
‘https://httpbin.org/headers‘,
headers = {
‘User-Agent‘: ‘MyBot 1.0‘
},
timeout = 10.0
)
Ответ содержит такие свойства, как status_code
, headers
, text
, json()
И т.д.:
print(response.status_code)
print(response.headers)
print(response.text)
json = response.json()
Вы также можете поэтапно передавать ответ, перебирая объект ответа.
Использование HTTPX-клиента
Для большинства задач очистки рекомендуется использовать постоянный httpx.Client
пример.
Клиент обрабатывает такие вещи, как пул соединений, сеансы, файлы cookie и т. д., в рамках нескольких запросов.
import httpx
client = httpx.Client()
response = client.get(‘https://example.com‘)
print(response.text)
response = client.get(‘https://httpbin.org/cookies/set?name=foo‘)
print(response.text)
response = client.get(‘https://httpbin.org/cookies‘)
print(response.json())
Здесь мы делаем несколько запросов, используя один и тот же клиент, который автоматически обрабатывает сохранение файлов cookie.
Вы также можете настроить такие параметры, как заголовки, прокси, аутентификация и т. д. при создании клиента:
client = httpx.Client(
headers = {
‘User-Agent‘: ‘MyBot 1.0‘,
‘Authorization‘: ‘Bearer xxx‘
},
proxies = ‘http://192.168.1.1:8181/‘,
auth = (‘username‘, ‘password‘)
)
Теперь давайте посмотрим на асинхронные запросы.
Асинхронные запросы с HTTPX
Для асинхронного выполнения запросов в Python HTTPX предоставляет AsyncClient
:
import httpx
async with httpx.AsyncClient() as client:
response = await client.get(‘https://example.com‘)
МЫ ИСПОЛЬЗУЕМ async with
для инициализации клиента, await
по запросу и автоматически закрыть клиент после этого.
Чтобы одновременно очистить несколько URL-адресов, мы можем использовать asyncio.gather()
:
import httpx
import asyncio
async def get_url(url):
async with httpx.AsyncClient() as client:
response = await client.get(url)
return response.text
urls = [‘https://example.com‘, ‘https://httpbin.org‘, ‘https://python.org‘]
async def main():
responses = await asyncio.gather(*[get_url(url) for url in urls])
print(responses)
asyncio.run(main())
asyncio.gather()
одновременно ожидает несколько сопрограмм и возвращает результаты в порядке ожидаемых.
Есть и другие варианты, например asyncio.as_completed()
для их обработки по мере их завершения:
tasks = [get_url(url) for url in urls]
async def main():
for result in asyncio.as_completed(tasks):
print(await result)
Async IO позволяет одновременно получать несколько страниц, что полезно для ускорения очистки.
Далее давайте рассмотрим сбор данных из ответов HTML и JSON.
Парсинг ответов HTML и JSON
Для парсинга HTML мы можем использовать парсер, такой как Beautiful Soup, для извлечения данных:
from bs4 import BeautifulSoup
response = httpx.get(‘https://en.wikipedia.org/wiki/Python_(programming_language)‘)
soup = BeautifulSoup(response.text, ‘html.parser‘)
for link in soup.select(‘.toctext‘):
print(link.text.strip())
При этом будет распечатано содержимое оглавления страницы Википедии.
Для ответов JSON HTTPX предоставляет встроенный .json()
Метод:
response = httpx.get(‘https://api.github.com/repos/encode/httpx‘)
json = response.json()
print(json[‘description‘])
Ассоциация json=
Параметр также можно использовать для сериализации данных JSON в запросах.
Вместе с парсером мы можем создавать парсеры для извлечения данных из API и веб-сайтов.
Обработка проблем и ошибок
При парсинге часто возникают такие проблемы, как ошибки соединения, тайм-ауты, ограничения скорости и т. д.
HTTPX предоставляет исключения и инструменты для их правильной обработки.
Таймауты
Чтобы справиться с медленными ответами, вы можете указать собственный timeout
параметр. По умолчанию — 5 секунд.
response = httpx.get(‘https://example.com‘, timeout=10.0)
Если это значение превышено, httpx.TimeoutException
происходит:
try:
response = httpx.get(‘https://example.com‘, timeout=0.001)
except httpx.TimeoutException:
print(‘Request timed out‘)
Для некоторых сайтов или страниц могут потребоваться более длительные тайм-ауты.
Ошибки HTTP
Для ошибок HTTP, таких как 400, 500 и т. д., response.raise_for_status()
можно использовать метод:
try:
response = httpx.get(‘https://httpbin.org/status/500‘)
response.raise_for_status()
except httpx.HTTPStatusError:
print(‘HTTP Error occurred‘)
Это вызовет исключение для любого кода состояния 4xx или 5xx.
Повторные запросы
Чтобы добавить логику повтора, внешние пакеты, такие как tenacity
может быть использован:
from tenacity import retry, stop_after_attempt
@retry(stop=stop_after_attempt(3))
def make_request():
response = httpx.get(‘https://example.com‘)
response.raise_for_status()
return response.json()
data = make_request()
Здесь мы повторяем попытку до 3 раз для любого исключения. Также можно определить более продвинутую логику повторов.
Ограничения параллельных запросов
При параллельном выполнении большого количества запросов вы можете столкнуться с ограничениями на количество подключений.
Ассоциация limits
Параметр можно использовать для настройки таких параметров, как максимальное количество подключений:
client = httpx.AsyncClient(
limits = httpx.Limits(max_connections=20)
)
Настройка этого параметра в зависимости от целевого сайта может помочь избежать ограничений.
Решив эти распространенные проблемы, можно создать более устойчивые скреперы.
Лучшие практики парсинга
Вот несколько советов по созданию эффективных парсеров с помощью HTTPX:
Используйте HTTPX-клиент – Клиенты обеспечивают объединение пулов соединений, сохранение файлов cookie и другие преимущества.
Соскребать вежливо – Ограничьте частоту запросов, чтобы избежать перегрузки серверов. Используйте случайные задержки и регулирование.
Обработка ошибок – Используйте блоки try/Exception, проверки состояния и повторные попытки для решения проблем.
Используйте асинхронный ввод-вывод – Парсинг страниц одновременно для повышения скорости. Но ограничьте параллелизм, чтобы избежать банов.
Случайный выбор пользовательских агентов – Поворачивайте случайные строки пользовательского агента, чтобы они выглядели более человечными.
Используйте прокси – Меняйте разные прокси/IP-адреса для распределения запросов.
Кэширование и сохранение данных – Сохраняйте очищенные данные в файлы/базы данных, чтобы избежать повторного очистки.
Следуя подобным передовым практикам, можно создать более надежные и удобные в обслуживании скреперы.
Продвинутые методы парсинга
Давайте посмотрим на некоторые более продвинутые возможности очистки HTTPX.
Парсинг страниц аутентификации
Для очистки аутентифицированных страниц HTTPX поддерживает несколько типов аутентификации, таких как базовая, дайджест и аутентификация на предъявителя:
client = httpx.Client(
auth = (‘username‘, ‘password‘)
)
response = client.get(‘https://api.example.com/users/me‘)
Учетные данные аутентификации автоматически сохраняются во всех запросах.
Обработка файлов cookie
Ассоциация cookies
параметр можно использовать для отправки пользовательских файлов cookie:
client = httpx.Client(
cookies = {
‘sessionId‘: ‘xxxx‘
}
)
response = client.get(‘https://example.com/dashboard‘)
А файлы cookie, установленные сервером, автоматически сохраняются в клиенте.
Потоковые ответы
Для больших ответов вы можете передавать их постепенно, повторяя объект ответа:
response = client.get(‘https://example.com/bigfile‘)
for chunk in response:
process(chunk)
Это позволяет избежать загрузки всего ответа в память.
Поддержка прокси
Для маршрутизации запросов через прокси-сервер proxies
параметр можно использовать:
proxy = ‘http://192.168.0.1:8888‘
client = httpx.Client(proxies = {‘http‘: proxy, ‘https‘: proxy})
Ротация разных прокси помогает распределять запросы с разных IP-адресов.
Пользовательские заголовки
Вы можете подделать или рандомизировать заголовки запросов, как пользовательские агенты:
client = httpx.Client(headers = {
‘User-Agent‘: ‘MyBot 1.0‘
})
Это имитирует заголовки реального браузера.
Благодаря этим более продвинутым функциям можно создавать надежные парсеры с использованием HTTPX и Python.
Примеры скребков
Давайте теперь посмотрим на несколько примеров парсеров, созданных с использованием HTTPX.
Скребок API Reddit
Вот базовый парсер для Reddit API:
import httpx
client = httpx.Client()
subreddit = ‘python‘
listing = ‘hot‘
limit = 10
response = client.get(f‘https://www.reddit.com/r/{subreddit}/{listing}.json?limit={limit}‘)
data = response.json()[‘data‘]
for post in data[‘children‘]:
title = post[‘data‘][‘title‘]
score = post[‘data‘][‘score‘]
print(f"{title} (Score: {score})")
При этом извлекаются данные о самых популярных сообщениях из субреддита Python. API возвращает JSON, который мы можем проанализировать.
Мы могли бы расширить этот парсер, чтобы извлекать данные из нескольких субреддитов, сохранять результаты в базе данных и т. д.
Новости Статья Скребок
Вот простой парсер новостей, который извлекает статьи с сайта:
from bs4 import BeautifulSoup
import httpx
client = httpx.Client()
response = client.get("https://example.com/news")
soup = BeautifulSoup(response.text, ‘html.parser‘)
for article in soup.select(‘.article‘):
title = article.select_one(‘.article-title‘).text
content = article.select_one(‘.article-content‘).text
print(title)
print(content)
print()
Это находит все .article
элементы, извлекает поля заголовка и содержимого и печатает статьи.
Опять же, это можно расширить, чтобы очистить дополнительные поля, проанализировать даты, сохранить в базе данных и т. д.
Парсер результатов поиска
А вот пример парсера результатов поиска Google:
import httpx
query = "httpx python"
url = f"https://www.google.com/search?q={query}"
client = httpx.Client()
response = client.get(url)
from bs4 import BeautifulSoup
soup = BeautifulSoup(response.text, ‘html.parser‘)
for result in soup.select(‘.tF2Cxc‘):
title = result.select_one(‘.DKV0Md‘).text
link = result.select_one(‘.yuRUbf a‘)[‘href‘]
print(title)
print(link)
print()
Это выполняет поиск в Google по заданному запросу, анализирует ссылки/заголовки результатов и распечатывает их.
Опять же, можно было бы внести множество улучшений, таких как извлечение количества результатов поиска, дополнительные поля, очистка страниц результатов, обнаружение капч и т. д.
Эти примеры демонстрируют общие шаблоны парсинга HTTPX. Те же методы можно применить для создания парсеров для многих веб-сайтов и API.
Обзор
Подводя итог, HTTPX предоставляет мощный HTTP-клиент для создания веб-скребков Python. Вот некоторые ключевые моменты:
HTTPX имеет простой API-интерфейс в стиле запросов для выполнения запросов.
Поддержка асинхронности позволяет выполнять запросы одновременно.
Надежная обработка ошибок с таймаутами, повторными попытками и проверками статуса.
Легко очищайте HTML-страницы с помощью API Beautiful Soup и JSON.
Постоянные клиенты обеспечивают пул соединений, сеансы и обработку файлов cookie.
Передовые методы, такие как прокси, заголовки и аутентификация, позволяют использовать сложные парсеры.
Следуйте лучшим практикам, таким как использование регулирования, случайных задержек и пользовательских агентов.
HTTPX позволяет легко начать парсинг с помощью Python. Благодаря надежной обработке ошибок и асинхронному параллелизму можно разработать масштабируемые парсеры.
Попробуйте HTTPX в своем следующем проекте парсинга веб-страниц на Python!