Получение HTML данных через HTTP-запросы средствами Python
Отправка HTTP-запросов к HTML страницам на Python
Для получения HTML кода веб-страницы и последующего парсинга в Python существует несколько способов. Наиболее популярным и простым решением является использование библиотеки requests в связке с BeautifulSoup. Однако в зависимости от задачи могут потребоваться другие инструменты.
Как получить HTML страницы с помощью библиотеки requests и обработать его BeautifulSoup?
Этот подход подходит для большинства сценариев: однократные запросы, работа с сессиями, обработка ошибок. Установка: pip install requests beautifulsoup4
import requests
from bs4 import BeautifulSoup
url = 'https://example.com'
response = requests.get(url)
response.raise_for_status() # вызовет исключение при ошибке
soup = BeautifulSoup(response.text, 'html.parser')
print(soup.title.text)Html запросы python (http-запросы к html)
Example Domain
содержимое страницы python (получение содержимого веб-страницы в python)
Пояснение: response.text содержит HTML как строку. BeautifulSoup преобразует её в дерево для удобного поиска элементов. Метод raise_for_status() помогает отловить неудачные коды ответа (4xx, 5xx).
Возможные проблемы и их решение:
- ConnectionError – нет соединения с сервером; проверьте интернет или url.
- Timeout – сервер долго отвечает; добавьте параметр
timeout=(connect, read). - HTTPError – код ошибки (например, 404); используйте
raise_for_status()или проверяйтеresponse.status_code. - Неправильная кодировка –
response.encoding = response.apparent_encodingдля автоматического определения.
Как выполнить простой HTTP-запрос без сторонних библиотек?
Стандартная библиотека включает модуль urllib.request. Это решение для минималистичных скриптов без установки зависимостей.
import urllib.request
url = 'https://example.com'
with urllib.request.urlopen(url) as response:
html = response.read().decode('utf-8')
print(html[:100])<!doctype html>
<html>
<head>
<title>Example Domain</title>Пояснение: urlopen возвращает файлоподобный объект. Данные читаются байтами, их нужно декодировать. Для настройки заголовков используйте Request объект.
Проблема: отсутствие автоматического следования редиректам (по умолчанию следует, но можно отключить). Также неудобно работать с куками и сессиями.
Как эффективно загрузить несколько HTML страниц одновременно?
Для асинхронных запросов применяется библиотека aiohttp. Она позволяет выполнять запросы конкурентно, ускоряя сбор данных.
import aiohttp
import asyncio
async def fetch(session, url):
async with session.get(url) as response:
return await response.text()
async def main():
urls = ['https://example.com', 'https://httpbin.org/html']
async with aiohttp.ClientSession() as session:
tasks = [fetch(session, url) for url in urls]
results = await asyncio.gather(*tasks)
for html in results:
print(len(html))
asyncio.run(main())1256 321
Пояснение: aiohttp.ClientSession управляет соединениями. asyncio.gather запускает несколько запросов параллельно. Подходит для сбора контента с десятков страниц.
Типичная ошибка: RuntimeError при попытке запустить асинхронный код в неподходящем окружении. Используйте asyncio.run() в основном потоке. Также не забывайте закрывать сессию.
Как работать с современными протоколами и гибкими настройками тайм-аутов?
Библиотека httpx поддерживает HTTP/1.1 и HTTP/2, а также предоставляет удобный интерфейс с тайм-аутами и сессиями.
import httpx
with httpx.Client(http2=True, timeout=10.0) as client:
response = client.get('https://example.com')
print(response.http_version)HTTP/2
Пояснение: Параметр http2=True включает поддержку HTTP/2. Тайм-аут задаётся в секундах. httpx также умеет автоматически следовать редиректам и управлять куками.
Проблема: httpx может не быть установлен по умолчанию, требуется pip install httpx[http2]. При большом количестве запросов асинхронная версия (httpx.AsyncClient) даст лучшую производительность.
Как сохранить состояние между запросами (авторизация, куки)?
Использование сессий позволяет сохранять куки, заголовки и параметры между запросами. Это необходимо для обхода login-форм или работы с API.
import requests
session = requests.Session()
session.headers.update({'User-Agent': 'Mozilla/5.0'})
session.get('https://example.com/login') # получаем куки
# далее запросы будут использовать эти куки
response = session.get('https://example.com/dashboard')
print(response.status_code)200
Пояснение: Session хранит куки и заголовки. Это удобно для парсинга сайтов, требующих аутентификации.
Ошибка: сессия может быть заблокирована, если не отправлять правильные заголовки (например, Referer). Иногда требуется добавлять задержки между запросами, чтобы избежать блокировки.
Расширенные примеры HTTP-запросов и парсинга HTML
Скачивание всех изображений со страницы
Пример извлекает все теги <img>, получает их атрибуты src и скачивает файлы.
import requests
from bs4 import BeautifulSoup
from urllib.parse import urljoin
import os
url = 'https://example.com/gallery'
response = requests.get(url)
soup = BeautifulSoup(response.text, 'html.parser')
img_tags = soup.find_all('img')
os.makedirs('images', exist_ok=True)
for img in img_tags:
src = img.get('src')
if not src:
continue
full_url = urljoin(url, src)
img_data = requests.get(full_url).content
filename = os.path.join('images', os.path.basename(src))
with open(filename, 'wb') as f:
f.write(img_data)
print(f'Сохранено {filename}')Сохранено images/photo1.jpg Сохранено images/photo2.png
Пояснение: urljoin корректно обрабатывает относительные ссылки. Для больших страниц лучше использовать асинхронную загрузку изображений.
Парсинг данных из таблицы HTML
Извлечение строк таблицы с последующей записью в CSV.
import requests
from bs4 import BeautifulSoup
import csv
response = requests.get('https://example.com/data')
soup = BeautifulSoup(response.text, 'lxml')
table = soup.find('table', class_='data-table')
rows = table.find_all('tr')
with open('output.csv', 'w', newline='', encoding='utf-8') as csvfile:
writer = csv.writer(csvfile)
for row in rows:
cells = row.find_all(['th', 'td'])
writer.writerow([cell.get_text(strip=True) for cell in cells])(файл output.csv создан)
Пояснение: Используется парсер lxml (более быстрый, чем html.parser). Атрибут class_ в BeautifulSoup ищет класс CSS. Метод get_text(strip=True) удаляет лишние пробелы.
Многопоточная загрузка страниц с сохранением результатов
Применение модуля concurrent.futures для параллельного выполнения синхронных запросов.
import requests
from concurrent.futures import ThreadPoolExecutor, as_completed
from bs4 import BeautifulSoup
def fetch_title(url):
try:
resp = requests.get(url, timeout=5)
resp.raise_for_status()
soup = BeautifulSoup(resp.text, 'html.parser')
return url, soup.title.string if soup.title else None
except Exception as e:
return url, str(e)
urls = [f'https://example.com/page{i}' for i in range(1, 11)]
with ThreadPoolExecutor(max_workers=5) as executor:
future_to_url = {executor.submit(fetch_title, url): url for url in urls}
for future in as_completed(future_to_url):
url, result = future.result()
print(f'{url}: {result}')https://example.com/page1: Page One https://example.com/page2: Page Two ...
Пояснение: ThreadPoolExecutor выполняет запросы в потоках. Пул из 5 потоков ускоряет загрузку. Обработка ошибок внутри функции предотвращает падение всего скрипта.
Использование прокси для обхода блокировок
import requests
proxies = {
'http': 'http://user:password@proxy.example.com:8080',
'https': 'http://user:password@proxy.example.com:8080'
}
try:
response = requests.get('https://example.com', proxies=proxies, timeout=10)
print(response.status_code)
except requests.exceptions.ProxyError:
print('Не удалось подключиться через прокси')200
Пояснение: Прокси настраиваются словарём. Для авторизации используйте http://user:pass@host:port. Ошибка ProxyError говорит о проблемах с прокси-сервером.
Работа с сессиями и куками в aiohttp
import aiohttp
import asyncio
async def main():
async with aiohttp.ClientSession(cookies={'sessionid': 'abc123'}) as session:
async with session.get('https://example.com/profile') as resp:
print(await resp.text()[:200])
asyncio.run(main())<!DOCTYPE html>...<h1>Profile</h1>
Пояснение: Куки передаются в конструктор сессии. Они будут отправляться при каждом запросе. Также можно обновлять куки из ответа.