Как получить содержимое веб-страницы на Python: от простых запросов до парсинга динамики

Раздел: Веб-разработка -> HTTP-запросы и парсинг

Методы получения содержимого веб-страниц в 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('Превышено количество попыток')
Превышено количество попыток

Получение содержимого веб-страницы в Python - comments

En
содержимое страницы python (python)