Как получить содержимое веб-страницы на Python: от простых запросов до парсинга динамики
Методы получения содержимого веб-страниц в Python
Основной способ: библиотека requests и BeautifulSoup
Как загрузить HTML-код веб-страницы и извлечь из него нужные данные?
Для получения содержимого веб-страницы чаще всего используется связка requests (для HTTP-запроса) и BeautifulSoup (для парсинга HTML). Это решение подходит для статических страниц, не требующих выполнения JavaScript.
import requests
from bs4 import BeautifulSoup
url = 'https://example.com'
response = requests.get(url)
response.encoding = 'utf-8' # при необходимости
soup = BeautifulSoup(response.text, 'html.parser')
print(soup.prettify()[:500])Html запросы python (http-запросы к html)
Пояснение шагов:
- requests.get() отправляет GET-запрос и возвращает объект Response.
- response.text содержит декодированный HTML-текст. Кодировка определяется автоматически, но иногда требуется задать вручную.
- BeautifulSoup преобразует HTML в дерево объектов, удобное для поиска.
- Метод prettify() выводит отформатированный HTML (для отладки).
Какие проблемы возникают при использовании requests?
- Ошибка ConnectionError – если сайт недоступен. Решение: обрабатывать исключения и добавлять повторные попытки (retry).
- Некорректная кодировка – страница может быть в cp1251 или другой. Решение: явно установить response.encoding = 'utf-8' или определить по заголовку Content-Type.
- SSL-сертификат – если сайт использует самоподписанный сертификат, параметр verify=False (с осторожностью).
- Динамический контент – страницы, загружаемые через JavaScript, не будут получены. Для этого нужны Selenium или aiohttp с headless-браузером.
Вариант 1: стандартная библиотека urllib
Как получить содержимое страницы без установки сторонних пакетов?
Модуль urllib.request входит в стандартную библиотеку Python. Он позволяет выполнять HTTP-запросы, но требует больше кода для обработки ошибок и кодировок.
import urllib.request
from urllib.error import URLError
url = 'https://example.com'
try:
with urllib.request.urlopen(url) as response:
html = response.read().decode('utf-8')
print(html[:200])
except URLError as e:
print('Ошибка:', e)содержимое страницы python (получение содержимого веб-страницы в python)
Основные отличия от requests: нужно вручную декодировать байты, нет удобных методов для заголовков и параметров.
Какие сложности встречаются при использовании urllib?
- Обработка cookie – требуется создавать opener с HTTPCookieProcessor.
- Таймаут – задаётся через timeout в urlopen.
- Кодировка – необходимо извлекать из заголовка или мета-тега, иначе возможны кракозябры.
Вариант 2: асинхронная библиотека aiohttp
Как загрузить несколько страниц одновременно для ускорения парсинга?
Для асинхронных запросов применяется aiohttp в связке с asyncio. Это позволяет обрабатывать десятки страниц параллельно.
import aiohttp
import asyncio
async def fetch(url):
async with aiohttp.ClientSession() as session:
async with session.get(url) as response:
return await response.text()
async def main():
urls = ['https://example.com', 'https://httpbin.org']
tasks = [fetch(url) for url in urls]
results = await asyncio.gather(*tasks)
for r in results:
print(len(r))
asyncio.run(main())
С какими проблемами сталкиваются при работе с aiohttp?
- Необходимость управления сессией – повторное использование сессии повышает производительность.
- Ограничения на количество одновременных соединений – можно настроить через TCPConnector.
- Обработка ошибок – каждое исключение требуется перехватывать внутри корутины.
Вариант 3: библиотека httpx
Как получить содержимое с поддержкой HTTP/2 и синхронного/асинхронного режимов?
httpx – современная библиотека, объединяющая возможности requests и aiohttp. Она поддерживает HTTP/2, синхронный и асинхронный API.
import httpx
# Синхронный режим
response = httpx.get('https://example.com')
print(response.text[:200])
# Асинхронный режим
import httpx
import asyncio
async def fetch():
async with httpx.AsyncClient() as client:
resp = await client.get('https://example.com')
return resp.text
html = asyncio.run(fetch())
print(len(html))
Какие особенности у httpx?
- HTTP/2 – может ускорить загрузку, но требует установки доп. пакетов (h2).
- Совместимость – API похож на requests, но есть различия в обработке таймаутов и перенаправлений.
- Прокси – настройка прокси-сервера отличается от requests.
Вариант 4: Selenium для динамических страниц
Как получить содержимое страницы, которое формируется после выполнения JavaScript?
Selenium с драйвером браузера (Chrome, Firefox) загружает страницу полностью, включая JS. После загрузки можно получить HTML через page_source.
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
options = Options()
options.add_argument('--headless')
driver = webdriver.Chrome(options=options)
driver.get('https://example.com')
html = driver.page_source
driver.quit()
print(html[:300])
Проблемы при использовании Selenium:
- Низкая скорость – запуск браузера занимает время.
- Потребление ресурсов – headless-режим снижает нагрузку, но всё равно выше, чем HTTP-запросы.
- Зависимость от драйвера – требуется установка chromedriver/geckodriver соответствующей версии.
- Ожидание загрузки элементов – необходимо использовать WebDriverWait для стабильности.
Вариант 5: библиотека lxml с XPath
Как быстро извлечь данные, используя XPath вместо CSS-селекторов?
lxml – быстрый парсер HTML/XML. Он умеет работать как с BeautifulSoup, так и напрямую из строки через html.fromstring.
from lxml import html
import requests
resp = requests.get('https://example.com')
tree = html.fromstring(resp.content)
title = tree.xpath('//title/text()')
print(title[0] if title else 'Нет заголовка')
Какие сложности у lxml?
- Установка C-компилятора – на некоторых системах требуется компиляция, проще ставить через wheel.
- Работа с невалидным HTML – lxml может исправлять теги, что иногда меняет структуру.
Дополнительные примеры и продвинутые техники
1. Сессия с cookies и заголовками (requests)
import requests
session = requests.Session()
session.headers.update({'User-Agent': 'Mozilla/5.0'})
session.cookies.set('sessionid', 'abc123')
response = session.get('https://httpbin.org/cookies')
print(response.json())
{
"cookies": {
"sessionid": "abc123"
}
}
2. Асинхронный парсинг с ограничением параллелизма (aiohttp + asyncio.Semaphore)
import aiohttp
import asyncio
sem = asyncio.Semaphore(5)
async def fetch(url):
async with sem:
async with aiohttp.ClientSession() as session:
async with session.get(url) as resp:
return await resp.text()
async def main():
urls = ['https://example.com'] * 10
tasks = [fetch(url) for url in urls]
results = await asyncio.gather(*tasks)
print('Загружено страниц:', len(results))
asyncio.run(main())
Загружено страниц: 10
3. Использование прокси-сервера (requests)
import requests
proxies = {
'http': 'http://user:pass@proxy.example.com:8080',
'https': 'http://user:pass@proxy.example.com:8080'
}
try:
resp = requests.get('https://httpbin.org/ip', proxies=proxies, timeout=10)
print(resp.json())
except requests.exceptions.ProxyError:
print('Ошибка прокси')
{"origin": "203.0.113.1"}
4. Извлечение данных из JSON-ответа (API-запрос)
import requests
url = 'https://jsonplaceholder.typicode.com/posts/1'
response = requests.get(url)
data = response.json()
print('Заголовок:', data['title'])
print('Текст:', data['body'][:50])
Заголовок: sunt aut facere repellat provident occaecati excepturi optio reprehenderit Текст: quia et suscipit suscipit recusandae consequuntur ...
5. Парсинг таблицы из HTML (BeautifulSoup + pandas)
import requests
from bs4 import BeautifulSoup
import pandas as pd
url = 'https://example.com/table'
resp = requests.get(url)
soup = BeautifulSoup(resp.text, 'html.parser')
table = soup.find('table')
df = pd.read_html(str(table))[0]
print(df.head())
Имя Возраст Город 0 Иван 25 Москва 1 Петр 30 Санкт-Петербург
6. Обработка аутентификации (HTTP Basic Auth)
import requests
from requests.auth import HTTPBasicAuth
url = 'https://httpbin.org/basic-auth/user/pass'
response = requests.get(url, auth=HTTPBasicAuth('user', 'pass'))
print(response.status_code, response.json())
200 {'authenticated': True, 'user': 'user'}
7. Загрузка изображения и сохранение в файл
import requests
url = 'https://httpbin.org/image/png'
response = requests.get(url, stream=True)
with open('image.png', 'wb') as f:
for chunk in response.iter_content(chunk_size=8192):
f.write(chunk)
print('Файл сохранён, размер:', len(response.content))
Файл сохранён, размер: 8090
8. Ошибка таймаута и повторные попытки (retry)
import requests
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry
session = requests.Session()
retries = Retry(total=3, backoff_factor=1, status_forcelist=[500, 502, 503])
adapter = HTTPAdapter(max_retries=retries)
session.mount('http://', adapter)
session.mount('https://', adapter)
try:
resp = session.get('https://httpbin.org/status/503', timeout=5)
print(resp.status_code)
except requests.exceptions.RetryError:
print('Превышено количество попыток')
Превышено количество попыток